"""Task template backend API (MVP)."""

from datetime import date, datetime, timedelta
from typing import Any, Dict, List, Optional, Tuple
import logging

from fastapi import APIRouter, Depends, HTTPException, Query

from app.core.auth_dependencies import require_permission
from app.core.database import execute_query, execute_query_single
from app.modules.task_templates.backend.models import (
    TaskTemplate,
    TaskTemplateCreate,
    TaskTemplateItem,
    TaskTemplateItemCreate,
    TaskTemplateItemUpdate,
    TaskTemplateUpdate,
    TemplatePreviewRequest,
    TemplateRunRequest,
)

router = APIRouter()
logger = logging.getLogger(__name__)


def _validate_company_template_payload(template_type: str, customer_id: Optional[int]) -> None:
    if template_type == "company" and not customer_id:
        raise HTTPException(status_code=400, detail="customer_id is required for company templates")

    if template_type in ("global", "internal", "deactivated") and customer_id is not None:
        raise HTTPException(
            status_code=400,
            detail="customer_id must be null unless template_type is 'company'",
        )


def _fetch_case(case_id: int) -> Dict[str, Any]:
    case_row = execute_query_single(
        """
        SELECT id, titel, customer_id, ansvarlig_bruger_id
        FROM sag_sager
        WHERE id = %s AND deleted_at IS NULL
        """,
        (case_id,),
    )
    if not case_row:
        raise HTTPException(status_code=404, detail="Case not found")
    return case_row


def _fetch_template_for_case(template_id: int, case_customer_id: Optional[int]) -> Dict[str, Any]:
    template = execute_query_single(
        """
        SELECT t.*
        FROM task_templates t
        WHERE t.id = %s
          AND t.deleted_at IS NULL
          AND t.is_active = TRUE
          AND t.template_type != 'deactivated'
          AND (
              t.template_type IN ('global', 'internal')
              OR (t.template_type = 'company' AND t.customer_id = %s)
          )
        """,
        (template_id, case_customer_id),
    )
    if not template:
        raise HTTPException(status_code=404, detail="Template not available for this case")
    return template


def _fetch_template_items(template_id: int) -> List[Dict[str, Any]]:
    return execute_query(
        """
        SELECT *
        FROM task_template_items
        WHERE template_id = %s
          AND is_active = TRUE
        ORDER BY sort_order ASC, id ASC
        """,
        (template_id,),
    ) or []


def _resolve_assignee(
    item: Dict[str, Any],
    assignee_mode: str,
    assignee_user_id: Optional[int],
    assignee_role_id: Optional[int],
) -> Tuple[Optional[int], Optional[int]]:
    if assignee_mode == "specific_user":
        return assignee_user_id, None
    if assignee_mode == "specific_role":
        return None, assignee_role_id
    return item.get("default_assignee_user_id"), item.get("default_assignee_role_id")


def _build_preview(
    items: List[Dict[str, Any]],
    start_date: date,
    mode: str,
    assignee_mode: str,
    assignee_user_id: Optional[int],
    assignee_role_id: Optional[int],
) -> Dict[str, Any]:
    preview_items: List[Dict[str, Any]] = []
    summary = {
        "subcases": 0,
        "tasks": 0,
        "assignments": 0,
        "deadlines": 0,
    }

    for item in items:
        item_type = item.get("item_type")
        if mode == "tasks" and item_type != "task":
            continue
        if mode == "subcases" and item_type != "subcase":
            continue

        days_offset = int(item.get("days_offset") or 0)
        due_date = start_date + timedelta(days=days_offset)
        assigned_user_id, assigned_role_id = _resolve_assignee(
            item,
            assignee_mode,
            assignee_user_id,
            assignee_role_id,
        )

        preview_items.append(
            {
                "template_item_id": item.get("id"),
                "title": item.get("title"),
                "description": item.get("description"),
                "item_type": item_type,
                "sort_order": item.get("sort_order") or 0,
                "days_offset": days_offset,
                "planned_due_date": due_date.isoformat(),
                "is_required": bool(item.get("is_required")),
                "assigned_user_id": assigned_user_id,
                "assigned_role_id": assigned_role_id,
            }
        )

        if item_type == "subcase":
            summary["subcases"] += 1
        else:
            summary["tasks"] += 1

        if assigned_user_id or assigned_role_id:
            summary["assignments"] += 1

        summary["deadlines"] += 1

    return {"items": preview_items, "summary": summary}


@router.get("/task-templates", response_model=List[TaskTemplate])
async def list_task_templates(
    company_id: Optional[int] = Query(None),
    category: Optional[str] = Query(None),
    source: str = Query("all", description="all|company|global|internal"),
    current_user: dict = Depends(require_permission("templates.view")),
):
    del current_user

    where_parts = ["t.deleted_at IS NULL", "t.is_active = TRUE", "t.template_type != 'deactivated'"]
    params: List[Any] = []

    if category:
        where_parts.append("t.category = %s")
        params.append(category)

    if source == "company":
        where_parts.append("t.template_type = 'company'")
    elif source == "global":
        where_parts.append("t.template_type = 'global'")
    elif source == "internal":
        where_parts.append("t.template_type = 'internal'")
    elif source != "all":
        raise HTTPException(status_code=400, detail="Invalid source. Use all|company|global|internal")

    if company_id is not None:
        where_parts.append(
            "(t.template_type IN ('global', 'internal') OR (t.template_type = 'company' AND t.customer_id = %s))"
        )
        params.append(company_id)

    where_clause = " AND ".join(where_parts)
    query = f"""
        SELECT t.id, t.name, t.description, t.template_type, t.customer_id,
               t.category, t.is_active, t.created_by, t.created_at, t.updated_at
        FROM task_templates t
        WHERE {where_clause}
        ORDER BY
            CASE
                WHEN %s IS NOT NULL AND t.template_type = 'company' AND t.customer_id = %s THEN 0
                WHEN t.template_type = 'company' THEN 1
                WHEN t.template_type = 'global' THEN 2
                ELSE 3
            END,
            t.name ASC
    """
    params.extend([company_id, company_id])

    rows = execute_query(query, tuple(params)) or []
    return [TaskTemplate(**row) for row in rows]


@router.post("/task-templates", response_model=TaskTemplate)
async def create_task_template(
    payload: TaskTemplateCreate,
    current_user: dict = Depends(require_permission("templates.create")),
):
    _validate_company_template_payload(payload.template_type, payload.customer_id)

    created = execute_query_single(
        """
        INSERT INTO task_templates (name, description, template_type, customer_id, category, is_active, created_by)
        VALUES (%s, %s, %s, %s, %s, %s, %s)
        RETURNING id, name, description, template_type, customer_id, category, is_active, created_by, created_at, updated_at
        """,
        (
            payload.name.strip(),
            payload.description,
            payload.template_type,
            payload.customer_id,
            payload.category,
            payload.is_active,
            current_user.get("id"),
        ),
    )
    if not created:
        raise HTTPException(status_code=500, detail="Failed to create task template")
    return TaskTemplate(**created)


@router.patch("/task-templates/{template_id}", response_model=TaskTemplate)
async def update_task_template(
    template_id: int,
    payload: TaskTemplateUpdate,
    current_user: dict = Depends(require_permission("templates.edit")),
):
    del current_user

    current = execute_query_single(
        "SELECT * FROM task_templates WHERE id = %s AND deleted_at IS NULL",
        (template_id,),
    )
    if not current:
        raise HTTPException(status_code=404, detail="Template not found")

    new_template_type = payload.template_type or current.get("template_type")
    if new_template_type in ("global", "internal", "deactivated"):
        new_customer_id = None
    elif payload.customer_id is not None:
        new_customer_id = payload.customer_id
    else:
        new_customer_id = current.get("customer_id")
    _validate_company_template_payload(new_template_type, new_customer_id)

    updates = []
    params: List[Any] = []

    if payload.name is not None:
        updates.append("name = %s")
        params.append(payload.name.strip())
    if payload.description is not None:
        updates.append("description = %s")
        params.append(payload.description)
    if payload.template_type is not None:
        updates.append("template_type = %s")
        params.append(payload.template_type)
    if payload.customer_id is not None or payload.template_type in ("global", "internal", "deactivated"):
        updates.append("customer_id = %s")
        params.append(new_customer_id)
    if payload.category is not None:
        updates.append("category = %s")
        params.append(payload.category)
    if payload.is_active is not None:
        updates.append("is_active = %s")
        params.append(payload.is_active)

    if not updates:
        raise HTTPException(status_code=400, detail="No fields to update")

    updates.append("updated_at = NOW()")
    params.append(template_id)

    updated = execute_query_single(
        f"""
        UPDATE task_templates
        SET {', '.join(updates)}
        WHERE id = %s AND deleted_at IS NULL
        RETURNING id, name, description, template_type, customer_id, category, is_active, created_by, created_at, updated_at
        """,
        tuple(params),
    )
    if not updated:
        raise HTTPException(status_code=404, detail="Template not found")
    return TaskTemplate(**updated)


@router.delete("/task-templates/{template_id}")
async def deactivate_task_template(
    template_id: int,
    current_user: dict = Depends(require_permission("templates.delete")),
):
    del current_user

    row = execute_query_single(
        """
        UPDATE task_templates
        SET is_active = FALSE,
            template_type = 'deactivated',
            customer_id = NULL,
            updated_at = NOW()
        WHERE id = %s AND deleted_at IS NULL
        RETURNING id
        """,
        (template_id,),
    )
    if not row:
        raise HTTPException(status_code=404, detail="Template not found")

    return {"status": "deactivated", "template_id": template_id}


@router.get("/task-templates/{template_id}/items", response_model=List[TaskTemplateItem])
async def list_task_template_items(
    template_id: int,
    current_user: dict = Depends(require_permission("templates.view")),
):
    del current_user

    rows = _fetch_template_items(template_id)
    return [TaskTemplateItem(**row) for row in rows]


@router.post("/task-templates/{template_id}/items", response_model=TaskTemplateItem)
async def create_task_template_item(
    template_id: int,
    payload: TaskTemplateItemCreate,
    current_user: dict = Depends(require_permission("templates.edit")),
):
    del current_user

    template_exists = execute_query_single(
        "SELECT id FROM task_templates WHERE id = %s AND deleted_at IS NULL",
        (template_id,),
    )
    if not template_exists:
        raise HTTPException(status_code=404, detail="Template not found")

    created = execute_query_single(
        """
        INSERT INTO task_template_items (
            template_id, title, description, item_type, default_assignee_user_id,
            default_assignee_role_id, days_offset, sort_order, is_required, is_active
        )
        VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
        RETURNING id, template_id, title, description, item_type, default_assignee_user_id,
                  default_assignee_role_id, days_offset, sort_order, is_required, is_active,
                  created_at, updated_at
        """,
        (
            template_id,
            payload.title.strip(),
            payload.description,
            payload.item_type,
            payload.default_assignee_user_id,
            payload.default_assignee_role_id,
            payload.days_offset,
            payload.sort_order,
            payload.is_required,
            payload.is_active,
        ),
    )
    if not created:
        raise HTTPException(status_code=500, detail="Failed to create template item")

    return TaskTemplateItem(**created)


@router.patch("/task-template-items/{item_id}", response_model=TaskTemplateItem)
async def update_task_template_item(
    item_id: int,
    payload: TaskTemplateItemUpdate,
    current_user: dict = Depends(require_permission("templates.edit")),
):
    del current_user

    updates = []
    params: List[Any] = []

    if payload.title is not None:
        updates.append("title = %s")
        params.append(payload.title.strip())
    if payload.description is not None:
        updates.append("description = %s")
        params.append(payload.description)
    if payload.item_type is not None:
        updates.append("item_type = %s")
        params.append(payload.item_type)
    if payload.default_assignee_user_id is not None:
        updates.append("default_assignee_user_id = %s")
        params.append(payload.default_assignee_user_id)
    if payload.default_assignee_role_id is not None:
        updates.append("default_assignee_role_id = %s")
        params.append(payload.default_assignee_role_id)
    if payload.days_offset is not None:
        updates.append("days_offset = %s")
        params.append(payload.days_offset)
    if payload.sort_order is not None:
        updates.append("sort_order = %s")
        params.append(payload.sort_order)
    if payload.is_required is not None:
        updates.append("is_required = %s")
        params.append(payload.is_required)
    if payload.is_active is not None:
        updates.append("is_active = %s")
        params.append(payload.is_active)

    if not updates:
        raise HTTPException(status_code=400, detail="No fields to update")

    updates.append("updated_at = NOW()")
    params.append(item_id)

    row = execute_query_single(
        f"""
        UPDATE task_template_items
        SET {', '.join(updates)}
        WHERE id = %s
        RETURNING id, template_id, title, description, item_type, default_assignee_user_id,
                  default_assignee_role_id, days_offset, sort_order, is_required, is_active,
                  created_at, updated_at
        """,
        tuple(params),
    )
    if not row:
        raise HTTPException(status_code=404, detail="Template item not found")

    return TaskTemplateItem(**row)


@router.post("/cases/{case_id}/template-preview")
async def preview_template_for_case(
    case_id: int,
    payload: TemplatePreviewRequest,
    current_user: dict = Depends(require_permission("templates.view")),
):
    del current_user

    case_row = _fetch_case(case_id)
    template = _fetch_template_for_case(payload.template_id, case_row.get("customer_id"))

    start_date = payload.start_date or date.today()
    items = _fetch_template_items(payload.template_id)
    preview = _build_preview(
        items,
        start_date,
        payload.mode,
        payload.assignee_mode,
        payload.assignee_user_id,
        payload.assignee_role_id,
    )

    return {
        "case_id": case_id,
        "template": {
            "id": template.get("id"),
            "name": template.get("name"),
            "template_type": template.get("template_type"),
            "category": template.get("category"),
        },
        "mode": payload.mode,
        "assignee_mode": payload.assignee_mode,
        "start_date": start_date.isoformat(),
        "summary": preview["summary"],
        "items": preview["items"],
    }


@router.post("/cases/{case_id}/run-template")
async def run_template_for_case(
    case_id: int,
    payload: TemplateRunRequest,
    current_user: dict = Depends(require_permission("templates.run")),
):
    case_row = _fetch_case(case_id)
    template = _fetch_template_for_case(payload.template_id, case_row.get("customer_id"))

    start_date = payload.start_date or date.today()
    items = _fetch_template_items(payload.template_id)
    preview = _build_preview(
        items,
        start_date,
        payload.mode,
        payload.assignee_mode,
        payload.assignee_user_id,
        payload.assignee_role_id,
    )

    run_row = execute_query_single(
        """
        INSERT INTO case_template_runs (case_id, template_id, started_by, started_at, status)
        VALUES (%s, %s, %s, NOW(), 'running')
        RETURNING id
        """,
        (case_id, payload.template_id, current_user.get("id")),
    )
    if not run_row:
        raise HTTPException(status_code=500, detail="Failed to start template run")

    run_id = run_row.get("id")
    created_task_ids: List[int] = []
    created_case_ids: List[int] = []

    try:
        for item in preview["items"]:
            created_task_id = None
            created_case_id = None

            if item["item_type"] == "task":
                task_row = execute_query_single(
                    """
                    INSERT INTO sag_todo_steps (sag_id, title, description, due_date, created_by_user_id)
                    VALUES (%s, %s, %s, %s, %s)
                    RETURNING id
                    """,
                    (
                        case_id,
                        item["title"],
                        item.get("description"),
                        item.get("planned_due_date"),
                        current_user.get("id"),
                    ),
                )
                created_task_id = task_row.get("id") if task_row else None
                if created_task_id:
                    created_task_ids.append(created_task_id)

            elif item["item_type"] == "subcase":
                subcase_row = execute_query_single(
                    """
                    INSERT INTO sag_sager (
                        titel,
                        beskrivelse,
                        template_key,
                        status,
                        customer_id,
                        ansvarlig_bruger_id,
                        created_by_user_id,
                        deadline
                    )
                    VALUES (%s, %s, %s, 'åben', %s, %s, %s, %s::date + time '09:00')
                    RETURNING id
                    """,
                    (
                        item["title"],
                        item.get("description"),
                        "task_template",
                        case_row.get("customer_id"),
                        case_row.get("ansvarlig_bruger_id"),
                        current_user.get("id"),
                        item.get("planned_due_date"),
                    ),
                )
                created_case_id = subcase_row.get("id") if subcase_row else None
                if created_case_id:
                    created_case_ids.append(created_case_id)
                    execute_query(
                        """
                        INSERT INTO sag_relationer (kilde_sag_id, målsag_id, relationstype)
                        VALUES (%s, %s, %s)
                        """,
                        (case_id, created_case_id, "undersag"),
                    )

            execute_query(
                """
                INSERT INTO case_template_run_items (
                    template_run_id, template_item_id, created_case_id, created_task_id, status
                )
                VALUES (%s, %s, %s, %s, %s)
                """,
                (
                    run_id,
                    item.get("template_item_id"),
                    created_case_id,
                    created_task_id,
                    "created" if (created_case_id or created_task_id) else "skipped",
                ),
            )

        execute_query(
            "UPDATE case_template_runs SET status = 'completed', updated_at = NOW() WHERE id = %s",
            (run_id,),
        )
    except Exception as exc:
        logger.error("❌ Template run %s failed: %s", run_id, exc)
        execute_query(
            "UPDATE case_template_runs SET status = 'failed', error_message = %s, updated_at = NOW() WHERE id = %s",
            (str(exc), run_id),
        )
        raise HTTPException(status_code=500, detail="Template run failed")

    return {
        "status": "completed",
        "run_id": run_id,
        "case_id": case_id,
        "template": {
            "id": template.get("id"),
            "name": template.get("name"),
        },
        "summary": preview["summary"],
        "created": {
            "task_ids": created_task_ids,
            "subcase_ids": created_case_ids,
        },
        "links": {
            "original_case_id": case_id,
            "related_subcases": created_case_ids,
        },
    }


@router.get("/cases/{case_id}/template-runs")
async def list_template_runs_for_case(
    case_id: int,
    limit: int = Query(10, ge=1, le=50),
    current_user: dict = Depends(require_permission("templates.view")),
):
    del current_user

    _fetch_case(case_id)

    rows = execute_query(
        """
        SELECT
            r.id,
            r.case_id,
            r.template_id,
            t.name AS template_name,
            r.started_by,
            r.started_at,
            r.status,
            r.error_message,
            COUNT(ri.id) AS item_count,
            COUNT(ri.id) FILTER (WHERE ri.created_task_id IS NOT NULL) AS created_tasks,
            COUNT(ri.id) FILTER (WHERE ri.created_case_id IS NOT NULL) AS created_subcases
        FROM case_template_runs r
        LEFT JOIN task_templates t ON t.id = r.template_id
        LEFT JOIN case_template_run_items ri ON ri.template_run_id = r.id
        WHERE r.case_id = %s
        GROUP BY r.id, t.name
        ORDER BY r.started_at DESC, r.id DESC
        LIMIT %s
        """,
        (case_id, limit),
    ) or []

    return rows
