from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import generics, status
from rest_framework.permissions import IsAuthenticated
from django.utils import timezone
from django.conf import settings
from django.core.validators import validate_email
from django.core.exceptions import ValidationError
from django.shortcuts import get_object_or_404
from django.utils.dateparse import parse_date
from django.db.models import Avg, Count
from datetime import timedelta
import secrets
import uuid
import logging

from apps.apps_.models import App, APIKey
from .models import BusinessPlatformLinks, Tour, ReviewLink, Review
from .serializers import (
    PlatformLinksReadSerializer,
    ReviewLinkSerializer, 
    ReviewSerializer, 
    ReviewSubmitSerializer, 
    BusinessPlatformLinksSerializer,
)
from .email_service import ReviewEmailService

logger = logging.getLogger(__name__)


class ReviewLinkCreateView(APIView):
    """
    Generate a secure review link for a tour and optionally send it via email.
    Authenticated via API key.
    """

    def post(self, request, *args, **kwargs):
        api_key_value = request.headers.get("X-API-KEY")
        if not api_key_value:
            return Response({"detail": "API key required"}, status=status.HTTP_401_UNAUTHORIZED)

        # Validate API key
        try:
            api_key = APIKey.objects.get(key=api_key_value, revoked=False)
            app = api_key.app
        except APIKey.DoesNotExist:
            return Response({"detail": "Invalid API key"}, status=status.HTTP_401_UNAUTHORIZED)

        # Extract required fields
        your_tour_id = request.data.get("tour_id")
        customer_email = request.data.get("customer_email")
        
        # Optional fields
        tour_name = request.data.get("tour_name")
        tour_date = request.data.get("tour_date")
        send_email = request.data.get("send_email", True)  # Default to True
        company_name = request.data.get("company_name")

        if not your_tour_id or not customer_email:
            return Response({
                "detail": "tour_id and customer_email are required"
            }, status=status.HTTP_400_BAD_REQUEST)

        try:
            # Validate email format
            try:
                validate_email(customer_email)
            except ValidationError:
                return Response({
                    "detail": "Invalid email format"
                }, status=status.HTTP_400_BAD_REQUEST)

            # Parse tour_date if provided
            parsed_tour_date = None
            if tour_date:
                parsed_tour_date = parse_date(tour_date)
                if not parsed_tour_date:
                    return Response({
                        "detail": "Invalid tour_date format. Use YYYY-MM-DD"
                    }, status=status.HTTP_400_BAD_REQUEST)

            logger.info(f"Creating review link for tour {your_tour_id}, email {customer_email}")

            # Get or create tour **per app**
            tour_defaults = {
                "name": tour_name or f"Tour {your_tour_id}",
                "date": parsed_tour_date or timezone.now().date(),
            }
            
            tour, created = Tour.objects.get_or_create(
                app=app,
                external_id=your_tour_id,
                defaults=tour_defaults
            )
            
            # If tour exists but we have updated info, update it
            if not created and (tour_name or parsed_tour_date):
                updated = False
                if tour_name and tour.name != tour_name:
                    tour.name = tour_name
                    updated = True
                if parsed_tour_date and tour.date != parsed_tour_date:
                    tour.date = parsed_tour_date
                    updated = True
                if updated:
                    tour.save()

            # Generate tokens
            token_str = secrets.token_urlsafe(32)
            token_uuid = uuid.uuid4()

            # Create the review link
            link = ReviewLink.objects.create(
                tour=tour,
                customer_email=customer_email,
                token_uuid=token_uuid,
                token_str=token_str,
                expires_at=timezone.now() + timedelta(days=7)
            )

            # Generate secure URL - use settings.SITE_URL (loaded by python-decouple)
            frontend_url = getattr(settings, 'FRONTEND_URL', 'http://localhost:3000')
            secure_url = f"{frontend_url}/review/{token_str}"

            # Prepare response
            serializer = ReviewLinkSerializer(link)
            response_data = serializer.data
            response_data["secure_link"] = secure_url
            response_data["tour_created"] = created

            # Send email if requested
            if send_email:
                try:
                    email_sent = ReviewEmailService.send_review_link_email(
                        review_link=link,
                        company_name=company_name or (app.company.name if hasattr(app, 'company') else None)
                    )
                    response_data["email_sent"] = email_sent
                    
                    if email_sent:
                        logger.info(f"Review link email sent successfully to {customer_email}")
                    else:
                        logger.warning(f"Failed to send review link email to {customer_email}")
                        
                except Exception as e:
                    logger.error(f"Email sending failed for {customer_email}: {str(e)}")
                    response_data["email_sent"] = False
                    response_data["email_error"] = "Failed to send email"
            else:
                response_data["email_sent"] = False
                response_data["email_skipped"] = True

            return Response(response_data, status=status.HTTP_201_CREATED)

        except Exception as e:
            logger.error(f"Error creating review link: {str(e)}", exc_info=True)
            
            # In debug mode, return the actual error for easier debugging
            if settings.DEBUG:
                return Response({
                    "detail": f"An error occurred while creating the review link: {str(e)}"
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
            else:
                return Response({
                    "detail": "An error occurred while creating the review link"
                }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


class ReviewSubmitView(generics.CreateAPIView):
    serializer_class = ReviewSubmitSerializer

    def create(self, request, *args, **kwargs):
        token_str = kwargs.get("token_str")
        link = get_object_or_404(ReviewLink, token_str=token_str)

        if link.expires_at < timezone.now():
            return Response({"detail": "Link expired"}, status=status.HTTP_400_BAD_REQUEST)

        # Check if review already exists for this customer + tour
        review = Review.objects.filter(
            tour=link.tour,
            customer_email=link.customer_email,
            source="internal"
        ).first()

        serializer = self.get_serializer(instance=review, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)

        if review:
            # Update existing review
            review = serializer.save()
            return Response(ReviewSerializer(review).data, status=status.HTTP_200_OK)
        else:
            # Create new review
            review = serializer.save(
                tour=link.tour,
                customer_email=link.customer_email,  
                source="internal"
            )
            return Response(ReviewSerializer(review).data, status=status.HTTP_201_CREATED)


class TourReviewListView(generics.ListAPIView):
    """
    List all reviews for a given tour (scoped to the company via API key).
    """
    serializer_class = ReviewSerializer

    def get_queryset(self):
        request = self.request
        api_key_value = request.headers.get("X-API-KEY")

        if not api_key_value:
            return Review.objects.none()

        try:
            api_key = APIKey.objects.get(key=api_key_value, revoked=False)
            app = api_key.app
        except APIKey.DoesNotExist:
            return Review.objects.none()

        # Use external_id instead of internal UUID
        external_id = self.kwargs.get("tour_id")

        return Review.objects.filter(
            tour__external_id=external_id,
            tour__app=app
        ).order_by("-submitted_at")


class ReviewAnalyticsView(APIView):
    """
    Return average rating and counts per source for a tour or app.
    """

    def get(self, request, *args, **kwargs):
        api_key_value = request.headers.get("X-API-KEY")
        if not api_key_value:
            return Response({"detail": "API key required"}, status=401)

        try:
            api_key = APIKey.objects.get(key=api_key_value, revoked=False)
            app = api_key.app
        except APIKey.DoesNotExist:
            return Response({"detail": "Invalid API key"}, status=401)

        tour_id = request.query_params.get("tour_id")

        reviews = Review.objects.filter(tour__app=app)
        if tour_id:
            reviews = reviews.filter(tour__id=tour_id)

        data = {
            "average_rating": reviews.aggregate(avg=Avg("rating"))["avg"] or 0,
            "total_reviews": reviews.count(),
            "by_source": reviews.values("source").annotate(count=Count("id"))
        }

        return Response(data)


class ReviewPlatformLinksView(APIView):
    """Get platform-specific review links for a review token - NO API KEY REQUIRED"""
    
    def get(self, request, token_str, *args, **kwargs):
        try:
            # Get the review link to identify the app - using token_str for auth
            link = get_object_or_404(ReviewLink, token_str=token_str)
            app = link.tour.app
            
            # Check if link is expired
            if link.expires_at < timezone.now():
                return Response({
                    "valid": False,
                    "error": "Link has expired"
                }, status=status.HTTP_400_BAD_REQUEST)
            
            # Get platform links for this app
            try:
                platform_links = BusinessPlatformLinks.objects.get(app=app)
                
                # Get configured platforms with direct URLs
                links_data = platform_links.get_configured_platforms()
                
                return Response({
                    "valid": True,
                    "business_name": platform_links.business_name or app.name,
                    "tour_name": link.tour.name,
                    "tour_date": link.tour.date.isoformat(),
                    "platform_links": links_data
                })
                
            except BusinessPlatformLinks.DoesNotExist:
                # Return empty links if not configured
                return Response({
                    "valid": True,
                    "business_name": app.name,
                    "tour_name": link.tour.name,
                    "tour_date": link.tour.date.isoformat(),
                    "platform_links": [],
                    "message": "No platform links configured for this business"
                })
                
        except Exception as e:
            logger.error(f"Error getting platform links for {token_str}: {str(e)}")
            return Response({
                "valid": False,
                "error": "Invalid or expired link"
            }, status=status.HTTP_404_NOT_FOUND)


class BusinessPlatformLinksManagementView(APIView):
    """
    Management API for platform links - requires JWT authentication
    GET: Retrieve platform links for the authenticated app
    POST: Create platform links for the authenticated app
    PUT: Update platform links for the authenticated app
    DELETE: Delete platform links for the authenticated app
    """

    permission_classes = [IsAuthenticated]

    def get_app_for_user(self, request):
        """Helper to fetch the app linked to the authenticated user"""
        try:
            return request.user.app  # adjust if your relation is different
        except AttributeError:
            return None

    def get(self, request, *args, **kwargs):
        """Get platform configuration for the authenticated app"""
        app = self.get_app_for_user(request)
        if not app:
            return Response({"detail": "No app associated with this user"}, status=status.HTTP_403_FORBIDDEN)

        try:
            platform_links = BusinessPlatformLinks.objects.get(app=app)
            serializer = PlatformLinksReadSerializer(platform_links)
            return Response(serializer.data)
        except BusinessPlatformLinks.DoesNotExist:
            return Response({
                "message": "No platform configuration found for this app",
                "app_name": app.name,
                "configured": False
            }, status=status.HTTP_404_NOT_FOUND)

    def post(self, request, *args, **kwargs):
        """Create platform configuration for the authenticated app"""
        app = self.get_app_for_user(request)
        if not app:
            return Response({"detail": "No app associated with this user"}, status=status.HTTP_403_FORBIDDEN)

        if BusinessPlatformLinks.objects.filter(app=app).exists():
            return Response({
                "detail": "Platform configuration already exists for this app. Use PUT to update."
            }, status=status.HTTP_400_BAD_REQUEST)

        serializer = BusinessPlatformLinksSerializer(data=request.data)
        if serializer.is_valid():
            platform_links = serializer.save(app=app)

            logger.info(f"Platform links created for app {app.name} ({app.id})")
            read_serializer = PlatformLinksReadSerializer(platform_links)
            return Response(read_serializer.data, status=status.HTTP_201_CREATED)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def put(self, request, *args, **kwargs):
        """Update platform configuration for the authenticated app"""
        app = self.get_app_for_user(request)
        if not app:
            return Response({"detail": "No app associated with this user"}, status=status.HTTP_403_FORBIDDEN)

        try:
            platform_links = BusinessPlatformLinks.objects.get(app=app)
        except BusinessPlatformLinks.DoesNotExist:
            return Response({
                "detail": "No platform configuration found for this app. Use POST to create."
            }, status=status.HTTP_404_NOT_FOUND)

        serializer = BusinessPlatformLinksSerializer(platform_links, data=request.data, partial=True)
        if serializer.is_valid():
            platform_links = serializer.save()
            logger.info(f"Platform links updated for app {app.name} ({app.id})")

            read_serializer = PlatformLinksReadSerializer(platform_links)
            return Response(read_serializer.data)

        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, *args, **kwargs):
        """Delete platform configuration for the authenticated app"""
        app = self.get_app_for_user(request)
        if not app:
            return Response({"detail": "No app associated with this user"}, status=status.HTTP_403_FORBIDDEN)

        try:
            platform_links = BusinessPlatformLinks.objects.get(app=app)
            platform_links.delete()
            logger.info(f"Platform links deleted for app {app.name} ({app.id})")

            return Response({"message": "Platform configuration deleted successfully"}, status=status.HTTP_204_NO_CONTENT)
        except BusinessPlatformLinks.DoesNotExist:
            return Response({"detail": "No platform configuration found for this app"}, status=status.HTTP_404_NOT_FOUND)


class BusinessPlatformLinksStatusView(APIView):
    """
    Get a quick status of platform configuration for dashboard - JWT only
    """

    permission_classes = [IsAuthenticated]

    def get_app_for_user(self, request):
        try:
            return request.user.app
        except AttributeError:
            return None

    def get(self, request, *args, **kwargs):
        app = self.get_app_for_user(request)
        if not app:
            return Response({"detail": "No app associated with this user"}, status=status.HTTP_403_FORBIDDEN)

        try:
            platform_links = BusinessPlatformLinks.objects.get(app=app)

            platform_status = {
                "google": bool(platform_links.google_review_url),
                "tripadvisor": bool(platform_links.tripadvisor_review_url),
                "facebook": bool(platform_links.facebook_review_url),
                "booking": bool(platform_links.booking_review_url),
            }
            platforms_configured = sum(platform_status.values())

            return Response({
                "configured": True,
                "platforms_configured": platforms_configured,
                "total_platforms": 4,
                "platform_status": platform_status,
                "business_name": platform_links.business_name or app.name,
                "last_updated": platform_links.updated_at.isoformat()
            })

        except BusinessPlatformLinks.DoesNotExist:
            return Response({
                "configured": False,
                "platforms_configured": 0,
                "total_platforms": 4,
                "platform_status": {
                    "google": False,
                    "tripadvisor": False,
                    "facebook": False,
                    "booking": False,
                },
                "business_name": app.name,
                "message": "No platform configuration found"
            })