"""
ABOS AI Worker – Email Analyser Bot Router
==========================================
Processes email text, generates responses using dynamically fetched tenant keys,
and saves them to email provider drafts. Connected directly to the React frontend.
"""

from __future__ import annotations

import logging
from typing import Any, Dict

import httpx
from fastapi import APIRouter, HTTPException, status

from app.config import settings
from app.schemas import EmailAnalyzeRequest, EmailAnalyzeResponse

logger = logging.getLogger(__name__)

email_router = APIRouter()

# ---------------------------------------------------------------------------
# Helper function: Fetch Credentials from Spring Boot
# ---------------------------------------------------------------------------
async def fetch_tenant_credentials(tenant_id: str, auth_token: str) -> Dict[str, Any]:
    """
    Fetches AI and email credentials dynamically from Spring Boot database.

    This keeps the worker completely stateless.

    Raises HTTPException(502) if Spring Boot cannot be reached or returns a
    non-200 response — this service has no "mock-openai-key"/"mock-email-token"
    fallback of its own (there's no DEBUG/USE_MOCKS flag in app/config.py to
    gate one behind), so a failure here must be surfaced to the caller rather
    than silently answered with fake credentials that would make every
    downstream step (LLM call, draft save) look like it succeeded when it
    didn't.
    """
    # In a real environment, this URL would point to the Core Spring Boot ERP service.
    # We resolve it from dynamic config or use a relative path if Spring Boot acts as gateway.
    spring_boot_base = "http://localhost:8080" # Fallback/default URL
    settings_url = f"{spring_boot_base}/api/finance/tenant-settings/credentials"

    headers = {
        "Authorization": f"Bearer {auth_token}",
        "X-Tenant-ID": tenant_id,
        "Content-Type": "application/json"
    }

    logger.info("Fetching credentials for tenant=%s from Spring Boot...", tenant_id)

    try:
        async with httpx.AsyncClient(timeout=10) as client:
            response = await client.get(settings_url, headers=headers)
    except Exception as exc:
        logger.error("Could not reach Spring Boot tenant-settings endpoint: %s", exc)
        raise HTTPException(
            status_code=status.HTTP_502_BAD_GATEWAY,
            detail=f"Could not reach Spring Boot to fetch tenant credentials: {exc}",
        ) from exc

    if response.status_code != 200:
        logger.error(
            "Spring Boot returned status %d fetching credentials for tenant=%s.",
            response.status_code, tenant_id,
        )
        raise HTTPException(
            status_code=status.HTTP_502_BAD_GATEWAY,
            detail=(
                f"Spring Boot returned HTTP {response.status_code} fetching tenant "
                "credentials — cannot generate a real email reply without them."
            ),
        )

    return response.json()

# ---------------------------------------------------------------------------
# Helper function: Generate Email Reply with LLM
# ---------------------------------------------------------------------------
async def generate_email_reply(
    body: str, 
    subject: str, 
    tone: str, 
    openai_key: str, 
    google_key: str
) -> str:
    """
    Generates a reply draft text based on the incoming email details.
    Uses OpenRouter or configured OpenAI/Gemini endpoints.

    Raises HTTPException(502) if no usable key was supplied or the LLM call
    fails/errors, instead of silently substituting a canned dummy reply — a
    fake reply that looks plausible is worse than an explicit failure, since
    nothing downstream (the draft save, the caller) can tell it wasn't
    actually generated by the model.
    """
    # Build the prompt
    prompt = (
        f"You are a professional business email assistant. Write a reply to this email.\n"
        f"Subject: {subject}\n"
        f"Desired Reply Tone: {tone}\n"
        f"Incoming Email Body:\n{body}\n\n"
        f"Respond with ONLY the email body reply. No subject line, no extra prose."
    )

    # We can utilize our existing openrouter setup as the engine.
    key_to_use = openai_key or google_key
    if not key_to_use:
        raise HTTPException(
            status_code=status.HTTP_502_BAD_GATEWAY,
            detail="No OpenAI/Google API key was supplied for this tenant — cannot generate an email reply.",
        )

    headers = {
        "Authorization": f"Bearer {key_to_use}",
        "Content-Type": "application/json"
    }

    payload = {
        "model": "google/gemini-2.0-flash-exp:free",
        "messages": [
            {"role": "user", "content": prompt}
        ],
        "temperature": 0.7
    }

    try:
        async with httpx.AsyncClient(timeout=30) as client:
            response = await client.post("https://openrouter.ai/api/v1/chat/completions", headers=headers, json=payload)
    except Exception as exc:
        logger.error("LLM call failed in Email Analyser: %s", exc)
        raise HTTPException(
            status_code=status.HTTP_502_BAD_GATEWAY,
            detail=f"LLM call failed while generating email reply: {exc}",
        ) from exc

    if response.status_code != 200:
        raise HTTPException(
            status_code=status.HTTP_502_BAD_GATEWAY,
            detail=f"LLM provider returned HTTP {response.status_code} while generating email reply.",
        )

    res_data = response.json()
    return res_data["choices"][0]["message"]["content"].strip()

# ---------------------------------------------------------------------------
# Helper function: Save to Provider Drafts
# ---------------------------------------------------------------------------
async def save_to_drafts(
    provider: str, 
    access_token: str, 
    to_email: str, 
    subject: str, 
    body: str
) -> str:
    """
    Interacts with Gmail API or Microsoft Graph to create a real draft.

    Raises HTTPException on any failure (unreachable provider, non-2xx
    response, or an unsupported/unimplemented provider) instead of returning
    a mock draft id — a caller getting back "gmail-mock-draft-id" or
    "abos-local-draft-uuid" has no way to tell the draft was never actually
    saved anywhere.
    """
    logger.info("Saving draft reply to %s provider...", provider)

    # Microsoft Graph API draft creation
    if provider.lower() == "msgraph":
        url = "https://graph.microsoft.com/v1.0/me/messages"
        headers = {
            "Authorization": f"Bearer {access_token}",
            "Content-Type": "application/json"
        }
        draft_payload = {
            "subject": f"RE: {subject}",
            "importance": "normal",
            "body": {
                "contentType": "HTML",
                "content": body.replace("\n", "<br/>")
            },
            "toRecipients": [
                {
                    "emailAddress": {
                        "address": to_email
                    }
                }
            ]
        }
        try:
            async with httpx.AsyncClient(timeout=10) as client:
                res = await client.post(url, headers=headers, json=draft_payload)
        except Exception as exc:
            logger.error("Microsoft Graph draft creation failed: %s", exc)
            raise HTTPException(
                status_code=status.HTTP_502_BAD_GATEWAY,
                detail=f"Microsoft Graph draft creation failed: {exc}",
            ) from exc

        if res.status_code not in (200, 201):
            raise HTTPException(
                status_code=status.HTTP_502_BAD_GATEWAY,
                detail=f"Microsoft Graph returned HTTP {res.status_code} creating the draft.",
            )
        draft_id = res.json().get("id")
        if not draft_id:
            raise HTTPException(
                status_code=status.HTTP_502_BAD_GATEWAY,
                detail="Microsoft Graph did not return a draft id.",
            )
        return draft_id

    # Gmail API draft creation is not implemented yet — fail closed rather
    # than pretending a draft was saved.
    if provider.lower() == "gmail":
        raise HTTPException(
            status_code=status.HTTP_501_NOT_IMPLEMENTED,
            detail="Gmail draft creation is not implemented yet.",
        )

    raise HTTPException(
        status_code=status.HTTP_400_BAD_REQUEST,
        detail=f"Unsupported email provider for draft creation: {provider!r}",
    )

# ---------------------------------------------------------------------------
# Main Entry Point
# ---------------------------------------------------------------------------
@email_router.post(
    "/email/analyze",
    response_model=EmailAnalyzeResponse,
    status_code=status.HTTP_200_OK,
    summary="Analyze incoming email and save reply to draft",
    description=(
        "Processes the email body, contacts Spring Boot using the passed token to "
        "retrieve credentials, generates the reply draft using AI, and saves it "
        "to the tenant's draft box."
    ),
    tags=["Email-Analyzer"],
)
async def analyze_and_draft_email(request: EmailAnalyzeRequest) -> EmailAnalyzeResponse:
    """Read the email, create an automated response, and save it to provider drafts."""
    try:
        # 1. Fetch settings from Spring Boot database
        credentials = await fetch_tenant_credentials(
            tenant_id=request.tenant_id, 
            auth_token=request.spring_boot_auth_token
        )
        
        openai_key = credentials.get("openai_api_key", "")
        google_key = credentials.get("google_api_key", "")
        provider = credentials.get("email_provider", "LocalMock")
        email_token = credentials.get("email_access_token", "")
        
        # 2. Analyze the email body and generate the reply
        reply_subject = f"RE: {request.subject}"
        reply_body = await generate_email_reply(
            body=request.body,
            subject=request.subject,
            tone=request.reply_tone or "professional",
            openai_key=openai_key,
            google_key=google_key
        )
        
        # 3. Save to drafts using provider credentials
        draft_id = await save_to_drafts(
            provider=provider,
            access_token=email_token,
            to_email=request.sender,
            subject=request.subject,
            body=reply_body
        )
        
        return EmailAnalyzeResponse(
            status="DRAFT_CREATED",
            original_subject=request.subject,
            generated_reply_subject=reply_subject,
            generated_reply_body=reply_body,
            draft_id=draft_id
        )

    except HTTPException:
        # Already a clean, correctly-status-coded error (e.g. 502 from a failed
        # Spring Boot/LLM/provider call, 501 for an unimplemented provider) —
        # let it propagate as-is instead of masking it as a generic 500.
        raise
    except Exception as exc:
        logger.exception("Failed to analyze email and create draft: %s", exc)
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Email analysis and draft generation failed: {exc}"
        )
