"""Message templates, live preview and the (LLM-free) message generator."""

from __future__ import annotations

from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy import select
from sqlalchemy.orm import Session

from app.database import get_db
from app.models import Campaign, Lead, MessageTemplate, MessageVariant, OutreachTask
from app.models.enums import ActivityType
from app.schemas.base import Message
from app.schemas.template import (
    GenerateMessageRequest,
    GenerateMessageResponse,
    MessageTemplateCreate,
    MessageTemplateRead,
    MessageTemplateUpdate,
    TemplateMetadata,
    TemplatePreviewRequest,
    TemplatePreviewResponse,
)
from app.services import message_service, template_engine
from app.services.activity_service import log_activity

router = APIRouter(prefix="/templates", tags=["templates"])


@router.get("/metadata", response_model=TemplateMetadata)
def template_metadata() -> TemplateMetadata:
    return TemplateMetadata(
        variables=template_engine.TEMPLATE_VARIABLES,
        categories=message_service.TEMPLATE_CATEGORIES,
        industry_phrases=template_engine.INDUSTRY_PHRASES,
    )


@router.get("", response_model=list[MessageTemplateRead])
def list_templates(
    db: Session = Depends(get_db),
    campaign_id: int | None = Query(default=None, alias="campaignId"),
    category: str | None = None,
    include_global: bool = Query(default=True, alias="includeGlobal"),
) -> list[MessageTemplateRead]:
    query = select(MessageTemplate)
    if campaign_id is not None:
        query = (
            query.where(
                (MessageTemplate.campaign_id == campaign_id)
                | (MessageTemplate.campaign_id.is_(None))
            )
            if include_global
            else query.where(MessageTemplate.campaign_id == campaign_id)
        )
    if category:
        query = query.where(MessageTemplate.category == category)
    query = query.order_by(MessageTemplate.category, MessageTemplate.priority, MessageTemplate.id)
    return [MessageTemplateRead.model_validate(item) for item in db.scalars(query).all()]


@router.post("", response_model=MessageTemplateRead, status_code=status.HTTP_201_CREATED)
def create_template(
    payload: MessageTemplateCreate, db: Session = Depends(get_db)
) -> MessageTemplateRead:
    try:
        template_engine.parse_blocks(payload.body)
    except template_engine.TemplateError as exc:
        raise HTTPException(status_code=422, detail=f"Invalid template: {exc}") from exc

    data = payload.model_dump(exclude={"variants"})
    template = MessageTemplate(**data)
    for variant in payload.variants:
        template.variants.append(MessageVariant(**variant.model_dump()))
    db.add(template)
    db.commit()
    db.refresh(template)
    return MessageTemplateRead.model_validate(template)


@router.post("/preview", response_model=TemplatePreviewResponse)
def preview_template(
    payload: TemplatePreviewRequest, db: Session = Depends(get_db)
) -> TemplatePreviewResponse:
    lead = db.get(Lead, payload.lead_id) if payload.lead_id else None
    campaign = db.get(Campaign, payload.campaign_id) if payload.campaign_id else None
    try:
        preview = message_service.preview_template(db, payload.body, lead, campaign)
    except template_engine.TemplateError as exc:
        return TemplatePreviewResponse(preview="", length=0, error=str(exc))
    return TemplatePreviewResponse(preview=preview, length=len(preview))


@router.post("/generate-message", response_model=GenerateMessageResponse)
def generate_message(
    payload: GenerateMessageRequest, db: Session = Depends(get_db)
) -> GenerateMessageResponse:
    """Build a message from templates + rules. No LLM is involved at any point."""
    task: OutreachTask | None = None
    lead: Lead | None = None
    campaign: Campaign | None = None

    if payload.task_id is not None:
        task = db.get(OutreachTask, payload.task_id)
        if task is None:
            raise HTTPException(status_code=404, detail=f"Task {payload.task_id} not found")
        lead = task.lead
        campaign = task.campaign

    if payload.lead_id is not None:
        lead = db.get(Lead, payload.lead_id)
        if lead is None:
            raise HTTPException(status_code=404, detail=f"Lead {payload.lead_id} not found")

    if payload.campaign_id is not None:
        campaign = db.get(Campaign, payload.campaign_id)
        if campaign is None:
            raise HTTPException(status_code=404, detail=f"Campaign {payload.campaign_id} not found")

    transient = False
    if lead is None:
        if not payload.lead:
            raise HTTPException(status_code=422, detail="Provide leadId, taskId or lead")
        from app.services.lead_service import normalize_row

        fields = normalize_row(payload.lead)
        fields.setdefault("full_name", "Unknown prospect")
        lead = Lead(**fields)
        transient = True

    campaign = campaign or (None if transient else lead.campaign)
    task_type = task.task_type if task is not None else payload.task_type

    generated = message_service.generate_message(
        db, lead, campaign, task_type=task_type, template_id=payload.template_id
    )

    if payload.save_to_task and task is not None:
        task.suggested_message = generated.message
        task.template_id = generated.template_id
        log_activity(
            db,
            ActivityType.MESSAGE_GENERATED,
            lead=lead,
            task=task,
            description=f"Regenerated message using '{generated.template_name}'",
        )
        db.commit()

    return GenerateMessageResponse.model_validate(generated.as_dict())


@router.get("/{template_id}", response_model=MessageTemplateRead)
def get_template(template_id: int, db: Session = Depends(get_db)) -> MessageTemplateRead:
    template = db.get(MessageTemplate, template_id)
    if template is None:
        raise HTTPException(status_code=404, detail=f"Template {template_id} not found")
    return MessageTemplateRead.model_validate(template)


@router.put("/{template_id}", response_model=MessageTemplateRead)
def update_template(
    template_id: int, payload: MessageTemplateUpdate, db: Session = Depends(get_db)
) -> MessageTemplateRead:
    template = db.get(MessageTemplate, template_id)
    if template is None:
        raise HTTPException(status_code=404, detail=f"Template {template_id} not found")

    data = payload.model_dump(exclude_unset=True, exclude={"variants"})
    if "body" in data and data["body"]:
        try:
            template_engine.parse_blocks(data["body"])
        except template_engine.TemplateError as exc:
            raise HTTPException(status_code=422, detail=f"Invalid template: {exc}") from exc

    for key, value in data.items():
        setattr(template, key, value)

    if payload.variants is not None:
        template.variants.clear()
        db.flush()
        for variant in payload.variants:
            template.variants.append(MessageVariant(**variant.model_dump()))

    db.commit()
    db.refresh(template)
    return MessageTemplateRead.model_validate(template)


@router.delete("/{template_id}", response_model=Message)
def delete_template(template_id: int, db: Session = Depends(get_db)) -> Message:
    template = db.get(MessageTemplate, template_id)
    if template is None:
        raise HTTPException(status_code=404, detail=f"Template {template_id} not found")
    name = template.name
    db.delete(template)
    db.commit()
    return Message(detail=f"Deleted template '{name}'")
