"""실행 없이 등록한 작업의 결과를 기존 작업·그룹 조회 경로에 연결한다."""
from __future__ import annotations

import hashlib
import json
from datetime import date
from pathlib import Path

from okstra_project import project_json_path, tasks_root
from okstra_project.dirs import TASK_CATALOG_RELATIVE

from . import group_context
from .brief_frontmatter import read_brief_frontmatter
from .ids import slugify_task_segment
from .json_boundary import load_owned_object, write_owned_object_atomic
from .paths import task_dir, task_manifest_file
from .render import render_task_catalog_discovery
from .run_context import dir_flock


def find_brief_tasks(project_root: Path, token: str, task_group: str) -> list[dict]:
    project = load_owned_object(project_json_path(project_root), artifact="project config")
    project_id = project.get("projectId", "")
    if not project_id:
        raise ValueError("project.json has no projectId")
    matches = []
    for folder in sorted(group_context.briefs_root(project_root).glob("*")):
        if not folder.is_dir() or (task_group and folder.name != slugify_task_segment(task_group)):
            continue
        for brief in group_context.group_briefs(project_root, folder.name):
            identities = (brief["brief_id"], brief["ticket_id"], folder.name)
            if token.casefold() not in {str(value).casefold() for value in identities}:
                continue
            path = project_root / brief["brief"]
            frontmatter = read_brief_frontmatter(path)
            group = frontmatter.get("task-group") or folder.name
            if slugify_task_segment(group) != folder.name:
                raise ValueError(f"Brief task-group does not match its directory: {brief['brief']}")
            task_id = slugify_task_segment(brief["brief_id"])
            root = task_dir(project_root, slugify_task_segment(group), task_id)
            matches.append({
                "_briefVerified": True,
                "schemaVersion": "1.0", "projectId": project_id,
                "projectRoot": str(project_root), "taskGroup": group, "taskId": task_id,
                "taskKey": f"{project_id}:{group}:{task_id}",
                "taskGroupPathSegment": slugify_task_segment(group),
                "taskIdPathSegment": task_id, "taskBriefPath": brief["brief"],
                "taskRootPath": root.relative_to(project_root).as_posix(),
                "taskManifestPath": task_manifest_file(root).relative_to(project_root).as_posix(),
            })
    return matches


def record_direct_work(project_root: Path, manifest_path: Path, manifest: dict) -> None:
    """상태와 본문이 같은 재시도는 기존 결과를 재사용한다. 정본 포인터는 호출자가 쓴다."""
    summary = str(manifest.get("workStatusNote") or "").strip()
    if not summary:
        raise ValueError("Direct completion requires --note or --note-file with the work and verification summary")
    previous_path = manifest.get("latestWorkRecordPath", "")
    if previous_path:
        (project_root / previous_path).resolve().relative_to(manifest_path.parent.resolve())
    previous = (
        load_owned_object(project_root / previous_path, artifact="direct work record")
        if previous_path else {}
    )
    if previous.get("summary") == summary and previous.get("statusUpdatedAt") == manifest["workStatusUpdatedAt"]:
        return
    record = {
        "schemaVersion": "1.0", "taskKey": manifest["taskKey"], "source": "direct",
        "summary": summary, "crossVerification": "not-performed",
        "statusUpdatedAt": manifest["workStatusUpdatedAt"],
        "previousRecordPath": previous_path,
    }
    identity = {key: value for key, value in record.items() if key != "statusUpdatedAt"}
    digest = hashlib.sha256(json.dumps(identity, sort_keys=True).encode()).hexdigest()
    path = manifest_path.parent / "work-records" / f"{digest}.json"
    if path.exists():
        saved = load_owned_object(path, artifact="direct work record")
        manifest["workStatusUpdatedAt"] = saved["statusUpdatedAt"]
        manifest["updatedAt"] = saved["statusUpdatedAt"]
    else:
        write_owned_object_atomic(path, record, artifact="direct work record")
    manifest["latestWorkRecordPath"] = path.relative_to(project_root).as_posix()


def publish_direct_work(project_root: Path, manifest: dict) -> Path | None:
    """상태 저장 뒤 재실행해도 같은 그룹 항목을 갱신한다."""
    catalog = project_root / TASK_CATALOG_RELATIVE
    with dir_flock(catalog.parent, ".task-catalog.lock"):
        render_task_catalog_discovery(str(catalog), {
            "PROJECT_ROOT": str(project_root), "OKSTRA_TASKS_ROOT": str(tasks_root(project_root)),
            "PROJECT_ID": manifest["projectId"], "TASK_KEY": manifest["taskKey"],
            "RUN_TIMESTAMP_ISO": manifest["workStatusUpdatedAt"],
        })
    if not manifest.get("latestWorkRecordPath") or manifest["workStatus"] != "done":
        return group_context.refresh_group_queue(project_root, manifest["taskGroup"])
    record = load_owned_object(
        project_root / manifest["latestWorkRecordPath"], artifact="direct work record"
    )
    entry = group_context.MemoryEntry(
        task_id=manifest["taskId"], task_type="", seq="", next_phase="",
        date=record["statusUpdatedAt"][:10], headline=" ".join(record["summary"].split())[:group_context.HEADLINE_MAX],
        decisions=(), follow_ups=(), record=manifest["latestWorkRecordPath"],
        source="direct",
    )
    target, _ = group_context.record_task_memory(
        project_root, manifest["taskGroup"], entry, today=date.today()
    )
    return target
