"""verify_upgrade_analysis -- Track and verify upgrade analysis completeness.

Scans release-docs/ for extracted .txt files (source material) and
upgrade-analysis/ for generated reports. Returns a structured checklist
showing which packages have been analyzed, which are remaining, and
whether the comprehensive report can proceed.

The AI MUST call this tool:
  1. Before starting report generation (to get the full manifest)
  2. After every 2-3 package reports (to see what's remaining)
  3. Before generating the comprehensive/executive report (gate check)

This ensures no packages are silently skipped.
"""

import json
import logging
import re
from pathlib import Path
from typing import Any

from ..utils import state

logger = logging.getLogger(__name__)

TOOL_DEFINITION = {
    "name": "verify_upgrade_analysis",
    "description": (
        "Track upgrade analysis completeness. Scans release-docs/ for "
        "source .txt files and upgrade-analysis/ for generated reports. "
        "Returns which packages are done, which are remaining, and "
        "whether the comprehensive report can proceed. Call this before "
        "starting, after every 2-3 packages, and before the executive "
        "summary."
    ),
    "inputSchema": {
        "type": "object",
        "properties": {
            "working_directory": {
                "type": "string",
                "description": "Absolute path to the workspace root directory.",
            },
            "account_name": {
                "type": "string",
                "description": (
                    "Customer account name. Determines the base directory: "
                    "customers/<slug>/release-docs/ and "
                    "customers/<slug>/upgrade-analysis/."
                ),
            },
        },
        "required": ["working_directory", "account_name"],
    },
}


def _make_slug(name: str) -> str:
    slug = name.lower().strip()
    slug = re.sub(r"[^a-z0-9]+", "-", slug)
    slug = slug.strip("-")
    return slug or "unknown"


def _scan_source_material(release_docs_dir: Path) -> dict[str, dict[str, Any]]:
    """Scan release-docs/ for extracted .txt files per package.

    Returns {package_folder_name: {txt_files: [...], txt_count: N, word_count: N}}
    """
    packages: dict[str, dict[str, Any]] = {}

    if not release_docs_dir.is_dir():
        return packages

    for pkg_dir in sorted(release_docs_dir.iterdir()):
        if not pkg_dir.is_dir() or pkg_dir.name.startswith("."):
            continue

        txt_files: list[dict[str, Any]] = []
        total_words = 0

        for release_dir in sorted(pkg_dir.iterdir()):
            if not release_dir.is_dir():
                continue
            for f in sorted(release_dir.iterdir()):
                if f.suffix == ".txt" and f.stat().st_size > 0:
                    word_count = len(f.read_text(errors="replace").split())
                    txt_files.append({
                        "release": release_dir.name,
                        "file": f.name,
                        "words": word_count,
                    })
                    total_words += word_count

        if txt_files:
            packages[pkg_dir.name] = {
                "txt_files": txt_files,
                "txt_count": len(txt_files),
                "word_count": total_words,
            }

    return packages


def _scan_existing_reports(analysis_dir: Path) -> dict[str, dict[str, Any]]:
    """Scan upgrade-analysis/ for existing .md reports.

    Returns {report_filename: {path, size_bytes, line_count, has_content}}
    """
    reports: dict[str, dict[str, Any]] = {}

    if not analysis_dir.is_dir():
        return reports

    for f in sorted(analysis_dir.iterdir()):
        if f.suffix != ".md":
            continue
        content = f.read_text(errors="replace")
        lines = content.strip().split("\n")
        non_empty_lines = [l for l in lines if l.strip()]

        reports[f.name] = {
            "path": str(f),
            "size_bytes": f.stat().st_size,
            "line_count": len(lines),
            "has_content": len(non_empty_lines) > 3,
        }

    return reports


def _match_package_to_report(
    pkg_folder: str,
    existing_reports: dict[str, dict[str, Any]],
) -> str | None:
    """Try to find an existing report file that matches a package folder name."""
    pkg_lower = pkg_folder.lower().replace("_", " ").replace("-", " ")
    pkg_words = set(pkg_lower.split())

    for report_name in existing_reports:
        report_lower = report_name.lower().replace("_", " ").replace("-", " ")
        report_lower = re.sub(r"^\d+\s*", "", report_lower)
        report_lower = report_lower.replace(".md", "")
        report_words = set(report_lower.split())

        if pkg_words & report_words and len(pkg_words & report_words) >= min(2, len(pkg_words)):
            return report_name

    return None


async def run(arguments: dict[str, Any]) -> str:
    """Execute the verify_upgrade_analysis tool."""
    state.set_working_dir(arguments.get("working_directory"))
    working_dir = state.get_working_dir()

    account_name = arguments.get("account_name", "").strip()
    if not account_name:
        return (
            "STATUS: MISSING_CUSTOMER\n\n"
            "account_name is required."
        )

    slug = _make_slug(account_name)
    customer_dir = working_dir / "customers" / slug
    release_docs_dir = customer_dir / "release-docs"
    analysis_dir = customer_dir / "upgrade-analysis"

    if not release_docs_dir.is_dir():
        return (
            f"STATUS: NO_SOURCE_DATA\n\n"
            f"No release-docs/ folder found at {release_docs_dir}.\n"
            f"Run get_release_info → download_release_docs → "
            f"extract_doc_text first."
        )

    source_packages = _scan_source_material(release_docs_dir)
    if not source_packages:
        return (
            f"STATUS: NO_SOURCE_DATA\n\n"
            f"release-docs/ exists but contains no extracted .txt files.\n"
            f"Run extract_doc_text first."
        )

    existing_reports = _scan_existing_reports(analysis_dir)

    done: list[str] = []
    remaining: list[str] = []
    pkg_details: list[str] = []

    for pkg_folder, pkg_info in sorted(source_packages.items()):
        matched_report = _match_package_to_report(pkg_folder, existing_reports)
        if matched_report and existing_reports[matched_report]["has_content"]:
            done.append(pkg_folder)
            pkg_details.append(
                f"  [DONE] {pkg_folder}: {pkg_info['txt_count']} source files, "
                f"{pkg_info['word_count']} words → {matched_report}"
            )
        else:
            remaining.append(pkg_folder)
            releases = ", ".join(f["release"] for f in pkg_info["txt_files"])
            pkg_details.append(
                f"  [TODO] {pkg_folder}: {pkg_info['txt_count']} source files, "
                f"{pkg_info['word_count']} words "
                f"(releases: {releases})"
            )

    special_reports = ["upgrade-sequence.md", "pre-upgrade-checklist.md"]
    special_status: list[str] = []
    for sr in special_reports:
        if sr in existing_reports and existing_reports[sr]["has_content"]:
            special_status.append(f"  [DONE] {sr}")
        else:
            special_status.append(f"  [TODO] {sr}")

    comprehensive_exists = any(
        "assessment" in name.lower() or "executive" in name.lower()
        or "comprehensive" in name.lower()
        for name, info in existing_reports.items()
        if info["has_content"]
    )

    all_packages_done = len(remaining) == 0
    can_proceed_to_comprehensive = all_packages_done

    header = [
        f"STATUS: READY\n",
        f"## Upgrade Analysis Verification — {account_name}\n",
        f"Source packages with .txt files: {len(source_packages)}",
        f"Per-package reports completed: {len(done)} / {len(source_packages)}",
        f"Remaining: {len(remaining)}",
        "",
    ]

    body = ["### Package checklist:\n"] + pkg_details + [""]
    body += ["### Supporting reports:\n"] + special_status + [""]

    if can_proceed_to_comprehensive:
        gate = [
            "### GATE: PASSED",
            "All per-package reports exist. You may now generate the "
            "comprehensive / executive summary report.",
        ]
        if comprehensive_exists:
            gate.append("(Comprehensive report already exists.)")
    else:
        gate = [
            "### GATE: BLOCKED",
            f"Cannot generate comprehensive report yet. "
            f"{len(remaining)} package(s) still need reports:",
        ]
        for pkg in remaining:
            info = source_packages[pkg]
            gate.append(
                f"  - {pkg} ({info['txt_count']} .txt files, "
                f"{info['word_count']} words)"
            )
        gate.append("")
        gate.append(
            "Generate reports for the remaining packages above, "
            "then call verify_upgrade_analysis again."
        )

    return "\n".join(header + body + gate)
