"""Notification system API routes — subscriptions, history, settings, stages."""

from __future__ import annotations

import json

from fastapi import APIRouter, Request, HTTPException
from pydantic import BaseModel

from notifications.subscription_manager import SubscriptionManager
from notifications.watch_config import WatchConfig
from notifications.status_stages import StatusStages
from notifications.event_processor import EventProcessor
from notifications.email_sender import EmailSender

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


# --- Request models ---

class SubscriptionCreate(BaseModel):
    email: str
    doc_number: str
    chain_id: str | None = None
    source_system: str | None = None
    doc_type: str | None = None
    notify_on_stages: list[str] | None = None


class SubscriptionUpdate(BaseModel):
    email: str | None = None
    doc_number: str | None = None
    chain_id: str | None = None
    source_system: str | None = None
    doc_type: str | None = None
    notify_on_stages: list[str] | None = None
    is_active: bool | None = None


class WatchColumnConfig(BaseModel):
    table_id: str
    columns: list[dict]  # [{"column_name": str, "is_status_column": bool, "is_key_column": bool, "is_doc_number_column": bool}]


class StageCreate(BaseModel):
    doc_type: str
    source_system: str
    stage_order: int
    stage_key: str
    stage_label: str


class SettingsUpdate(BaseModel):
    key: str
    value: dict


class TestEmailRequest(BaseModel):
    email: str


# --- Subscription endpoints ---

@router.post("/subscriptions")
async def create_subscription(request: Request, body: SubscriptionCreate):
    mgr = SubscriptionManager(request.app.state.db)
    sub = await mgr.create(
        email=body.email,
        doc_number=body.doc_number,
        chain_id=body.chain_id,
        source_system=body.source_system,
        doc_type=body.doc_type,
        notify_on_stages=body.notify_on_stages,
    )

    # Send initial confirmation email with current chain status
    sender = EmailSender(request.app.state.db)
    email_result = await sender.send_subscription_confirmation(
        email=body.email,
        doc_number=body.doc_number,
        source_system=body.source_system,
    )
    sub["confirmation_email"] = email_result

    return sub


@router.get("/subscriptions")
async def list_subscriptions(request: Request, email: str | None = None, doc_number: str | None = None):
    mgr = SubscriptionManager(request.app.state.db)
    subs = await mgr.list_subscriptions(email=email, doc_number=doc_number)
    return {"subscriptions": subs, "count": len(subs)}


@router.get("/subscriptions/{subscription_id}")
async def get_subscription(request: Request, subscription_id: str):
    mgr = SubscriptionManager(request.app.state.db)
    sub = await mgr.get(subscription_id)
    if not sub:
        raise HTTPException(404, "Subscription not found")
    return sub


@router.put("/subscriptions/{subscription_id}")
async def update_subscription(request: Request, subscription_id: str, body: SubscriptionUpdate):
    mgr = SubscriptionManager(request.app.state.db)
    updated = await mgr.update(subscription_id, **body.model_dump(exclude_none=True))
    if not updated:
        raise HTTPException(404, "Subscription not found")
    return updated


@router.delete("/subscriptions/{subscription_id}")
async def delete_subscription(request: Request, subscription_id: str):
    mgr = SubscriptionManager(request.app.state.db)
    await mgr.delete(subscription_id)
    return {"deleted": True}


# --- Notification history ---

@router.get("/history")
async def get_history(request: Request, limit: int = 50, status: str | None = None):
    cm = request.app.state.db
    query = "SELECT * FROM v3q_config.notification_log WHERE 1=1"
    params: dict = {}
    if status:
        query += " AND status = :status"
        params["status"] = status
    query += " ORDER BY created_at DESC LIMIT :limit"
    params["limit"] = limit
    rows = await cm.execute(query, params)
    return {"notifications": [dict(r) for r in rows], "count": len(rows)}


@router.get("/history/{doc_number}")
async def get_history_for_doc(request: Request, doc_number: str):
    cm = request.app.state.db
    rows = await cm.execute(
        "SELECT * FROM v3q_config.notification_log WHERE doc_number = :doc_number ORDER BY created_at DESC",
        {"doc_number": doc_number},
    )
    return {"notifications": [dict(r) for r in rows], "count": len(rows)}


# --- Status stage definitions ---

@router.get("/stages")
async def list_stages(request: Request, doc_type: str | None = None, source_system: str | None = None):
    stages = StatusStages(request.app.state.db)
    result = await stages.list_stages(doc_type=doc_type, source_system=source_system)
    return {"stages": result, "count": len(result)}


@router.post("/stages")
async def create_stage(request: Request, body: StageCreate):
    stages = StatusStages(request.app.state.db)
    return await stages.create(
        doc_type=body.doc_type,
        source_system=body.source_system,
        stage_order=body.stage_order,
        stage_key=body.stage_key,
        stage_label=body.stage_label,
    )


@router.delete("/stages/{stage_id}")
async def delete_stage(request: Request, stage_id: str):
    stages = StatusStages(request.app.state.db)
    await stages.delete(stage_id)
    return {"deleted": True}


# --- Watch columns ---

@router.get("/watch-columns/{table_id}")
async def get_watch_columns(request: Request, table_id: str):
    wc = WatchConfig(request.app.state.db)
    cols = await wc.get_watch_columns(table_id)
    return {"columns": cols, "count": len(cols)}


@router.post("/watch-columns")
async def configure_watch_columns(request: Request, body: WatchColumnConfig):
    wc = WatchConfig(request.app.state.db)
    result = await wc.configure(body.table_id, body.columns)
    return {"columns": result, "count": len(result)}


# --- Notification settings ---

@router.get("/settings")
async def get_settings(request: Request):
    cm = request.app.state.db
    rows = await cm.execute("SELECT * FROM v3q_config.notification_settings ORDER BY key")
    settings = {}
    for r in rows:
        val = r["value"]
        settings[r["key"]] = json.loads(val) if isinstance(val, str) else val
    return settings


@router.put("/settings")
async def update_settings(request: Request, body: SettingsUpdate):
    cm = request.app.state.db
    await cm.execute_write(
        """INSERT INTO v3q_config.notification_settings (key, value, updated_at)
           VALUES (:key, :value, now())
           ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, updated_at = now()""",
        {"key": body.key, "value": json.dumps(body.value)},
    )
    return {"updated": True, "key": body.key}


# --- Test email ---

@router.post("/test-email")
async def send_test_email(request: Request, body: TestEmailRequest):
    sender = EmailSender(request.app.state.db)
    result = await sender.send_test_email(body.email)
    if not result["success"]:
        raise HTTPException(400, result.get("error", "Failed to send test email"))
    return result


# --- Manual processing trigger ---

@router.post("/process")
async def trigger_processing(request: Request):
    cm = request.app.state.db
    sub_mgr = SubscriptionManager(cm)
    processor = EventProcessor(cm, sub_mgr)
    sender = EmailSender(cm)

    queued = await processor.process_pending_events()
    sent = await sender.send_pending_notifications()
    return {"events_processed": queued, "emails_sent": sent}


# --- Debug: recent sync events ---

@router.get("/events")
async def get_recent_events(request: Request, limit: int = 50, table_id: str | None = None):
    cm = request.app.state.db
    query = "SELECT * FROM v3q_data.sync_events WHERE 1=1"
    params: dict = {}
    if table_id:
        query += " AND table_id = :table_id"
        params["table_id"] = table_id
    query += " ORDER BY detected_at DESC LIMIT :limit"
    params["limit"] = limit
    rows = await cm.execute(query, params)
    return {"events": [dict(r) for r in rows], "count": len(rows)}


# --- Chain status lookup for immediate display ---

@router.get("/chain-status/{doc_number}")
async def get_chain_status(request: Request, doc_number: str):
    """Get current chain status for a document — stages + linked docs + recent events."""
    cm = request.app.state.db
    stages_mgr = StatusStages(cm)
    from tracking.document_tracker import DocumentTracker
    tracker = DocumentTracker(cm)

    # Get all stage definitions
    all_stages = await stages_mgr.list_stages()

    # Get recent sync events for this doc
    events = await cm.execute(
        """SELECT * FROM v3q_data.sync_events
           WHERE doc_number = :doc_number
           ORDER BY detected_at DESC LIMIT 20""",
        {"doc_number": doc_number},
    )

    # Get notification history
    history = await cm.execute(
        """SELECT * FROM v3q_config.notification_log
           WHERE doc_number = :doc_number
           ORDER BY created_at DESC LIMIT 20""",
        {"doc_number": doc_number},
    )

    # Try to find linked chain documents via document_tracker
    chain_docs = []
    chain_id = None
    try:
        chain_id = await tracker.get_chain_id_for_doc(doc_number)
        if chain_id:
            chain_data = await tracker.get_chain(chain_id)
            if chain_data and chain_data.get("documents"):
                chain_docs = [dict(d) for d in chain_data["documents"]]
    except Exception:
        pass

    # Determine current stage by matching latest event values against stage_key
    current_stage = None
    if all_stages and events:
        latest_values = set()
        for evt in events:
            if evt.get("new_value"):
                latest_values.add(evt["new_value"])
        for stage in reversed(all_stages):
            if stage["stage_key"] in latest_values:
                current_stage = dict(stage)
                break

    return {
        "doc_number": doc_number,
        "chain_id": chain_id,
        "stages": [dict(s) for s in all_stages],
        "current_stage": current_stage,
        "events": [dict(e) for e in events],
        "history": [dict(h) for h in history],
        "chain_documents": chain_docs,
    }
