"""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 = ""
    environment_ids: list[str] = Field(default_factory=list)
    tool_names: list[str] = Field(default_factory=list)
    llm_names: list[str] = Field(default_factory=list)
    user_ids: list[str] = Field(default_factory=list)


class UpdateProjectReq(BaseModel):
    name: str | None = None
    default_tool: str | None = None
    description: str | None = None
    status: str | None = None
    environment_ids: list[str] | None = None
    tool_names: list[str] | None = None
    llm_names: list[str] | None = None
    user_ids: list[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()
    data["project_key"] = project.name if not getattr(project, "source_path", "") else project.id
    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["project_key"])]
        data["ticket_count"] = len(matched)
    except Exception:
        matched = []
        data["ticket_count"] = 0

    # Project-scoped tools: prefer explicit project assignment, fallback to ticket usage
    try:
        explicit_tools = list(getattr(project, "tool_names", []) or [])
        if explicit_tools:
            data["assigned_tools"] = explicit_tools
        else:
            tools_used = sorted({
                t.assigned_tool.tool
                for t in matched
                if getattr(t, "assigned_tool", None) and getattr(t.assigned_tool, "tool", "")
            })
            data["assigned_tools"] = tools_used
    except Exception:
        data["assigned_tools"] = []

    # Project-scoped environments
    try:
        from proxym.dashboard._environments_api import get_environment_registry
        env_reg = get_environment_registry()
        envs = []
        for env_id in getattr(project, "environment_ids", []) or []:
            env = env_reg.get(env_id)
            if env:
                envs.append({
                    "id": env.id,
                    "name": env.name,
                    "kind": env.kind.value if hasattr(env.kind, "value") else str(env.kind),
                    "path": env.path,
                    "target": env.target_label(),
                })
        data["assigned_environments"] = envs
    except Exception:
        data["assigned_environments"] = []

    # Project-scoped tools and LLMs
    try:
        from proxym.tools import ToolRegistry
        reg_tools = ToolRegistry.get()
        tools = []
        for tool_name in getattr(project, "tool_names", []) or []:
            tool = reg_tools.get_tool(tool_name)
            if tool:
                tools.append({
                    "name": tool.name,
                    "default_model": tool.default_model,
                    "default_instance": tool.default_instance,
                    "description": tool.description,
                })
            else:
                tools.append({"name": tool_name, "default_model": "", "default_instance": "", "description": ""})
        data["assigned_tool_details"] = tools
    except Exception:
        data["assigned_tool_details"] = []

    try:
        data["assigned_llms"] = list(getattr(project, "llm_names", []) or [])
    except Exception:
        data["assigned_llms"] = []

    # Users
    try:
        from proxym.dashboard.users import UserManager
        user_mgr = UserManager.get()
        users = []
        for user_id in getattr(project, "user_ids", []) or []:
            user = user_mgr.get_user(user_id)
            if user:
                users.append({"id": user.id, "name": user.name or user.email or user.id, "email": user.email, "role": user.role})
        data["assigned_users"] = users
    except Exception:
        data["assigned_users"] = []

    return data


def _get_project(project_id: str):
    reg = _get_registry()
    project = reg.get(project_id)
    if not project:
        project = reg.find_by_name(project_id)
    return project


def _logical_project_key(project) -> str:
    return project.name if not getattr(project, "source_path", "") else project.id


# --- 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_project(project_id)
    if not project:
        raise HTTPException(404, f"Project {project_id} not found")
    return _enrich_project(project)


@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,
            environment_ids=req.environment_ids,
            tool_names=req.tool_names,
            llm_names=req.llm_names,
            user_ids=req.user_ids,
        )
        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,
            default_tool=req.default_tool,
            environment_ids=req.environment_ids,
            tool_names=req.tool_names,
            llm_names=req.llm_names,
            user_ids=req.user_ids,
        )
        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="",
            local_path="",
            default_tool=req.default_tool,
            description=req.description,
            environment_ids=req.environment_ids,
            tool_names=req.tool_names,
            llm_names=req.llm_names,
            user_ids=req.user_ids,
        )
        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 _enrich_project(result)


@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_project(project_id)
    match_values = {project_id}
    if project:
        match_values.add(project.name)
        match_values.add(_logical_project_key(project))
    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_project(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"] = _logical_project_key(project)
    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())
