from django.db.models import Q
from django.shortcuts import get_object_or_404
from rest_framework import permissions
from rest_framework.response import Response
from rest_framework.views import APIView
from api_core.application import mutation
from api_core.pagination import limited
from api_core.permissions import can_manage_club,is_platform_admin
from clubs.models import Club
from academy.models import YouthSquadMembership
from players.models import Player
from .api_serializers import IndividualScheduleSerializer,PlayerDevelopmentSerializer,RatingRunSerializer,TeamScheduleSerializer,TrainingResultSerializer,TrainingSessionSerializer
from .exceptions import TrainingDomainError
from .models import PlayerDevelopmentProgress,PlayerRatingMaterializationRun,TrainingDevelopmentResult,TrainingSession
from .services import TrainingExecutionService,TrainingLifecycleService,TrainingSchedulingService
from .timed import schedule_slot, personal_facility
from .drills import RELATED, weights


def _can_session(user,session):
    if is_platform_admin(user):return True
    if session.club_id:return can_manage_club(user,session.club)
    return session.participants.filter(player__career__user=user).exists()
class TrainingSessionListAPIView(APIView):
    permission_classes=[permissions.IsAuthenticated]
    def get(self,request):
        qs=TrainingSession.objects.prefetch_related("participants").select_related("club__coach_career__user","club__ownership_record__owner").order_by("-training_date","-created_at")
        if not is_platform_admin(request.user):qs=qs.filter(Q(club__ownership_record__owner=request.user)|Q(club__coach_career__user=request.user)|Q(participants__player__career__user=request.user)|Q(club__squad_memberships__player__career__user=request.user, starts_at__isnull=False)|Q(club__academy__youth_team__squad_memberships__player__career__user=request.user,starts_at__isnull=False)).distinct()
        if request.query_params.get("player_id"):
            from rest_framework import serializers
            field = serializers.UUIDField()
            pid = field.run_validation(request.query_params["player_id"])
            player = get_object_or_404(Player.objects.select_related("career"), pk=pid)
            if not (is_platform_admin(request.user) or player.career.user_id == request.user.pk):
                return Response({"detail":"Player owner permission required."},status=403)
            qs = qs.filter(Q(participants__player=player)|Q(starts_at__isnull=False, club__squad_memberships__player=player)|Q(starts_at__isnull=False,club__academy__youth_team__squad_memberships__player=player)).distinct()
        return limited(request,qs,TrainingSessionSerializer)
class IndividualTrainingScheduleAPIView(APIView):
    permission_classes=[permissions.IsAuthenticated]
    def post(self,request):
        s=IndividualScheduleSerializer(data=request.data);s.is_valid(raise_exception=True);p=get_object_or_404(Player.objects.select_related("career__user"),pk=s.validated_data["player_id"])
        if not (is_platform_admin(request.user) or p.career.user_id==request.user.pk):return Response({"detail":"Only the player owner may schedule individual training."},status=403)
        return mutation(request=request,scope=f"training.player.{p.pk}.schedule",operation=lambda:TrainingSchedulingService.schedule_individual(**s.validated_data, policy_version="2.0.0"),serialize=lambda x:TrainingSessionSerializer(x).data,success_status=201,domain_errors=(TrainingDomainError,))
class TeamTrainingScheduleAPIView(APIView):
    permission_classes=[permissions.IsAuthenticated]
    def post(self,request):
        s=TeamScheduleSerializer(data=request.data);s.is_valid(raise_exception=True);club=get_object_or_404(Club.objects.select_related("coach_career__user","ownership_record__owner"),pk=s.validated_data["club_id"])
        if not can_manage_club(request.user,club):return Response({"detail":"Club management permission required."},status=403)
        return mutation(request=request,scope=f"training.club.{club.pk}.schedule",operation=lambda:schedule_slot(**s.validated_data),serialize=lambda x:TrainingSessionSerializer(x).data,success_status=201,domain_errors=(TrainingDomainError,))
class TrainingSessionDetailAPIView(APIView):
    permission_classes=[permissions.IsAuthenticated]
    def get(self,request,session_id):
        obj=get_object_or_404(TrainingSession.objects.prefetch_related("participants").select_related("club__coach_career__user","club__ownership_record__owner"),pk=session_id)
        if not (_can_session(request.user,obj) or (obj.starts_at and (obj.club.squad_memberships.filter(player__career__user=request.user).exists() or YouthSquadMembership.objects.filter(youth_team__academy__club=obj.club,player__career__user=request.user).exists()))):return Response({"detail":"Not authorized."},status=403)
        data=TrainingSessionSerializer(obj).data
        results=TrainingDevelopmentResult.objects.filter(participant__session=obj)
        if not _can_session(request.user,obj):results=results.filter(player__career__user=request.user)
        data["results"]=TrainingResultSerializer(results,many=True).data;return Response(data)
class TrainingSessionActionAPIView(APIView):
    permission_classes=[permissions.IsAuthenticated]
    def post(self,request,session_id,action):
        obj=get_object_or_404(TrainingSession.objects.prefetch_related("participants").select_related("club__coach_career__user","club__ownership_record__owner"),pk=session_id)
        if action == "attend":
            from rest_framework import serializers
            from .timed import attend
            class AttendanceInput(serializers.Serializer):
                player_id = serializers.UUIDField()
            data = AttendanceInput(data=request.data); data.is_valid(raise_exception=True)
            player = get_object_or_404(Player.objects.select_related("career"), pk=data.validated_data["player_id"])
            if player.career.user_id != request.user.pk:
                return Response({"detail":"Only the player owner can attend."},status=403)
            return mutation(request=request,scope=f"training.session.{session_id}.attend.{player.pk}",operation=lambda:attend(session_id=session_id,player_id=player.pk,user=request.user),serialize=lambda x:TrainingSessionSerializer(x).data,domain_errors=(TrainingDomainError,))
        if not _can_session(request.user,obj):return Response({"detail":"Not authorized."},status=403)
        if action=="execute":
            def op():
                TrainingExecutionService.execute(session_id=session_id);return TrainingSession.objects.prefetch_related("participants").get(pk=session_id)
        elif action=="cancel":op=lambda:TrainingLifecycleService.cancel(session_id=session_id)
        else:return Response({"detail":"Unknown action."},status=404)
        return mutation(request=request,scope=f"training.session.{session_id}.{action}",operation=op,serialize=lambda x:TrainingSessionSerializer(x).data,domain_errors=(TrainingDomainError,))
class PlayerDevelopmentAPIView(APIView):
    permission_classes=[permissions.IsAuthenticated]
    def get(self,request,player_id):
        p=get_object_or_404(Player.objects.select_related("career__user"),pk=player_id)
        if not (is_platform_admin(request.user) or p.career.user_id==request.user.pk or (hasattr(p,"squad_membership") and can_manage_club(request.user,p.squad_membership.club)) or (hasattr(p,"youth_squad_membership") and can_manage_club(request.user,p.youth_squad_membership.youth_team.academy.club))):return Response({"detail":"Not authorized."},status=403)
        _, facility = personal_facility(p)
        return Response({"facility":facility,"drills":{k:{a:str(w) for a,w in weights(k).items()} for k in RELATED},"progress":PlayerDevelopmentSerializer(PlayerDevelopmentProgress.objects.filter(player=p),many=True).data,"rating_runs":RatingRunSerializer(PlayerRatingMaterializationRun.objects.filter(player=p)[:30],many=True).data})
