"""Category verification for existing models on new mailboxes."""
import logging
import json
import re
import random
from typing import List, Dict, Any

from src.email_providers.base import Email
from src.llm.base import BaseLLMProvider

logger = logging.getLogger(__name__)


def verify_model_categories(
    emails: List[Email],
    model_categories: List[str],
    llm_provider: BaseLLMProvider,
    sample_size: int = 20
) -> Dict[str, Any]:
    """
    Verify if trained model categories fit a new mailbox.

    Single LLM call to check if categories are appropriate.

    Args:
        emails: All emails from new mailbox
        model_categories: Categories the model was trained on
        llm_provider: LLM provider for verification
        sample_size: Number of emails to sample for verification

    Returns:
        {
            'verdict': 'GOOD_MATCH' | 'FAIR_MATCH' | 'POOR_MATCH',
            'confidence': float (0-1),
            'reasoning': str,
            'suggested_categories': List[str] (if poor match),
            'category_mapping': Dict[str, str] (suggested name changes)
        }
    """
    logger.info(f"Verifying model categories against {len(emails)} emails")
    logger.info(f"Model categories ({len(model_categories)}): {', '.join(model_categories)}")

    # Sample random emails
    sample = random.sample(emails, min(sample_size, len(emails)))
    logger.info(f"Sampled {len(sample)} emails for verification")

    # Build email summaries
    email_summaries = []
    for i, email in enumerate(sample[:20]):  # Limit to 20 to avoid token limits
        summary = f"{i+1}. From: {email.sender}\n   Subject: {email.subject}\n   Preview: {email.body_snippet[:80]}..."
        email_summaries.append(summary)

    email_text = "\n\n".join(email_summaries)

    # Build categories list
    categories_text = "\n".join([f"  - {cat}" for cat in model_categories])

    # Build verification prompt
    prompt = f"""<no_think>You are evaluating whether pre-trained email categories fit a new mailbox.

TRAINED MODEL CATEGORIES ({len(model_categories)} categories):
{categories_text}

SAMPLE EMAILS FROM NEW MAILBOX ({len(sample)} total, showing first {len(email_summaries)}):
{email_text}

TASK:
Evaluate if the trained categories are appropriate for this mailbox.

Consider:
1. Do the sample emails naturally fit into the trained categories?
2. Are there obvious email types that don't match any category?
3. Are the category names semantically appropriate?
4. Would a user find these categories helpful for THIS mailbox?

Respond with JSON:
{{
  "verdict": "GOOD_MATCH" | "FAIR_MATCH" | "POOR_MATCH",
  "confidence": 0.0-1.0,
  "reasoning": "brief explanation",
  "fit_percentage": 0-100,
  "suggested_categories": ["cat1", "cat2", ...],  // Only if POOR_MATCH
  "category_mapping": {{"old_name": "better_name", ...}}  // Optional renames
}}

Verdict criteria:
- GOOD_MATCH: 80%+ of emails fit well, categories are appropriate
- FAIR_MATCH: 60-80% fit, some gaps but usable
- POOR_MATCH: <60% fit, significant category mismatch

JSON:
"""

    try:
        logger.info("Calling LLM for category verification...")
        response = llm_provider.complete(
            prompt,
            temperature=0.1,
            max_tokens=1000
        )

        logger.debug(f"LLM verification response: {response[:500]}")

        # Parse response
        result = _parse_verification_response(response)

        logger.info(f"Verification complete: {result['verdict']} ({result['confidence']:.0%})")
        if result.get('reasoning'):
            logger.info(f"Reasoning: {result['reasoning']}")

        return result

    except Exception as e:
        logger.error(f"Verification failed: {e}")
        # Return conservative default
        return {
            'verdict': 'FAIR_MATCH',
            'confidence': 0.5,
            'reasoning': f'Verification failed: {e}',
            'fit_percentage': 50,
            'suggested_categories': [],
            'category_mapping': {}
        }


def _parse_verification_response(response: str) -> Dict[str, Any]:
    """Parse LLM verification response."""
    try:
        # Strip think tags
        cleaned = re.sub(r'<think>.*?</think>', '', response, flags=re.DOTALL)

        # Extract JSON
        json_match = re.search(r'\{.*\}', cleaned, re.DOTALL)
        if json_match:
            # Find complete JSON by counting braces
            brace_count = 0
            for i, char in enumerate(cleaned):
                if char == '{':
                    brace_count += 1
                    if brace_count == 1:
                        start = i
                elif char == '}':
                    brace_count -= 1
                    if brace_count == 0:
                        json_str = cleaned[start:i+1]
                        break

            parsed = json.loads(json_str)

            # Validate and set defaults
            result = {
                'verdict': parsed.get('verdict', 'FAIR_MATCH'),
                'confidence': float(parsed.get('confidence', 0.5)),
                'reasoning': parsed.get('reasoning', ''),
                'fit_percentage': int(parsed.get('fit_percentage', 50)),
                'suggested_categories': parsed.get('suggested_categories', []),
                'category_mapping': parsed.get('category_mapping', {})
            }

            # Validate verdict
            if result['verdict'] not in ['GOOD_MATCH', 'FAIR_MATCH', 'POOR_MATCH']:
                logger.warning(f"Invalid verdict: {result['verdict']}, defaulting to FAIR_MATCH")
                result['verdict'] = 'FAIR_MATCH'

            # Clamp confidence
            result['confidence'] = max(0.0, min(1.0, result['confidence']))

            return result

    except json.JSONDecodeError as e:
        logger.warning(f"JSON parse error: {e}")
    except Exception as e:
        logger.warning(f"Parse error: {e}")

    # Fallback parsing - try to extract verdict from text
    verdict = 'FAIR_MATCH'
    if 'GOOD_MATCH' in response or 'good match' in response.lower():
        verdict = 'GOOD_MATCH'
    elif 'POOR_MATCH' in response or 'poor match' in response.lower():
        verdict = 'POOR_MATCH'

    logger.warning(f"Using fallback parsing, verdict: {verdict}")
    return {
        'verdict': verdict,
        'confidence': 0.5,
        'reasoning': 'Fallback parsing - response format invalid',
        'fit_percentage': 50,
        'suggested_categories': [],
        'category_mapping': {}
    }
