"""Read project-local okstra state into manager-owned snapshots."""
from __future__ import annotations

from pathlib import Path

from okstra_project import TASKS_RELATIVE, StateError, parse_task_key, read_task_catalog, read_task_manifest, slugify

from . import next_phase
from .manager_paths import children_json_path, projects_json_path, snapshots_json_path, task_manifest_path
from .manager_store import _now_iso, _read_json, _read_json_default, _write_json


def _project_map(home: Path, manager_id: str) -> dict[str, dict]:
    projects = _read_json_default(projects_json_path(home, manager_id), {"projects": []})
    return {
        str(project.get("projectId")): project
        for project in projects.get("projects", [])
        if isinstance(project, dict) and project.get("projectId")
    }


def _phase_outcome(manifest: dict) -> dict:
    value = manifest.get("phaseOutcome")
    return value if isinstance(value, dict) else {}


def _workflow(manifest: dict) -> dict:
    value = manifest.get("workflow")
    return value if isinstance(value, dict) else {}


def _list_field(payload: dict, field: str) -> list:
    value = payload.get(field)
    return list(value) if isinstance(value, list) else []


def _resolve_task_root_read_only(project_root: Path, task_key: str) -> Path | None:
    _, task_group, task_id = parse_task_key(task_key)
    requested_key = task_key.lower()
    for entry in read_task_catalog(project_root):
        entry_key = entry.get("taskKey") or ""
        if not isinstance(entry_key, str) or entry_key.lower() != requested_key:
            continue
        relative_path = entry.get("taskRootPath") or entry.get("taskRoot") or ""
        if not isinstance(relative_path, str) or not relative_path:
            continue
        candidate = project_root / relative_path if not Path(relative_path).is_absolute() else Path(relative_path)
        if candidate.is_dir():
            return candidate
    slug_path = project_root / TASKS_RELATIVE / slugify(task_group) / slugify(task_id)
    if slug_path.is_dir():
        return slug_path
    return None


def _base_child_snapshot(child: dict) -> dict:
    task_key = str(child.get("taskKey") or "")
    return {
        "projectId": str(child.get("projectId") or ""),
        "taskGroup": str(child.get("taskGroup") or ""),
        "taskId": str(child.get("taskId") or ""),
        "taskKey": task_key,
        "exists": False,
        "taskRoot": "",
    }


def _snapshot_child(project_root: Path, child: dict) -> dict:
    base = _base_child_snapshot(child)
    task_key = base["taskKey"]
    try:
        task_dir = _resolve_task_root_read_only(project_root, task_key)
        if task_dir is None:
            return base
        manifest = read_task_manifest(task_dir) or {}
    except StateError as exc:
        return {**base, "error": str(exc)}
    workflow = _workflow(manifest)
    outcome = _phase_outcome(manifest)
    return {
        **base,
        "exists": True,
        "taskRoot": str(task_dir),
        "taskType": str(manifest.get("taskType") or ""),
        "currentPhase": str(workflow.get("currentPhase") or ""),
        "currentPhaseState": str(workflow.get("currentPhaseState") or ""),
        "lastCompletedPhase": str(workflow.get("lastCompletedPhase") or ""),
        "nextRecommendedPhase": next_phase.promote(
            workflow.get("nextRecommendedPhase")
        ),
        "latestRunStatus": str(manifest.get("latestRunStatus") or manifest.get("currentStatus") or ""),
        "latestReportRecordPath": str(manifest.get("latestReportRecordPath") or ""),
        "finalVerdict": str(outcome.get("finalVerdict") or ""),
        "crossProjectDependencies": _list_field(outcome, "crossProjectDependencies"),
        "recommendedNextSteps": _list_field(outcome, "recommendedNextSteps"),
        "openClarifications": _list_field(outcome, "openClarifications"),
    }


def sync_task(home: Path, manager_id: str, task_group: str, task_id: str, *, now: str | None = None) -> dict:
    _read_json(task_manifest_path(home, manager_id, task_group, task_id))
    children = _read_json_default(children_json_path(home, manager_id, task_group, task_id), {"children": []})
    projects = _project_map(home, manager_id)
    rows = []
    for child in children.get("children", []):
        if not isinstance(child, dict):
            continue
        project = projects.get(str(child.get("projectId") or ""))
        if project is None:
            rows.append({**child, "exists": False, "error": "unknown project membership"})
            continue
        root = Path(str(project.get("projectRoot") or ""))
        if not root.is_dir():
            rows.append({**child, "exists": False, "error": f"missing project root: {root}"})
            continue
        rows.append(_snapshot_child(root, child))
    payload = {
        "managerId": manager_id,
        "taskGroup": task_group,
        "taskId": task_id,
        "syncedAt": now or _now_iso(),
        "children": rows,
    }
    _write_json(snapshots_json_path(home, manager_id, task_group, task_id), payload)
    return payload


def status_task(home: Path, manager_id: str, task_group: str, task_id: str) -> dict:
    manifest = _read_json(task_manifest_path(home, manager_id, task_group, task_id))
    children = _read_json_default(children_json_path(home, manager_id, task_group, task_id), {"children": []})
    snapshot = _read_json_default(snapshots_json_path(home, manager_id, task_group, task_id), {"children": []})
    by_key = {row.get("taskKey"): row for row in snapshot.get("children", []) if isinstance(row, dict)}
    rows = []
    summary = {"planned": 0, "missing": 0, "running": 0, "done": 0, "blocked": 0}
    for child in children.get("children", []):
        if not isinstance(child, dict):
            continue
        key = child.get("taskKey")
        snapshot_row = by_key.get(key)
        row = {**child, **(snapshot_row or {})}
        status = str(row.get("latestRunStatus") or row.get("launch", {}).get("status") or "planned")
        if snapshot_row is None:
            summary["planned"] += 1
        elif not row.get("exists", False):
            summary["missing"] += 1
        elif status == "done":
            summary["done"] += 1
        elif status in {"running", "started", "in-progress"}:
            summary["running"] += 1
        elif status == "blocked":
            summary["blocked"] += 1
        else:
            summary["planned"] += 1
        rows.append(row)
    return {"manifest": manifest, "summary": summary, "children": rows, "lastSnapshot": snapshot}
