"""Gremlin Triage API - 'What should I do with this?'"""

from __future__ import annotations

from typing import Any, Optional

from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession

from ...auth_security import require_account
from ...db import get_session
from ...services.gremlin_ai import GremlinAI
from ...services.sheet_classifier import (
    build_suggested_actions,
    classify_sheet,
)
from .gremlin import get_gremlin_tier, get_sheets_service_from_token

router = APIRouter(prefix="/api/v2/gremlin", tags=["gremlin"])


class TriageRequest(BaseModel):
    spreadsheet_id: str
    sheet_name: Optional[str] = None
    range: Optional[str] = None
    # Client-side data (preferred - avoids Sheets API calls from backend)
    values: Optional[list[list[Any]]] = None
    formulas: Optional[list[list[Any]]] = None
    sheet_titles: Optional[list[str]] = None


class TriageResponse(BaseModel):
    spreadsheet_id: str
    sheet_name: str
    summary: dict[str, Any]
    ai_summary: Optional[str] = None
    suggested_actions: list[dict[str, Any]]


# Server-side payload limits (defense in depth - client also clamps)
MAX_PAYLOAD_ROWS = 2500
MAX_PAYLOAD_COLS = 100


def _has_triage_client_data(request: TriageRequest) -> bool:
    """Check if request contains client-side sheet data."""
    return request.values is not None and len(request.values) > 0


def _validate_triage_payload_size(values: list[list[Any]]) -> None:
    """Reject payloads that exceed size limits."""
    if len(values) > MAX_PAYLOAD_ROWS:
        raise HTTPException(
            status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
            detail=f"Sheet payload too large: {len(values)} rows exceeds limit of {MAX_PAYLOAD_ROWS}"
        )
    if values and len(values[0]) > MAX_PAYLOAD_COLS:
        raise HTTPException(
            status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
            detail=f"Sheet payload too wide: {len(values[0])} columns exceeds limit of {MAX_PAYLOAD_COLS}"
        )


def _normalize_triage_data(request: TriageRequest) -> tuple[list[list[Any]], list[list[Any]] | None, str]:
    """
    Normalize client-side data for triage.
    Returns (values, formulas, sheet_name).
    """
    values = request.values or []
    if not values:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="No sheet data provided in values field"
        )

    # Server-side size validation (defense in depth)
    _validate_triage_payload_size(values)

    # Formulas can be None for triage (used for model detection but optional)
    formulas = request.formulas

    # Sheet name: use provided, or first from titles, or default
    sheet_name = request.sheet_name
    if not sheet_name and request.sheet_titles:
        sheet_name = request.sheet_titles[0]
    if not sheet_name:
        sheet_name = "Sheet1"

    return values, formulas, sheet_name


@router.post("/triage", response_model=TriageResponse)
async def triage_sheet(
    request: TriageRequest,
    account_id: str = Depends(require_account),
    sheets_service=Depends(get_sheets_service_from_token),
    db: AsyncSession = Depends(get_session),
):
    """
    Analyze a sheet and suggest what the user should do next.

    Supports two modes:
    1. Client-side data: values/formulas sent in payload (preferred)
    2. Sheets API: X-Sheets-Token header used to fetch data from Google

    - Classifies sheet type (event leads, accounts, model, etc.)
    - Computes data quality metrics
    - Suggests relevant actions from existing Gremlin flows
    - For paid tiers, includes AI-generated summary
    """
    spreadsheet_id = request.spreadsheet_id
    use_client_data = _has_triage_client_data(request)

    if use_client_data:
        # Client-side data mode - normalize inputs
        values, formulas, sheet_name = _normalize_triage_data(request)
    else:
        # Sheets API mode - requires X-Sheets-Token
        if sheets_service is None:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Either X-Sheets-Token header or values payload is required"
            )

        # Determine sheet name (fallback to first sheet)
        if request.sheet_name:
            sheet_name = request.sheet_name
        else:
            spreadsheet = (
                sheets_service.spreadsheets()
                .get(spreadsheetId=spreadsheet_id, fields="sheets.properties.title")
                .execute()
            )
            sheet_name = spreadsheet.get("sheets", [{}])[0].get("properties", {}).get("title", "")

        if not sheet_name:
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Sheet name could not be resolved")

        # Cap default range to A1:Z2000
        if request.range:
            range_str = request.range
        else:
            range_str = f"'{sheet_name}'!A1:Z2000"

        # Fetch values
        try:
            values_result = (
                sheets_service.spreadsheets()
                .values()
                .get(
                    spreadsheetId=spreadsheet_id,
                    range=range_str,
                    valueRenderOption="UNFORMATTED_VALUE",
                )
                .execute()
            )
            values = values_result.get("values", []) or []
        except Exception as exc:  # pragma: no cover - upstream errors
            raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=f"Failed to read sheet: {exc}") from exc

        # Fetch formulas (optional, for model detection)
        formulas = None
        try:
            formulas_result = (
                sheets_service.spreadsheets()
                .values()
                .get(
                    spreadsheetId=spreadsheet_id,
                    range=range_str,
                    valueRenderOption="FORMULA",
                )
                .execute()
            )
            formulas = formulas_result.get("values", []) or []
        except Exception:
            formulas = None

    # Classify sheet
    classification = classify_sheet(values, formulas)

    # Build suggested actions
    actions = build_suggested_actions(classification)

    # Build summary dict from dataclass
    summary_dict = {
        "row_count": classification.row_count,
        "column_count": classification.column_count,
        "headers": classification.headers,
        "has_formulas": classification.has_formulas,
        "formula_count": classification.formula_count,
        "formula_density": classification.formula_density,
        "has_offset_formulas": classification.has_offset_formulas,
        "has_cross_sheet_refs": classification.has_cross_sheet_refs,
        "cross_sheet_tabs": classification.cross_sheet_tabs,
        "has_sfdc_ids": classification.has_sfdc_ids,
        "sfdc_id_types": classification.sfdc_id_types,
        "sfdc_id_columns": classification.sfdc_id_columns,
        "email_columns": classification.email_columns,
        "domain_columns": classification.domain_columns,
        "company_columns": classification.company_columns,
        "name_columns": classification.name_columns,
        "b2c_email_pct": classification.b2c_email_pct,
        "duplicate_email_pct": classification.duplicate_email_pct,
        "null_counts": classification.null_counts,
        "likely_record_type": classification.likely_record_type,
        "classification_confidence": classification.classification_confidence,
        "likely_use_cases": classification.likely_use_cases,
    }

    # AI summary for paid tiers (best-effort)
    ai_summary: Optional[str] = None
    tier = await get_gremlin_tier(account_id, db)

    if tier in ("pro", "scale", "unleashed"):
        try:
            ai = GremlinAI(tier)
            ai_summary = await ai.generate_triage_summary(classification)
        except Exception:
            ai_summary = None

    return TriageResponse(
        spreadsheet_id=spreadsheet_id,
        sheet_name=sheet_name,
        summary=summary_dict,
        ai_summary=ai_summary,
        suggested_actions=actions,
    )
