"""map-gen task: produces patches.diff for map.json."""

from __future__ import annotations

import difflib
import json

from milco.core.run_context import RunContext
from milco.core.artifacts import write_artifact, ensure_all_artifacts_exist
from milco.tools.fs_tools import scan_repo
from milco.tasks.base import FixResult
from milco.tasks.registry import register_task, TaskBase


def _generate_map_json_content(ctx: RunContext) -> str:
    repo_map = scan_repo(ctx.repo_root)
    data = {
        "repo_root": repo_map["repo_root"],
        "files": repo_map["files"],
        "directories": repo_map["directories"],
        "total_files": repo_map["total_files"],
        "total_directories": repo_map["total_directories"],
        "python_file_count": repo_map["python_file_count"],
    }
    return json.dumps(data, indent=2) + "\n"


def _make_unified_diff(old_content: str, new_content: str, filename: str) -> str:
    old_lines = old_content.splitlines(keepends=True)
    new_lines = new_content.splitlines(keepends=True)
    diff = difflib.unified_diff(
        old_lines,
        new_lines,
        fromfile=f"a/{filename}",
        tofile=f"b/{filename}",
    )
    return "".join(diff)


@register_task("map-gen")
class MapGenTask(TaskBase):
    needs_llm = False
    description = "Generate repo knowledge index (map.json)"

    def fix(self, ctx: RunContext) -> FixResult:
        ctx.ensure_run_dir()
        errors: list[str] = []

        from milco.policy.policy import check_evidence_first

        evidence_path = ctx.artifact_path("evidence.md")
        evidence_text = (
            evidence_path.read_text(encoding="utf-8") if evidence_path.exists() else ""
        )
        ok, msg = check_evidence_first(evidence_text)
        if not ok:
            errors.append(msg)
            write_artifact(ctx, "summary.md", f"# Fix Summary\n\nBlocked: {msg}\n")
            ensure_all_artifacts_exist(ctx)
            return FixResult(success=False, applied=False, diff_text="", errors=errors)

        map_path = ctx.repo_root / "map.json"
        old_content = map_path.read_text(encoding="utf-8") if map_path.exists() else ""
        new_content = _generate_map_json_content(ctx)
        diff_text = _make_unified_diff(old_content, new_content, "map.json")

        if not diff_text.strip():
            diff_text = "# No changes needed – map.json is up to date.\n"

        write_artifact(ctx, "patches.diff", diff_text)

        if ctx.can_apply():
            map_path.write_text(new_content, encoding="utf-8")
            applied = True
        else:
            applied = False

        ensure_all_artifacts_exist(ctx)
        return FixResult(
            success=len(errors) == 0,
            applied=applied,
            diff_text=diff_text,
            errors=errors,
        )
