from rest_framework.response import Response
from jobs.competition import Sportcompetition
from django.utils import timezone
from django.db.models import Q
from blog.models import Category, Blogpost, User
from App.models import Matches, Predictions, UnavailablePredictions, LeagueStanding, AppSettings, Textlinks
from rest_framework import status
from rest_framework.validators import UniqueValidator
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated, IsAdminUser, AllowAny
from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework_simplejwt.tokens import RefreshToken, TokenError
from rest_framework import serializers

class LogOutView(APIView):
    authentication_classes = [JWTAuthentication] # authentication_classes = [AllowAny]
    permission_classes = [IsAuthenticated] # IsAdminUser
    
    def post(self, request):
        try:
            refresh_token = request.data["refresh"]
            if not refresh_token:
                return Response(
                    {"error": "Refresh token is required."},
                    status=status.HTTP_400_BAD_REQUEST
                )

            token = RefreshToken(refresh_token)
            token.blacklist()  # mark token as blacklisted

            return Response(
                {"message": "Logout successful — token blacklisted."},
                status=status.HTTP_200_OK
            )

        except TokenError:
            return Response(
                {"error": "Invalid or already blacklisted token."},
                status=status.HTTP_400_BAD_REQUEST
            )

class CompetitionListView(APIView):
    permission_classes = [IsAdminUser]
    authentication_classes = [JWTAuthentication] # authentication_classes = [AllowAny]

    class MatchesSerializer(serializers.ModelSerializer):
        class Meta:
            model = Matches
            fields = '__all__'
        
    def get(self, request):
        if request.GET["req"] == "competitions_list":
            compiled_competitions = []
            for competition in Sportcompetition.competitions:
                compiled_competitions.append({
                    "competition": competition["competition"],
                    "name": competition["name"],
                    "region": competition["region"],
                    "flag": competition["flag"],
                })
            return Response(compiled_competitions, status=status.HTTP_200_OK)
            
        elif request.GET["req"] == "match_list":
            matches = Matches.objects.filter(competition=request.GET["competition_key"], commencement_time__date=timezone.now().date(), is_completed=False)
            serializer = self.MatchesSerializer(matches, many=True)
            return Response(serializer.data, status=status.HTTP_200_OK)

class GetLinks(APIView):
    
    class TextlinksSerializer(serializers.ModelSerializer):
        class Meta:
            model = Textlinks
            fields = ['name', 'href']
        
    def get(self, request):
        links = Textlinks.objects.all()
        serializer = self.TextlinksSerializer(links, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)
        

class GetStananding(APIView):
    
    def get(self, request):
        try:
            competition = request.GET["competition"]
            if not LeagueStanding.objects.filter(competition=competition).exists():
                return Response({"error": "Competition Unavailable!"}, status=status.HTTP_400_BAD_REQUEST)
            standing = LeagueStanding.objects.get(competition=competition)
            standing_data = []
            for team in standing.standing["table"]:
                standing_data.append({
                    "p": team["position"],
                    "team": team['team']["tla"],
                    "M": team["playedGames"],
                    "W": team["won"],
                    "D": team["draw"],
                    "L": team["lost"],
                    "GD": team["goalDifference"],
                    "P": team["points"]
                })
            # Get match region 
            comp = next((c for c in Sportcompetition.competitions if c["competition"] == competition), None)

            return Response({
                "region": comp["region"] if comp else "",
                "competition": comp["name"] if comp else "",
                "standing_data": standing_data,
            }, status=status.HTTP_200_OK)
        except:
            return Response({"error": "Bad request."}, status=status.HTTP_400_BAD_REQUEST)
        
        
class GetBlogPost(APIView):
    
    def get(self, request):
        try:
            category = Category.objects.get(category="Sport")
            sport = Blogpost.objects.filter(category=category.pk).order_by("-date_created")[:3]
            sport_blog = []
            for i in sport:
                sport_blog.append(
                    {
                        "id" : i.pk,
                        "title": i.title,
                        "image": str(i.image)
                    }
                )
            return Response({
                "category": category.pk,
                "blog_post": sport_blog,
            }, status=status.HTTP_200_OK)
        except:
            return Response(
                    {"error": "Bad request."},
                    status=status.HTTP_400_BAD_REQUEST
                )
    
    
class GettodayFixtures(APIView):
    class MatchSerializer(serializers.ModelSerializer):
        class Meta:
            model = Matches
            fields = [
                "home_team",
                "away_team",
                "commencement_time"
            ]
    
    def get(self, request):
        matchs = Matches.objects.filter(commencement_time__date=timezone.now().date())
        fixtures = []
        for m in matchs:
            comp = next((c for c in Sportcompetition.competitions if c["competition"] == m.competition), None)
            fixtures.append({
                "home_team": m.home_team,
                "away_team": m.away_team,
                "commencement_time": m.commencement_time,
                "region": comp["region"] if comp else "",
                "competition": comp["name"] if comp else "",
            })
        return Response(fixtures, status=status.HTTP_200_OK)
        
        # match = Matches.objects.filter(commencement_time__date=timezone.now().date())
        # serializer = self.MatchSerializer(match, many=True)
        # return Response(serializer.data, status=status.HTTP_200_OK)
            
            
class GetDetailView(APIView):
    class PredictionSerializer(serializers.ModelSerializer):
        class Meta:
            model = Predictions
            fields = '__all__'   # return ALL model fields
            
    class MatchesSerializer(serializers.ModelSerializer):
        class Meta:
            model = Matches
            fields = '__all__'   # return ALL model fields
            
    def get(self, request):
        # Safely get query parameters (avoid MultiValueDictKeyError)
        match_id = request.GET.get("match_id")
        pred_id = request.GET.get("id")

        # Validate input
        if not match_id or not pred_id:
            return Response(
                {"error": "Both 'match_id' and 'id' query params are required."},
                status=status.HTTP_400_BAD_REQUEST
            )

        # Fetch prediction safely
        try:
            prediction = Predictions.objects.get(id=pred_id)
            match = Matches.objects.get(match_id=match_id)
            home_prev = Matches.objects.filter(Q(home_team=match.home_team) | Q(away_team=match.home_team), is_completed=True).order_by('-commencement_time')[:5]
            away_prev = Matches.objects.filter(Q(home_team=match.away_team) | Q(away_team=match.away_team), is_completed=True).order_by('-commencement_time')[:5]
        except Predictions.DoesNotExist:
            return Response(
                {"error": "Prediction not found."},
                status=status.HTTP_404_NOT_FOUND
            )
        
        pred_serializer = self.PredictionSerializer(prediction)
        match_serializer = self.MatchesSerializer(match)
        
        home_form = []
        home_prev_match = []
        away_form = []
        away_prev_match = []
        
        # Handle home  form
        for i in home_prev:
            try:
                if int(i.score_home) == int(i.score_away):
                    home_form.append("D")
                elif i.home_team == match.home_team:
                    if int(i.score_home) > int(i.score_away):
                        home_form.append("W")
                    else:home_form.append("L")
                elif i.away_team == match.home_team:
                    if int(i.score_home) < int(i.score_away):
                        home_form.append("W")
                    else:home_form.append("L")
            except:pass
            
            # Handle away previous matches
            home_prev_match.append({
                "date": i.commencement_time.date(),
                "team1": i.home_team,
                "score": f"{i.score_home if i.score_home != None else "--"} : {i.score_away if i.score_away != None else "--"}",
                "team2": i.away_team
            })
        
        # Handle away  form
        for i in away_prev:
            try:
                if int(i.score_home) == int(i.score_away):
                    away_form.append("D")
                elif i.home_team == match.away_team:
                    if int(i.score_home) > int(i.score_away):
                        away_form.append("W")
                    else:away_form.append("L")
                elif i.away_team == match.away_team:
                    if int(i.score_home) < int(i.score_away):
                        away_form.append("W")
                    else:away_form.append("L")
            except:pass
            
            # Handle away previous matches
            away_prev_match.append({
                "date": i.commencement_time.date(),
                "team1": i.home_team,
                "score": f"{i.score_home} : {i.score_away}",
                "team2": i.away_team
            })
        
        # Get match region 
        comp = next((c for c in Sportcompetition.competitions if c["competition"] == match.competition), None)

        # Successful response
        return Response(
            {
                "region": comp["region"] if comp else "",
                "prediction_data": pred_serializer.data,
                "match_data": match_serializer.data,
                "h2h": {
                    "home_prev_match": home_prev_match,
                    "home_form": home_form,
                    "away_prev_match": away_prev_match,
                    "away_form": away_form
                }
            },
            status=status.HTTP_200_OK
        )


class AppSettingsView(APIView):
    class AppSettingsSerializer(serializers.ModelSerializer):
        
        key = serializers.CharField(validators=[UniqueValidator(queryset=AppSettings.objects.all(), message="this key already exists")])
        
        class Meta:
            model = AppSettings
            fields = '__all__'
    
    authentication_classes = [JWTAuthentication]
    
    def get_permissions(self):
        if self.request.method == "GET":
            return [AllowAny()]
        
        elif self.request.method == "POST":
            return [IsAdminUser()]
        
    def post(self, request):
        key = request.data["key"]
        
        instance = AppSettings.objects.filter(key=key).first()

        if instance:
            # UPDATE existing object
            serializer = self.AppSettingsSerializer(instance, data=request.data, partial=True)
            action = "updated"
        else:
            # CREATE new object
            serializer = self.AppSettingsSerializer(data=request.data)
            action = "created"
            
        if serializer.is_valid():
            serializer.save()
            return Response(
                {"message": f"AppSettings {action} successfully", "data": serializer.data},
                status=status.HTTP_200_OK
            )
            
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        
    def get(self, request):
        try:
            key = request.GET.get("key")
            settings = AppSettings.objects.get(key=key)
            serializer = self.AppSettingsSerializer(settings)
            return Response(serializer.data, status=status.HTTP_200_OK)
        except:
            return Response({"error": "Bad request."}, status=status.HTTP_400_BAD_REQUEST)
        
class UserRegisterView(APIView):
    class UserSerializer(serializers.ModelSerializer):
        
        class Meta:
            model = User
            fields = [
                "username",
                "first_name",
                "last_name",
                "phone_number",
                "email",
                "password"
            ]
            extra_kwargs = {
            'password': {'write_only': True}
        }
        
    
        def create(self, validated_data):
            user = User(**validated_data)
            user.set_password(validated_data["password"])
            user.save()
            return user
    
    def post(self, request):
        serializer = self.UserSerializer(data=request.data)
         
        if serializer.is_valid():
            serializer.save()
            return Response(
                {"message": f"New user created successfully.", "data": serializer.data},
                status=status.HTTP_200_OK
            )
            
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
        
    
class GetPredictionsView(APIView):
    def get(self, request):
        prediction_list = []
        #predictions = Predictions.objects.all()  # For production, remove this line and also unmultiply the returned prediction_list
        predictions = Predictions.objects.filter(Q(commencement_time__date=timezone.now().date())) # | Q(date_created__date=timezone.now().date())
        unav_predictions = UnavailablePredictions.objects.filter(Q(commencement_time__date=timezone.now().date())) # | Q(date_created__date=timezone.now().date())
        for i in predictions:
            match = Matches.objects.get(match_id=i.match_id)
            comp = next((c for c in Sportcompetition.competitions if c["competition"] == match.competition), None)
            prediction_list.append({
                "id": i.id,
                "match_id": i.match_id,
                "home_team":match.home_team,
                "away_team":match.away_team,
                "score_home": match.score_home,
                "score_away": match.score_away,
                "tip": i.tip,
                "competition": i.competition,
                "region": comp["region"] if comp else "",
                "odds": i.odds,
                "commencement_time": i.commencement_time,
            })
            
        for i in unav_predictions:
            prediction_list.append({
                "id": "",
                "match_id": None,
                "home_team":i.home_team,
                "away_team":i.away_team,
                "score_home": None,
                "score_away": None,
                "tip": i.tip,
                "competition": i.competition,
                "region": "",
                "odds": i.odds,
                "commencement_time": i.commencement_time,
            })
        return Response(list(reversed(prediction_list)), status=status.HTTP_200_OK)
    

class PredictionsView(APIView):
    permission_classes = [IsAdminUser]
    authentication_classes = [JWTAuthentication] # authentication_classes = [AllowAny]

    class PredictionsSerializer(serializers.ModelSerializer):
        class Meta:
            model = Predictions
            fields = '__all__'  
        
    def post(self, request):
        serializer = self.PredictionsSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class UnavailablePredictionsView(APIView):
    permission_classes = [IsAdminUser]
    authentication_classes = [JWTAuthentication] # authentication_classes = [AllowAny]
    
    class UnavailablePredictionsSerializer(serializers.ModelSerializer):
        class Meta:
            model = UnavailablePredictions
            fields = '__all__'  

    def post(self, request):
        serializer = self.UnavailablePredictionsSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    