"""Unified cockpit projects and cross-module assets."""
from __future__ import annotations

import json
from typing import Any, Optional

from app.db import execute, fetch_all, fetch_one
from app.services import nas_folders


def _row(row: dict | None) -> dict | None:
    if not row:
        return None
    out = dict(row)
    for k, v in list(out.items()):
        if hasattr(v, "isoformat"):
            out[k] = v.isoformat()
    return out


def list_projects(client_id: Optional[int] = None, limit: int = 50) -> list[dict[str, Any]]:
    clauses, params = [], []
    if client_id:
        clauses.append("p.client_id = %s")
        params.append(client_id)
    where = (" WHERE " + " AND ".join(clauses)) if clauses else ""
    safe = max(1, min(limit, 200))
    rows = fetch_all(
        f"""
        SELECT p.*, c.name AS client_name,
               (SELECT COUNT(*) FROM project_assets a WHERE a.project_id = p.id) AS asset_count
        FROM cockpit_projects p
        LEFT JOIN clients c ON c.id = p.client_id
        {where}
        ORDER BY p.updated_at DESC, p.id DESC
        LIMIT %s
        """,
        tuple(params + [safe]),
    )
    return [_row(r) for r in rows]


def get_project(project_id: int) -> dict[str, Any] | None:
    row = fetch_one(
        """
        SELECT p.*, c.name AS client_name
        FROM cockpit_projects p
        LEFT JOIN clients c ON c.id = p.client_id
        WHERE p.id = %s
        """,
        (project_id,),
    )
    if not row:
        return None
    out = _row(row) or {}
    assets = fetch_all(
        "SELECT * FROM project_assets WHERE project_id = %s ORDER BY created_at DESC",
        (project_id,),
    )
    out["assets"] = [_row(a) for a in assets]
    return out


def create_project(
    name: str,
    client_id: Optional[int] = None,
    description: str = "",
    created_by: str = "ceo",
    metadata: dict | None = None,
    project_type: str = "general",
    priority: str = "normal",
    ensure_nas: bool = True,
) -> dict[str, Any]:
    row = fetch_one(
        """
        INSERT INTO cockpit_projects (name, client_id, description, created_by, metadata, project_type, priority, updated_at)
        VALUES (%s, %s, %s, %s, %s::jsonb, %s, %s, NOW())
        RETURNING *
        """,
        (name.strip(), client_id, description or None, created_by, json.dumps(metadata or {}), project_type, priority),
    )
    out = _row(row) or {}
    if ensure_nas and out.get("id"):
        client_name = None
        if client_id:
            c = fetch_one("SELECT name FROM clients WHERE id = %s", (client_id,))
            client_name = c["name"] if c else None
        try:
            paths = nas_folders.ensure_project_folder(
                int(out["id"]), name, client_id, client_name, project_type
            )
            out.update(paths)
        except Exception as exc:
            out["nas_error"] = str(exc)
    return out


def update_project(project_id: int, **fields: Any) -> dict[str, Any] | None:
    allowed = ("name", "description", "status", "client_id", "project_type", "priority")
    sets, params = [], []
    for k, v in fields.items():
        if k in allowed and v is not None:
            sets.append(f"{k} = %s")
            params.append(v)
    if not sets:
        return get_project(project_id)
    params.append(project_id)
    execute(f"UPDATE cockpit_projects SET {', '.join(sets)}, updated_at = NOW() WHERE id = %s", tuple(params))
    return get_project(project_id)


def project_stats() -> dict[str, Any]:
    total = fetch_one("SELECT COUNT(*) AS n FROM cockpit_projects") or {"n": 0}
    by_type = fetch_all(
        "SELECT COALESCE(project_type, 'general') AS t, COUNT(*) AS n FROM cockpit_projects GROUP BY t"
    )
    with_nas = fetch_one("SELECT COUNT(*) AS n FROM cockpit_projects WHERE nas_path IS NOT NULL")
    with_client = fetch_one("SELECT COUNT(*) AS n FROM cockpit_projects WHERE client_id IS NOT NULL")
    assets = fetch_one("SELECT COUNT(*) AS n FROM project_assets")
    return {
        "total": int(total.get("n") or 0),
        "with_nas": int((with_nas or {}).get("n") or 0),
        "with_client": int((with_client or {}).get("n") or 0),
        "assets": int((assets or {}).get("n") or 0),
        "by_type": {r["t"]: int(r["n"]) for r in by_type},
    }


def add_asset(
    project_id: int,
    asset_type: str,
    title: str,
    ref_id: str | None = None,
    file_path: str | None = None,
    payload: dict | None = None,
    created_by: str = "ceo",
    source_agent: str | None = None,
) -> dict[str, Any]:
    row = fetch_one(
        """
        INSERT INTO project_assets (project_id, asset_type, ref_id, title, file_path, payload, created_by, source_agent)
        VALUES (%s, %s, %s, %s, %s, %s::jsonb, %s, %s)
        RETURNING *
        """,
        (
            project_id,
            asset_type,
            ref_id,
            title,
            file_path,
            json.dumps(payload or {}),
            created_by,
            source_agent,
        ),
    )
    execute("UPDATE cockpit_projects SET updated_at = NOW() WHERE id = %s", (project_id,))
    return _row(row) or {}


def get_or_create_agent_project(agent_key: str, client_id: Optional[int] = None) -> int:
    key = (agent_key or "agent").strip().lower()
    row = fetch_one(
        """
        SELECT id FROM cockpit_projects
        WHERE metadata->>'auto_agent' = %s AND status = 'active'
        ORDER BY updated_at DESC LIMIT 1
        """,
        (key,),
    )
    if row:
        return int(row["id"])
    created = create_project(
        f"Agent · {key}",
        client_id=client_id,
        description=f"Automatisch project voor {key} output",
        created_by=key,
        metadata={"auto_agent": key},
    )
    return int(created["id"])


def register_agent_output(
    asset_type: str,
    title: str,
    ref_id: str | None = None,
    payload: dict | None = None,
    project_id: Optional[int] = None,
    source_agent: str | None = None,
    created_by: str = "ceo",
    file_path: str | None = None,
) -> dict[str, Any] | None:
    agent = (source_agent or created_by or "agent").strip().lower()
    pid = project_id or get_or_create_agent_project(agent)

    if ref_id:
        existing = fetch_one(
            """
            SELECT id FROM project_assets
            WHERE project_id = %s AND asset_type = %s AND ref_id = %s
            LIMIT 1
            """,
            (pid, asset_type, ref_id),
        )
        if existing:
            return {"id": existing["id"], "project_id": pid, "dedup": True}

    return add_asset(
        pid,
        asset_type,
        title,
        ref_id=ref_id,
        file_path=file_path,
        payload=payload,
        created_by=created_by or agent,
        source_agent=agent,
    )


def link_photo_to_project(photo_id: int, project_id: int, created_by: str = "ceo") -> None:
    photo = fetch_one("SELECT id, filename, source FROM photo_imports WHERE id = %s", (photo_id,))
    if not photo:
        raise ValueError("Photo not found")
    execute(
        "UPDATE photo_imports SET project_id = %s, created_by = COALESCE(created_by, %s) WHERE id = %s",
        (project_id, created_by, photo_id),
    )
    add_asset(
        project_id,
        "photo",
        photo.get("filename") or f"Foto #{photo_id}",
        ref_id=str(photo_id),
        created_by=created_by,
        source_agent=photo.get("source"),
    )
