"""REST endpoints for project management."""
from __future__ import annotations

from pathlib import Path
from typing import Any

from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, Field, ValidationError

from proxym.config import get_settings
from proxym.observability import log_call
from proxym.storage import DEFAULT_SQLITE_PATH

router = APIRouter(tags=["projects"])


# --- Lazy singleton ---

_registry = None


def _get_registry():
    global _registry
    if _registry is None:
        from proxym.projects import ProjectRegistry
        persist = DEFAULT_SQLITE_PATH
        _registry = ProjectRegistry(persist_path=persist)
        # Auto-scan default directory
        settings = get_settings()
        root = settings.projects_root
        if root:
            _registry.scan_directory(root)
    return _registry


# --- Request models ---

class AddProjectReq(BaseModel):
    """Dodaj projekt — jedno z: path, git_url, ssh."""
    name: str | None = None
    path: str | None = None          # local: ~/github/my-app
    git_url: str | None = None       # git: https://github.com/user/repo.git
    clone_to: str | None = None      # gdzie klonować (domyślnie projects_root)
    ssh_host: str | None = None      # SSH host
    ssh_path: str | None = None      # SSH remote path
    ssh_user: str = "root"
    ssh_key: str | None = None
    ftp_url: str | None = None       # ftp://host/path
    default_tool: str | None = None
    description: str = ""


class UpdateProjectReq(BaseModel):
    name: str | None = None
    default_tool: str | None = None
    description: str | None = None
    status: str | None = None


class ScanReq(BaseModel):
    directory: str                    # folder do skanowania


# --- Helpers ---

def _enrich_project(project) -> dict[str, Any]:
    """Add assignment counts to project payload: tickets, environments, tools, users."""
    data = project.model_dump()
    pid = project.id
    pname = project.name

    # Tickets assigned to this project (by id or name)
    try:
        from proxym.dashboard._tickets_api import _tickets
        mgr = _tickets()
        all_tickets = mgr.list_tickets()
        matched = [t for t in all_tickets if t.project_id in (pid, pname)]
        data["ticket_count"] = len(matched)
        # Unique tools used across tickets
        tools_used = set()
        for t in matched:
            if t.assigned_tool and t.assigned_tool.tool:
                tools_used.add(t.assigned_tool.tool)
        data["assigned_tools"] = sorted(tools_used)
    except Exception:
        data["ticket_count"] = 0
        data["assigned_tools"] = []

    # Environments
    try:
        from proxym.dashboard._environments_api import get_environment_registry
        env_reg = get_environment_registry()
        envs = []
        for env_id, env in env_reg.environments.items():
            envs.append({"id": env_id, "name": env.name, "kind": env.kind.value if hasattr(env.kind, "value") else str(env.kind)})
        data["assigned_environments"] = envs
    except Exception:
        data["assigned_environments"] = []

    # Users
    try:
        from proxym.dashboard.users import UserManager
        user_mgr = UserManager.get()
        users = [{"id": u.id, "name": u.name or u.email or u.id} for u in user_mgr.users.values()]
        data["assigned_users"] = users
    except Exception:
        data["assigned_users"] = []

    return data


# --- Endpoints ---

@router.get("/projects")
async def list_projects(
    status: str | None = None,
    source_type: str | None = None,
) -> list[dict[str, Any]]:
    """Lista wszystkich projektów z informacją o przypisanych obiektach."""
    reg = _get_registry()
    from proxym.projects import ProjectStatus, SourceType
    s = ProjectStatus(status) if status else None
    st = SourceType(source_type) if source_type else None
    projects = reg.list_projects(status=s, source_type=st)
    return [_enrich_project(p) for p in projects]


@router.get("/projects/{project_id}")
async def get_project(project_id: str) -> dict[str, Any]:
    project = _get_registry().get(project_id)
    if not project:
        raise HTTPException(404, f"Project {project_id} not found")
    return project.model_dump()


@router.post("/projects")
@log_call(level="info")
async def add_project(req: AddProjectReq) -> dict[str, Any]:
    """Dodaj projekt — po nazwie lub z pełną konfiguracją."""
    reg = _get_registry()

    if req.path:
        # Lokalny folder
        from proxym.projects import Project, SourceType
        path = str(Path(req.path).expanduser().resolve())
        project = Project(
            name=req.name or Path(path).name,
            source_type=SourceType.local,
            source_path=path,
            local_path=path,
            default_tool=req.default_tool,
            description=req.description,
        )
        return _enrich_project(reg.add(project))

    elif req.git_url:
        settings = get_settings()
        clone_to = req.clone_to or settings.projects_root or "~/github"
        return _enrich_project(reg.add_git_repo(req.git_url, clone_to=clone_to))

    elif req.ssh_host and req.ssh_path:
        return _enrich_project(reg.add_ssh_project(
            host=req.ssh_host, path=req.ssh_path,
            user=req.ssh_user, ssh_key=req.ssh_key, name=req.name,
        ))

    elif req.ftp_url:
        from proxym.projects import Project, SourceType
        name = req.name or req.ftp_url.rsplit("/", 1)[-1]
        project = Project(
            name=name, source_type=SourceType.ftp,
            source_path=req.ftp_url, description=req.description,
        )
        return _enrich_project(reg.add(project))

    elif req.name:
        # Name-only project (lightweight label)
        from proxym.projects import Project, SourceType
        project = Project(
            name=req.name,
            source_type=SourceType.local,
            source_path="",
            description=req.description,
        )
        return _enrich_project(reg.add(project))

    else:
        raise HTTPException(400, "Provide at least 'name'.")


@router.put("/projects/{project_id}")
async def update_project(project_id: str, req: UpdateProjectReq) -> dict[str, Any]:
    updates = {k: v for k, v in req.model_dump().items() if v is not None}
    result = _get_registry().update(project_id, updates)
    if not result:
        raise HTTPException(404)
    return result.model_dump()


@router.delete("/projects/{project_id}")
async def remove_project(project_id: str) -> dict[str, str]:
    if _get_registry().remove(project_id):
        return {"status": "deleted"}
    raise HTTPException(404)


@router.post("/projects/scan")
@log_call(level="info")
async def scan_directory(req: ScanReq) -> dict[str, Any]:
    """Skanuj folder i dodaj znalezione projekty."""
    added = _get_registry().scan_directory(req.directory)
    return {
        "scanned": req.directory,
        "added": len(added),
        "projects": [p.model_dump() for p in added],
    }


@router.get("/projects/{project_id}/tickets")
async def project_tickets(project_id: str) -> list[dict[str, Any]]:
    """Tickety powiązane z projektem (match by id or name)."""
    from proxym.dashboard._tickets_api import _tickets
    mgr = _tickets()
    # Also resolve project name for matching
    project = _get_registry().get(project_id)
    match_values = {project_id}
    if project:
        match_values.add(project.name)
    all_tickets = mgr.list_tickets()
    return [
        t.summary() for t in all_tickets
        if getattr(t, "project_id", None) in match_values
    ]


@router.post("/projects/{project_id}/tickets")
async def create_project_ticket(project_id: str, req: dict[str, Any]) -> dict[str, Any]:
    """Stwórz ticket od razu powiązany z projektem."""
    # Ensure project exists
    project = _get_registry().get(project_id)
    if not project:
        raise HTTPException(404, f"Project {project_id} not found")

    from proxym.dashboard._tickets_api import CreateTicketReq, create_ticket

    payload = dict(req or {})
    payload["project_id"] = project_id
    try:
        ticket_req = CreateTicketReq(**payload)
    except ValidationError as e:
        # Request body validation errors should not surface as 500.
        raise HTTPException(422, {"detail": e.errors()})

    # Call create_ticket with validated/normalized types.
    return await create_ticket(**ticket_req.model_dump())
