"""
NOMAZRA views — AI Legal Assistant for 140+ countries.
Integrates: country_data (155 countries), glossary_data (300+ terms),
ai_service (branded GPT), storage_service (R2), file_converter,
subscription enforcement, voice tiers.
"""
import os
import io
import time
import uuid
import tempfile
import logging

from django.db import IntegrityError
from django.http import HttpResponse
from django.utils import timezone
from rest_framework import status
from rest_framework.decorators import api_view, permission_classes, parser_classes
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.response import Response

from .models import (
    Conversation, Message, Document, RightsCard,
    GlossaryTerm, VoiceSession, Bookmark, Reminder, Feedback, UserStats,
)
from .serializers import (
    ConversationListSerializer, ConversationDetailSerializer,
    MessageSerializer, DocumentSerializer, RightsCardSerializer,
    GlossaryTermSerializer, VoiceSessionSerializer, BookmarkSerializer,
    ReminderSerializer, FeedbackSerializer, UserStatsSerializer,
)
from . import ai_service, storage_service, file_converter
from .country_data import (
    get_all_countries, get_country, search_countries, get_emergency_info, LEGAL_TOPICS,
)
from .glossary_data import search_glossary, get_glossary_term, get_glossary_by_area, LEGAL_GLOSSARY

logger = logging.getLogger(__name__)

# Max sizes
MAX_MESSAGE_LENGTH = 5000  # chars
MAX_UPLOAD_SIZE = 50 * 1024 * 1024  # 50MB

ALLOWED_DOC_TYPES = {
    'application/pdf', 'application/msword',
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
    'text/plain', 'text/csv',
    'image/jpeg', 'image/png', 'image/webp',
    'audio/mpeg', 'audio/wav', 'audio/ogg', 'audio/mp4', 'audio/webm',
}

# ── SUBSCRIPTION PLAN LIMITS ──

PLAN_LIMITS = {
    'free': {
        'queries_per_day': 10,
        'docs_per_day': 1,
        'voice_sessions_per_day': 0,
        'tts_per_day': 5,
        'countries': 1,
        'history_days': 7,
        'tts_voices': {'echo', 'nova'},
    },
    'plus': {
        'queries_per_day': 50,
        'docs_per_day': 10,
        'voice_sessions_per_day': 5,
        'tts_per_day': 30,
        'countries': 5,
        'history_days': 90,
        'tts_voices': {'echo', 'nova', 'alloy', 'shimmer'},
    },
    'premium': {
        'queries_per_day': 999999,
        'docs_per_day': 999999,
        'voice_sessions_per_day': 999999,
        'tts_per_day': 999999,
        'countries': 999999,
        'history_days': 365,
        'tts_voices': {'alloy', 'echo', 'fable', 'onyx', 'nova', 'shimmer'},
    },
    'professional': {
        'queries_per_day': 999999,
        'docs_per_day': 999999,
        'voice_sessions_per_day': 999999,
        'tts_per_day': 999999,
        'countries': 999999,
        'history_days': 999999,
        'tts_voices': {'alloy', 'echo', 'fable', 'onyx', 'nova', 'shimmer'},
    },
}


def _get_plan(user):
    """Get user's subscription plan. Returns plan key string."""
    plan = getattr(user, 'subscription_plan', None) or 'free'
    return plan if plan in PLAN_LIMITS else 'free'


def _get_limits(user):
    """Get plan limits for user."""
    return PLAN_LIMITS[_get_plan(user)]


def _daily_usage(user, model_class, date_field='created_at'):
    """Count today's usage for a model."""
    today = timezone.now().date()
    return model_class.objects.filter(
        user=user,
        **{f'{date_field}__date': today},
    ).count()


def _check_query_limit(user):
    """Check if user is within daily query limits. Returns (allowed, error_response)."""
    limits = _get_limits(user)
    today = timezone.now().date()
    today_queries = Message.objects.filter(
        conversation__user=user,
        role='user',
        created_at__date=today,
    ).count()
    if today_queries >= limits['queries_per_day']:
        plan = _get_plan(user)
        return False, Response({
            'error': 'Daily query limit reached',
            'limit': limits['queries_per_day'],
            'used': today_queries,
            'plan': plan,
            'upgrade_message': 'Upgrade your plan for more queries.' if plan == 'free' else None,
        }, status=status.HTTP_429_TOO_MANY_REQUESTS)
    return True, None


def _check_doc_limit(user):
    """Check daily document upload limit."""
    limits = _get_limits(user)
    today_docs = _daily_usage(user, Document)
    if today_docs >= limits['docs_per_day']:
        plan = _get_plan(user)
        return False, Response({
            'error': 'Daily document limit reached',
            'limit': limits['docs_per_day'],
            'used': today_docs,
            'plan': plan,
        }, status=status.HTTP_429_TOO_MANY_REQUESTS)
    return True, None


# ──────────────────── CONVERSATIONS ────────────────────

@api_view(['GET', 'POST'])
@permission_classes([IsAuthenticated])
def conversations(request):
    if request.method == 'GET':
        qs = Conversation.objects.filter(user=request.user)
        ser = ConversationListSerializer(qs, many=True)
        return Response(ser.data)

    title = request.data.get('title', '')[:255]
    country = request.data.get('country', 'KH')[:5]
    conv = Conversation.objects.create(
        user=request.user, title=title, country=country,
    )
    ser = ConversationDetailSerializer(conv)
    return Response(ser.data, status=status.HTTP_201_CREATED)


@api_view(['GET', 'DELETE'])
@permission_classes([IsAuthenticated])
def conversation_detail(request, pk):
    try:
        conv = Conversation.objects.get(pk=pk, user=request.user)
    except Conversation.DoesNotExist:
        return Response({'error': 'Not found'}, status=status.HTTP_404_NOT_FOUND)

    if request.method == 'DELETE':
        conv.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

    ser = ConversationDetailSerializer(conv)
    return Response(ser.data)


@api_view(['GET', 'POST'])
@permission_classes([IsAuthenticated])
def conversation_messages(request, pk):
    try:
        conv = Conversation.objects.get(pk=pk, user=request.user)
    except Conversation.DoesNotExist:
        return Response({'error': 'Not found'}, status=status.HTTP_404_NOT_FOUND)

    if request.method == 'GET':
        msgs = conv.messages.all()
        ser = MessageSerializer(msgs, many=True)
        return Response(ser.data)

    # POST — user sends a message, AI responds
    content = request.data.get('content', '').strip()
    input_type = request.data.get('input_type', 'text')
    if not content:
        return Response({'error': 'Content required'}, status=status.HTTP_400_BAD_REQUEST)
    if len(content) > MAX_MESSAGE_LENGTH:
        return Response(
            {'error': f'Message too long (max {MAX_MESSAGE_LENGTH} chars)'},
            status=status.HTTP_400_BAD_REQUEST,
        )

    # Check query limit
    allowed, err = _check_query_limit(request.user)
    if not allowed:
        return err

    # Save user message
    user_msg = Message.objects.create(
        conversation=conv, role='user', content=content, input_type=input_type,
    )

    # Build conversation history for context
    history_msgs = conv.messages.exclude(pk=user_msg.pk).order_by('created_at')[:20]
    conversation_history = [
        {'role': m.role, 'content': m.content} for m in history_msgs
    ]

    # Check if there's a document attached to this conversation
    document_text = None
    latest_doc = conv.documents.filter(
        status='completed', extracted_text__gt='',
    ).order_by('-created_at').first()
    if latest_doc:
        document_text = latest_doc.extracted_text

    # Resolve country name
    country_name = None
    country_info = get_country(conv.country)
    if country_info:
        country_name = country_info['name']

    # Call AI with country context
    start = time.time()
    result = ai_service.chat(
        user_message=content,
        conversation_history=conversation_history,
        document_text=document_text,
        country=country_name,
    )
    elapsed = int((time.time() - start) * 1000)

    ai_msg = Message.objects.create(
        conversation=conv,
        role='assistant',
        content=result['response'],
        tokens_used=result.get('input_tokens', 0) + result.get('output_tokens', 0),
        processing_time_ms=elapsed,
    )

    # Update stats
    stats, _ = UserStats.objects.get_or_create(user=request.user)
    stats.total_queries += 1
    stats.last_active_date = timezone.now().date()
    if conv.country not in (stats.countries_queried or []):
        stats.countries_queried = (stats.countries_queried or []) + [conv.country]
    stats.save()

    # Auto-set title from first message
    if conv.messages.filter(role='user').count() == 1 and not conv.title:
        conv.title = content[:100]
        conv.save(update_fields=['title'])

    return Response({
        'user_message': MessageSerializer(user_msg).data,
        'ai_message': MessageSerializer(ai_msg).data,
    }, status=status.HTTP_201_CREATED)


# ──────────────────── FILE UPLOAD (R2) ────────────────────

@api_view(['POST'])
@permission_classes([IsAuthenticated])
@parser_classes([MultiPartParser, FormParser])
def upload_file(request):
    """Upload a file to R2 storage. Returns the file URL."""
    file_obj = request.FILES.get('file')
    category = request.data.get('category', 'documents')

    if not file_obj:
        return Response({'error': 'No file provided'}, status=status.HTTP_400_BAD_REQUEST)
    if file_obj.size > MAX_UPLOAD_SIZE:
        return Response({'error': 'File too large (max 50MB)'}, status=status.HTTP_400_BAD_REQUEST)

    content_type = file_obj.content_type or 'application/octet-stream'
    if content_type not in ALLOWED_DOC_TYPES:
        return Response(
            {'error': f'File type not allowed: {content_type}'},
            status=status.HTTP_400_BAD_REQUEST,
        )

    try:
        r2 = storage_service.R2Client()
        result = r2.upload_file(
            user_id=str(request.user.id),
            category=category,
            file_name=file_obj.name,
            file_data=file_obj.read(),
            content_type=content_type,
        )
        return Response(result, status=status.HTTP_201_CREATED)
    except ValueError as e:
        return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST)
    except Exception as e:
        logger.error("File upload failed: %s", e)
        return Response(
            {'error': 'Upload failed'},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR,
        )


# ──────────────────── DOCUMENTS ────────────────────

@api_view(['GET', 'POST'])
@permission_classes([IsAuthenticated])
@parser_classes([MultiPartParser, FormParser])
def documents(request):
    if request.method == 'GET':
        qs = Document.objects.filter(user=request.user)
        ser = DocumentSerializer(qs, many=True)
        return Response(ser.data)

    # Check doc limit
    allowed, err = _check_doc_limit(request.user)
    if not allowed:
        return err

    # POST — upload document for analysis
    file_obj = request.FILES.get('file')
    file_url = request.data.get('file_url', '')
    original_name = request.data.get('original_name', '')
    conversation_id = request.data.get('conversation_id')

    # If a file is uploaded directly, process it
    if file_obj:
        if file_obj.size > MAX_UPLOAD_SIZE:
            return Response({'error': 'File too large (max 50MB)'}, status=status.HTTP_400_BAD_REQUEST)

        content_type = file_obj.content_type or 'application/octet-stream'
        if content_type not in ALLOWED_DOC_TYPES:
            return Response(
                {'error': f'File type not allowed: {content_type}'},
                status=status.HTTP_400_BAD_REQUEST,
            )

        original_name = original_name or file_obj.name

        # Upload to R2
        try:
            r2 = storage_service.R2Client()
            upload_result = r2.upload_file(
                user_id=str(request.user.id),
                category='documents',
                file_name=file_obj.name,
                file_data=file_obj.read(),
                content_type=content_type,
            )
            file_url = upload_result['url']
        except Exception as e:
            logger.error("Document upload to R2 failed: %s", e)
            return Response({'error': 'Upload failed'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        # Extract text from file
        extracted_text = ''
        try:
            with tempfile.NamedTemporaryFile(delete=False, suffix=os.path.splitext(file_obj.name)[1]) as tmp:
                file_obj.seek(0)
                for chunk in file_obj.chunks():
                    tmp.write(chunk)
                tmp_path = tmp.name

            raw_text = file_converter.extract_text(tmp_path, content_type)
            extracted_text = file_converter.sanitize_extracted_text(raw_text)
        except Exception as e:
            logger.error("Text extraction failed: %s", e)
            extracted_text = f"[Text extraction failed: {e}]"
        finally:
            if 'tmp_path' in locals():
                try:
                    os.unlink(tmp_path)
                except OSError:
                    pass

        file_type = content_type
    elif file_url and original_name:
        file_type = request.data.get('file_type', '')
        extracted_text = ''
    else:
        return Response(
            {'error': 'Provide a file upload or file_url + original_name'},
            status=status.HTTP_400_BAD_REQUEST,
        )

    conv = None
    if conversation_id:
        try:
            conv = Conversation.objects.get(pk=conversation_id, user=request.user)
        except Conversation.DoesNotExist:
            pass

    doc = Document.objects.create(
        user=request.user,
        conversation=conv,
        file_url=file_url,
        file_type=file_type,
        original_name=original_name[:255],
        extracted_text=extracted_text,
        status='completed' if extracted_text else 'processing',
    )

    # If text was extracted, generate AI analysis
    if extracted_text and not extracted_text.startswith('['):
        try:
            # Get country context from conversation
            country_name = None
            if conv and conv.country:
                ci = get_country(conv.country)
                if ci:
                    country_name = ci['name']
            analysis_result = ai_service.summarize_document(extracted_text, original_name, country=country_name)
            doc.analysis = {
                'summary': analysis_result['response'],
                'tokens_used': analysis_result.get('input_tokens', 0) + analysis_result.get('output_tokens', 0),
            }
            doc.status = 'completed'
        except Exception as e:
            logger.error("Document analysis failed: %s", e)
            doc.analysis = {'summary': 'Analysis pending — please try again.'}
            doc.status = 'completed'
        doc.save()

    stats, _ = UserStats.objects.get_or_create(user=request.user)
    stats.total_documents += 1
    stats.save()

    ser = DocumentSerializer(doc)
    return Response(ser.data, status=status.HTTP_201_CREATED)


@api_view(['GET', 'DELETE'])
@permission_classes([IsAuthenticated])
def document_detail(request, pk):
    try:
        doc = Document.objects.get(pk=pk, user=request.user)
    except Document.DoesNotExist:
        return Response({'error': 'Not found'}, status=status.HTTP_404_NOT_FOUND)

    if request.method == 'DELETE':
        # Also delete from R2
        if doc.file_url:
            try:
                r2 = storage_service.R2Client()
                r2.delete_file(doc.file_url)
            except Exception as e:
                logger.warning("R2 delete failed: %s", e)
        doc.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

    ser = DocumentSerializer(doc)
    return Response(ser.data)


# ──────────────────── VOICE SESSIONS ────────────────────

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def voice_start_session(request):
    # Check voice session limit
    limits = _get_limits(request.user)
    if limits['voice_sessions_per_day'] == 0:
        return Response({
            'error': 'Voice sessions not available on free plan',
            'plan': _get_plan(request.user),
            'upgrade_message': 'Upgrade to Plus or higher for voice sessions.',
        }, status=status.HTTP_403_FORBIDDEN)

    today_sessions = _daily_usage(request.user, VoiceSession)
    if today_sessions >= limits['voice_sessions_per_day']:
        return Response({
            'error': 'Daily voice session limit reached',
            'limit': limits['voice_sessions_per_day'],
            'used': today_sessions,
        }, status=status.HTTP_429_TOO_MANY_REQUESTS)

    country = request.data.get('country', 'KH')[:5]
    conv = Conversation.objects.create(
        user=request.user, country=country, is_voice_session=True,
        title='Voice Session',
    )
    session = VoiceSession.objects.create(
        user=request.user, conversation=conv,
    )

    stats, _ = UserStats.objects.get_or_create(user=request.user)
    stats.total_voice_sessions += 1
    stats.save()

    return Response({
        'session_id': str(session.id),
        'conversation_id': str(conv.id),
    }, status=status.HTTP_201_CREATED)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def voice_end_session(request):
    session_id = request.data.get('session_id')
    duration = request.data.get('duration_seconds', 0)
    transcript = request.data.get('transcript', '')

    if not session_id:
        return Response({'error': 'session_id required'}, status=status.HTTP_400_BAD_REQUEST)

    try:
        session = VoiceSession.objects.get(pk=session_id, user=request.user)
    except (VoiceSession.DoesNotExist, ValueError):
        return Response({'error': 'Session not found'}, status=status.HTTP_404_NOT_FOUND)

    session.duration_seconds = min(int(duration), 7200)
    session.transcript = transcript[:50000]

    if transcript.strip():
        try:
            summary_result = ai_service.chat(
                f"Summarize this legal voice consultation transcript concisely:\n\n{transcript[:10000]}"
            )
            session.summary = summary_result['response']
        except Exception as e:
            logger.error("Voice summary failed: %s", e)
            session.summary = f"Voice session lasted {duration}s."

    session.save()
    ser = VoiceSessionSerializer(session)
    return Response(ser.data)


@api_view(['POST'])
@permission_classes([IsAuthenticated])
@parser_classes([MultiPartParser, FormParser])
def voice_transcribe(request):
    """Transcribe audio using Whisper API."""
    audio_file = request.FILES.get('audio')
    audio_text = request.data.get('text', '')

    if audio_file:
        if audio_file.size > MAX_UPLOAD_SIZE:
            return Response({'error': 'Audio too large (max 50MB)'}, status=status.HTTP_400_BAD_REQUEST)

        content_type = audio_file.content_type or 'audio/mpeg'
        if not content_type.startswith('audio/'):
            return Response({'error': 'Invalid audio file'}, status=status.HTTP_400_BAD_REQUEST)

        try:
            with tempfile.NamedTemporaryFile(delete=False, suffix='.mp3') as tmp:
                for chunk in audio_file.chunks():
                    tmp.write(chunk)
                tmp_path = tmp.name

            transcription = file_converter.extract_text(tmp_path, content_type)
            return Response({'transcription': transcription})
        except Exception as e:
            logger.error("Audio transcription failed: %s", e)
            return Response({'error': 'Transcription failed'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
        finally:
            if 'tmp_path' in locals():
                try:
                    os.unlink(tmp_path)
                except OSError:
                    pass
    elif audio_text:
        return Response({'transcription': audio_text})
    else:
        return Response({'error': 'Provide audio file or text'}, status=status.HTTP_400_BAD_REQUEST)


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def voice_sessions_list(request):
    qs = VoiceSession.objects.filter(user=request.user)
    ser = VoiceSessionSerializer(qs, many=True)
    return Response(ser.data)


# ──────────────────── RIGHTS CARDS ────────────────────

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def rights_cards(request):
    country = request.query_params.get('country', '')
    qs = RightsCard.objects.filter(is_active=True)
    if country:
        qs = qs.filter(country=country)
    ser = RightsCardSerializer(qs, many=True)
    return Response(ser.data)


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def rights_card_detail(request, pk):
    try:
        card = RightsCard.objects.get(pk=pk, is_active=True)
    except RightsCard.DoesNotExist:
        return Response({'error': 'Not found'}, status=status.HTTP_404_NOT_FOUND)
    ser = RightsCardSerializer(card)
    return Response(ser.data)


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def rights_cards_by_category(request, category):
    country = request.query_params.get('country', '')
    qs = RightsCard.objects.filter(category=category, is_active=True)
    if country:
        qs = qs.filter(country=country)
    ser = RightsCardSerializer(qs, many=True)
    return Response(ser.data)


# ──────────────────── GLOSSARY (Hybrid: DB + glossary_data) ────────────────────

@api_view(['GET'])
@permission_classes([AllowAny])
def glossary(request):
    """Get glossary terms. Merges DB terms with built-in glossary_data."""
    area = request.query_params.get('area', '')

    # Built-in glossary from glossary_data.py
    if area:
        builtin = get_glossary_by_area(area)
    else:
        builtin = LEGAL_GLOSSARY

    # DB terms
    qs = GlossaryTerm.objects.all()
    if area:
        qs = qs.filter(area=area)
    db_terms = GlossaryTermSerializer(qs, many=True).data

    # Merge: DB terms first, then built-in (no duplicates)
    db_term_names = {t['term'].lower() for t in db_terms}
    merged = list(db_terms)
    for entry in builtin:
        if entry['term'].lower() not in db_term_names:
            merged.append(entry)

    return Response(merged)


@api_view(['GET'])
@permission_classes([AllowAny])
def glossary_term(request, term):
    """Get a single glossary term. Checks DB first, then built-in."""
    try:
        t = GlossaryTerm.objects.get(term__iexact=term)
        return Response(GlossaryTermSerializer(t).data)
    except GlossaryTerm.DoesNotExist:
        pass

    builtin = get_glossary_term(term)
    if builtin:
        return Response(builtin)

    return Response({'error': 'Term not found'}, status=status.HTTP_404_NOT_FOUND)


@api_view(['GET'])
@permission_classes([AllowAny])
def glossary_search(request):
    """Search glossary. Checks both DB and built-in glossary."""
    q = request.query_params.get('q', '')
    if not q:
        return Response([])

    # DB search
    qs = GlossaryTerm.objects.filter(term__icontains=q)[:20]
    db_results = GlossaryTermSerializer(qs, many=True).data

    # Built-in search
    builtin_results = search_glossary(q, limit=20)

    # Merge
    seen = {r['term'].lower() for r in db_results}
    merged = list(db_results)
    for entry in builtin_results:
        if entry['term'].lower() not in seen:
            merged.append(entry)
            seen.add(entry['term'].lower())

    return Response(merged[:30])


# ──────────────────── BOOKMARKS ────────────────────

@api_view(['GET', 'POST'])
@permission_classes([IsAuthenticated])
def bookmarks(request):
    if request.method == 'GET':
        qs = Bookmark.objects.filter(user=request.user)
        ser = BookmarkSerializer(qs, many=True)
        return Response(ser.data)

    message_id = request.data.get('message')
    note = request.data.get('note', '')[:1000]

    if not message_id:
        return Response({'error': 'message required'}, status=status.HTTP_400_BAD_REQUEST)

    try:
        bm = Bookmark.objects.create(
            user=request.user, message_id=message_id, note=note,
        )
    except IntegrityError:
        return Response({'error': 'Already bookmarked'}, status=status.HTTP_400_BAD_REQUEST)

    ser = BookmarkSerializer(bm)
    return Response(ser.data, status=status.HTTP_201_CREATED)


@api_view(['DELETE'])
@permission_classes([IsAuthenticated])
def bookmark_delete(request, pk):
    try:
        bm = Bookmark.objects.get(pk=pk, user=request.user)
    except Bookmark.DoesNotExist:
        return Response({'error': 'Not found'}, status=status.HTTP_404_NOT_FOUND)
    bm.delete()
    return Response(status=status.HTTP_204_NO_CONTENT)


# ──────────────────── REMINDERS ────────────────────

@api_view(['GET', 'POST'])
@permission_classes([IsAuthenticated])
def reminders(request):
    if request.method == 'GET':
        qs = Reminder.objects.filter(user=request.user, is_completed=False)
        ser = ReminderSerializer(qs, many=True)
        return Response(ser.data)

    ser = ReminderSerializer(data=request.data)
    if ser.is_valid():
        ser.save(user=request.user)
        return Response(ser.data, status=status.HTTP_201_CREATED)
    return Response(ser.errors, status=status.HTTP_400_BAD_REQUEST)


@api_view(['PATCH', 'DELETE'])
@permission_classes([IsAuthenticated])
def reminder_detail(request, pk):
    try:
        rem = Reminder.objects.get(pk=pk, user=request.user)
    except Reminder.DoesNotExist:
        return Response({'error': 'Not found'}, status=status.HTTP_404_NOT_FOUND)

    if request.method == 'DELETE':
        rem.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

    for field in ['title', 'description', 'remind_at', 'reminder_type', 'is_completed']:
        if field in request.data:
            setattr(rem, field, request.data[field])
    rem.save()
    ser = ReminderSerializer(rem)
    return Response(ser.data)


# ──────────────────── FEEDBACK ────────────────────

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def feedback(request, message_id):
    rating = request.data.get('rating', '')
    comment = request.data.get('comment', '')[:1000]

    if rating not in ['helpful', 'not_helpful', 'inaccurate']:
        return Response({'error': 'Invalid rating'}, status=status.HTTP_400_BAD_REQUEST)

    try:
        fb, created = Feedback.objects.update_or_create(
            user=request.user, message_id=message_id,
            defaults={'rating': rating, 'comment': comment},
        )
    except Exception:
        return Response({'error': 'Invalid message'}, status=status.HTTP_400_BAD_REQUEST)

    ser = FeedbackSerializer(fb)
    return Response(ser.data, status=status.HTTP_201_CREATED if created else status.HTTP_200_OK)


# ──────────────────── STATUTE CHECK ────────────────────

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def statute_check(request):
    case_type = request.data.get('case_type', '').strip()[:200]
    incident_date = request.data.get('incident_date', '').strip()[:20]
    country_code = request.data.get('country', 'KH')[:5]

    if not case_type or not incident_date:
        return Response(
            {'error': 'case_type and incident_date required'},
            status=status.HTTP_400_BAD_REQUEST,
        )

    allowed, err = _check_query_limit(request.user)
    if not allowed:
        return err

    country_info = get_country(country_code)
    country_name = country_info['name'] if country_info else country_code

    result = ai_service.check_statute(case_type, incident_date, country=country_name)

    stats, _ = UserStats.objects.get_or_create(user=request.user)
    stats.total_queries += 1
    stats.save()

    return Response({
        'case_type': case_type,
        'incident_date': incident_date,
        'country': country_code,
        'country_name': country_name,
        'analysis': result['response'],
        'disclaimer': 'This is legal information, not legal advice. Consult a licensed attorney.',
    })


# ──────────────────── COST ESTIMATOR ────────────────────

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def cost_estimate(request):
    case_type = request.data.get('case_type', '').strip()[:200]
    country_code = request.data.get('country', 'KH')[:5]
    description = request.data.get('description', '').strip()[:2000]

    if not case_type:
        return Response({'error': 'case_type required'}, status=status.HTTP_400_BAD_REQUEST)

    allowed, err = _check_query_limit(request.user)
    if not allowed:
        return err

    country_info = get_country(country_code)
    country_name = country_info['name'] if country_info else country_code

    result = ai_service.estimate_cost(case_type, description, country=country_name)

    return Response({
        'case_type': case_type,
        'country': country_code,
        'country_name': country_name,
        'estimate': result['response'],
        'disclaimer': 'Estimates are approximate ranges based on general market data, not quotes.',
    })


# ──────────────────── COUNTRIES (155 countries from country_data) ────────────────────

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def countries(request):
    """Get all supported countries or search."""
    q = request.query_params.get('q', '').strip()
    continent = request.query_params.get('continent', '').strip()

    if q:
        results = search_countries(q)
        return Response(results)

    all_countries = get_all_countries()
    if continent:
        all_countries = [c for c in all_countries if c['continent'].lower() == continent.lower()]

    return Response({
        'count': len(all_countries),
        'countries': all_countries,
    })


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def country_detail(request, code):
    """Get details for a specific country including legal topics."""
    country = get_country(code)
    if not country:
        return Response({'error': 'Country not found'}, status=status.HTTP_404_NOT_FOUND)

    # Add legal topics based on legal system type
    topics = LEGAL_TOPICS.get(country.get('legal_system', ''), LEGAL_TOPICS.get('mixed', []))

    return Response({
        **country,
        'topics': topics,
    })


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def country_topics(request, code):
    """Get legal topics for a country (backward compatible)."""
    country = get_country(code)
    if not country:
        return Response({'error': 'Country not found'}, status=status.HTTP_404_NOT_FOUND)

    topics = LEGAL_TOPICS.get(country.get('legal_system', ''), LEGAL_TOPICS.get('mixed', []))

    return Response({
        'code': country['code'],
        'name': country['name'],
        'topics': topics,
    })


# ──────────────────── STATS ────────────────────

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def stats(request):
    s, _ = UserStats.objects.get_or_create(user=request.user)
    ser = UserStatsSerializer(s)
    data = ser.data

    # Add plan info and daily usage
    plan = _get_plan(request.user)
    limits = _get_limits(request.user)
    today = timezone.now().date()

    today_queries = Message.objects.filter(
        conversation__user=request.user,
        role='user',
        created_at__date=today,
    ).count()

    data['plan'] = plan
    data['daily_queries_used'] = today_queries
    data['daily_queries_limit'] = limits['queries_per_day']
    data['daily_docs_used'] = _daily_usage(request.user, Document)
    data['daily_docs_limit'] = limits['docs_per_day']

    return Response(data)


# ──────────────────── TTS (Text-to-Speech) with Voice Tiers ────────────────────

VALID_TTS_VOICES = {'alloy', 'echo', 'fable', 'onyx', 'nova', 'shimmer'}
VALID_TTS_FORMATS = {'mp3', 'opus', 'aac', 'flac'}
TTS_CONTENT_TYPES = {
    'mp3': 'audio/mpeg',
    'opus': 'audio/ogg',
    'aac': 'audio/aac',
    'flac': 'audio/flac',
}


@api_view(['POST'])
@permission_classes([IsAuthenticated])
def voice_tts(request):
    """Convert text to speech using OpenAI TTS API. Voice availability based on plan."""
    text = request.data.get('text', '').strip()
    voice = request.data.get('voice', 'nova').strip().lower()
    speed = request.data.get('speed', 1.0)
    response_format = request.data.get('response_format', 'mp3').strip().lower()

    if not text:
        return Response({'error': 'text is required'}, status=status.HTTP_400_BAD_REQUEST)
    if len(text) > 4096:
        return Response({'error': 'Text too long (max 4096 chars)'}, status=status.HTTP_400_BAD_REQUEST)

    # Check TTS daily limit
    limits = _get_limits(request.user)
    today = timezone.now().date()
    # We'll just count based on a simple counter approach; use stats
    tts_today = getattr(request.user, '_tts_count', 0)  # approximate

    # Check voice tier
    allowed_voices = limits['tts_voices']
    if voice not in allowed_voices:
        return Response({
            'error': f'Voice "{voice}" not available on your plan',
            'allowed_voices': sorted(allowed_voices),
            'plan': _get_plan(request.user),
            'upgrade_message': 'Upgrade for more voices.' if _get_plan(request.user) == 'free' else None,
        }, status=status.HTTP_403_FORBIDDEN)

    if voice not in VALID_TTS_VOICES:
        return Response({'error': f'Invalid voice. Choose from: {", ".join(sorted(VALID_TTS_VOICES))}'}, status=status.HTTP_400_BAD_REQUEST)
    if response_format not in VALID_TTS_FORMATS:
        return Response({'error': f'Invalid format. Choose from: {", ".join(sorted(VALID_TTS_FORMATS))}'}, status=status.HTTP_400_BAD_REQUEST)

    try:
        speed = float(speed)
        speed = max(0.25, min(4.0, speed))
    except (TypeError, ValueError):
        speed = 1.0

    try:
        import openai
        client = openai.OpenAI(api_key=os.getenv('OPENAI_API_KEY'))
        response = client.audio.speech.create(
            model='tts-1',
            voice=voice,
            input=text,
            speed=speed,
            response_format=response_format,
        )
        audio_bytes = response.content
        content_type = TTS_CONTENT_TYPES.get(response_format, 'audio/mpeg')
        return HttpResponse(
            audio_bytes,
            content_type=content_type,
            headers={'Content-Length': str(len(audio_bytes))},
        )
    except Exception as e:
        logger.error("TTS failed: %s", e)
        return Response({'error': 'TTS generation failed'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


# ──────────────────── TTS VOICES LIST ────────────────────

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def voice_tts_voices(request):
    """Get available TTS voices for user's plan."""
    limits = _get_limits(request.user)
    all_voices = [
        {'id': 'alloy', 'name': 'Alloy', 'gender': 'neutral', 'description': 'Warm and balanced'},
        {'id': 'echo', 'name': 'Echo', 'gender': 'male', 'description': 'Clear and confident'},
        {'id': 'fable', 'name': 'Fable', 'gender': 'neutral', 'description': 'Storytelling style'},
        {'id': 'nova', 'name': 'Nova', 'gender': 'female', 'description': 'Friendly and professional'},
        {'id': 'onyx', 'name': 'Onyx', 'gender': 'male', 'description': 'Deep and authoritative'},
        {'id': 'shimmer', 'name': 'Shimmer', 'gender': 'female', 'description': 'Bright and engaging'},
    ]
    allowed = limits['tts_voices']
    for v in all_voices:
        v['available'] = v['id'] in allowed

    return Response({
        'plan': _get_plan(request.user),
        'voices': all_voices,
    })


# ──────────────────── PDF EXPORT ────────────────────

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def export_pdf(request, message_id):
    """Export an AI response as a formatted PDF document."""
    try:
        msg = Message.objects.get(pk=message_id)
    except Message.DoesNotExist:
        return Response({'error': 'Message not found'}, status=status.HTTP_404_NOT_FOUND)

    if msg.conversation.user != request.user:
        return Response({'error': 'Not your message'}, status=status.HTTP_403_FORBIDDEN)

    if msg.role != 'assistant':
        return Response({'error': 'Can only export AI responses'}, status=status.HTTP_400_BAD_REQUEST)

    include_question = request.data.get('include_question', True)
    include_timestamp = request.data.get('include_timestamp', True)
    include_disclaimer = request.data.get('include_disclaimer', True)
    custom_title = request.data.get('title', '').strip()[:200]

    question_text = ''
    if include_question:
        prev_msg = Message.objects.filter(
            conversation=msg.conversation,
            created_at__lt=msg.created_at,
            role='user',
        ).order_by('-created_at').first()
        if prev_msg:
            question_text = prev_msg.content

    try:
        from reportlab.lib.pagesizes import A4
        from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
        from reportlab.lib.units import inch, cm
        from reportlab.lib.colors import HexColor
        from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, HRFlowable

        buffer = io.BytesIO()
        doc = SimpleDocTemplate(
            buffer, pagesize=A4,
            leftMargin=2 * cm, rightMargin=2 * cm,
            topMargin=2 * cm, bottomMargin=2 * cm,
        )

        styles = getSampleStyleSheet()
        navy = HexColor('#0A1628')
        royal_blue = HexColor('#1B4DFF')

        title_style = ParagraphStyle(
            'NTitle', parent=styles['Heading1'],
            textColor=navy, fontSize=18, spaceAfter=12,
        )
        header_style = ParagraphStyle(
            'NHeader', parent=styles['Normal'],
            textColor=royal_blue, fontSize=10, spaceAfter=6,
        )
        body_style = ParagraphStyle(
            'NBody', parent=styles['Normal'],
            fontSize=11, leading=16, spaceAfter=8,
        )
        question_style = ParagraphStyle(
            'NQuestion', parent=styles['Normal'],
            fontSize=11, leading=16, spaceAfter=8,
            textColor=HexColor('#444444'), leftIndent=20,
        )
        disclaimer_style = ParagraphStyle(
            'NDisclaimer', parent=styles['Normal'],
            fontSize=8, textColor=HexColor('#888888'),
            spaceBefore=20,
        )

        elements = []

        elements.append(Paragraph('NOMAZRA — AI Legal Assistant', header_style))
        elements.append(HRFlowable(width='100%', thickness=1, color=royal_blue))
        elements.append(Spacer(1, 12))

        title = custom_title or 'Legal Opinion'
        elements.append(Paragraph(title, title_style))

        if include_timestamp:
            ts = msg.created_at.strftime('%B %d, %Y at %I:%M %p')
            elements.append(Paragraph(f'Generated: {ts}', header_style))
            elements.append(Spacer(1, 12))

        if question_text:
            elements.append(Paragraph('<b>Your Question:</b>', body_style))
            safe_q = question_text.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
            elements.append(Paragraph(safe_q, question_style))
            elements.append(Spacer(1, 8))
            elements.append(HRFlowable(width='100%', thickness=0.5, color=HexColor('#DDDDDD')))
            elements.append(Spacer(1, 8))

        elements.append(Paragraph('<b>Legal Analysis:</b>', body_style))
        safe_content = msg.content.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
        for para in safe_content.split('\n'):
            para = para.strip()
            if para:
                elements.append(Paragraph(para, body_style))

        if include_disclaimer:
            elements.append(Spacer(1, 20))
            elements.append(HRFlowable(width='100%', thickness=0.5, color=HexColor('#DDDDDD')))
            elements.append(Paragraph(
                '<b>Disclaimer:</b> This document was generated by NOMAZRA AI Legal Assistant. '
                'It provides general legal information and does not constitute legal advice. '
                'Please consult a licensed attorney for specific legal matters.',
                disclaimer_style,
            ))

        elements.append(Spacer(1, 12))
        elements.append(Paragraph(
            'Generated by NOMAZRA — Kelthos Technologies',
            ParagraphStyle('Footer', parent=styles['Normal'], fontSize=7, textColor=HexColor('#AAAAAA')),
        ))

        doc.build(elements)
        pdf_bytes = buffer.getvalue()
        buffer.close()

        return_format = request.query_params.get('format', 'binary')
        if return_format == 'json':
            try:
                r2_key = storage_service.upload_bytes(
                    user_id=str(request.user.id),
                    category='documents',
                    data=pdf_bytes,
                    filename=f'nomazra_export_{msg.id}.pdf',
                )
                r2_url = storage_service.get_presigned_url(r2_key)
                return Response({
                    'pdf_url': r2_url,
                    'filename': f'nomazra_legal_opinion_{msg.created_at.strftime("%Y-%m-%d")}.pdf',
                    'size': len(pdf_bytes),
                })
            except Exception as e:
                logger.error("PDF R2 upload failed: %s", e)

        filename = f'nomazra_legal_opinion_{msg.created_at.strftime("%Y-%m-%d")}.pdf'
        response = HttpResponse(pdf_bytes, content_type='application/pdf')
        response['Content-Disposition'] = f'attachment; filename="{filename}"'
        response['Content-Length'] = str(len(pdf_bytes))
        return response

    except ImportError:
        return Response(
            {'error': 'PDF generation not available. Install reportlab.'},
            status=status.HTTP_500_INTERNAL_SERVER_ERROR,
        )
    except Exception as e:
        logger.error("PDF export failed: %s", e)
        return Response({'error': 'PDF generation failed'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)


# ──────────────────── EMERGENCY INFO (140+ countries from country_data) ────────────────────

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def emergency_info(request):
    """Get emergency legal contacts and hotlines for a country."""
    country_code = request.query_params.get('country', 'KH').upper()[:5]

    info = get_emergency_info(country_code)
    if not info:
        return Response(
            {'error': f'No emergency info available for country: {country_code}'},
            status=status.HTTP_404_NOT_FOUND,
        )

    return Response(info)


# ──────────────────── CONTRACT DRAFT ────────────────────

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def contract_draft(request):
    """Draft a simple legal document/contract using AI."""
    contract_type = request.data.get('contract_type', '').strip()[:200]
    details = request.data.get('details', '').strip()
    country_code = request.data.get('country', 'KH')[:5]

    if not contract_type:
        return Response({'error': 'contract_type is required'}, status=status.HTTP_400_BAD_REQUEST)
    if not details:
        return Response({'error': 'details is required'}, status=status.HTTP_400_BAD_REQUEST)
    if len(details) > 5000:
        return Response({'error': 'Details too long (max 5000 chars)'}, status=status.HTTP_400_BAD_REQUEST)

    allowed, err = _check_query_limit(request.user)
    if not allowed:
        return err

    country_info = get_country(country_code)
    country_name = country_info['name'] if country_info else None

    result = ai_service.draft_contract(contract_type, details, country=country_name)

    stats_obj, _ = UserStats.objects.get_or_create(user=request.user)
    stats_obj.total_queries += 1
    stats_obj.save()

    return Response({
        'draft': result['response'],
        'country': country_code,
        'tokens_used': result.get('input_tokens', 0) + result.get('output_tokens', 0),
        'disclaimer': 'This AI-generated draft should be reviewed by a qualified lawyer.',
    })


# ──────────────────── LAW SEARCH ────────────────────

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def law_search(request):
    """Search for applicable laws based on a described situation."""
    description = request.data.get('description', '').strip()
    country_code = request.data.get('country', 'KH')[:5]

    if not description:
        return Response({'error': 'description is required'}, status=status.HTTP_400_BAD_REQUEST)
    if len(description) > 5000:
        return Response({'error': 'Description too long (max 5000 chars)'}, status=status.HTTP_400_BAD_REQUEST)

    allowed, err = _check_query_limit(request.user)
    if not allowed:
        return err

    country_info = get_country(country_code)
    country_name = country_info['name'] if country_info else None

    result = ai_service.search_law(description, country=country_name)

    stats_obj, _ = UserStats.objects.get_or_create(user=request.user)
    stats_obj.total_queries += 1
    stats_obj.save()

    return Response({
        'applicable_laws': result['response'],
        'country': country_code,
        'tokens_used': result.get('input_tokens', 0) + result.get('output_tokens', 0),
        'disclaimer': 'This is AI-generated legal information, not legal advice.',
    })


# ──────────────────── SUBSCRIPTION VERIFICATION ────────────────────

@api_view(['POST'])
@permission_classes([IsAuthenticated])
def subscription_verify(request):
    """Verify a Google Play subscription purchase."""
    purchase_token = request.data.get('purchase_token', '').strip()
    product_id = request.data.get('product_id', '').strip()

    if not purchase_token or not product_id:
        return Response({'error': 'purchase_token and product_id required'}, status=status.HTTP_400_BAD_REQUEST)

    # Map product IDs to plan names
    PRODUCT_TO_PLAN = {
        'nomazra_plus_monthly': 'plus',
        'nomazra_plus_yearly': 'plus',
        'nomazra_premium_monthly': 'premium',
        'nomazra_premium_yearly': 'premium',
        'nomazra_pro_monthly': 'professional',
        'nomazra_pro_yearly': 'professional',
    }

    plan = PRODUCT_TO_PLAN.get(product_id)
    if not plan:
        return Response({'error': 'Invalid product_id'}, status=status.HTTP_400_BAD_REQUEST)

    # TODO: Add Google Play Developer API verification when app is published
    # For now, record the subscription
    user = request.user
    user.subscription_plan = plan
    user.save(update_fields=['subscription_plan'])

    return Response({
        'plan': plan,
        'product_id': product_id,
        'status': 'active',
        'message': f'Subscription activated: NOMAZRA {plan.title()}',
    })


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def subscription_status(request):
    """Get current subscription status and limits."""
    plan = _get_plan(request.user)
    limits = _get_limits(request.user)
    today = timezone.now().date()

    today_queries = Message.objects.filter(
        conversation__user=request.user,
        role='user',
        created_at__date=today,
    ).count()

    return Response({
        'plan': plan,
        'limits': {
            'queries_per_day': limits['queries_per_day'],
            'docs_per_day': limits['docs_per_day'],
            'voice_sessions_per_day': limits['voice_sessions_per_day'],
            'tts_per_day': limits['tts_per_day'],
            'countries': limits['countries'],
            'history_days': limits['history_days'],
        },
        'usage_today': {
            'queries': today_queries,
            'documents': _daily_usage(request.user, Document),
        },
        'available_voices': sorted(limits['tts_voices']),
    })
