#!/usr/bin/env python3
"""List changed 1C objects from a saved-state object report."""

from __future__ import annotations

import argparse
import json
from pathlib import Path
from typing import Any


def load_json(path: Path) -> dict[str, Any]:
    return json.loads(path.read_text(encoding="utf-8-sig"))


def write_json(path: Path, data: dict[str, Any]) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(json.dumps(data, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")


def has_payload_role(item: dict[str, Any], role: str | None) -> bool:
    if not role:
        return True
    return any((part or {}).get("payload_role") == role for part in item.get("parts") or [])


def has_text_diff(item: dict[str, Any], required: bool | None) -> bool:
    if required is None:
        return True
    value = int(item.get("text_diff_parts") or 0) > 0
    return value is required


def has_active_missing(item: dict[str, Any], required: bool | None) -> bool:
    if required is None:
        return True
    value = int(item.get("active_missing_parts") or 0) > 0
    return value is required


def compact_object(item: dict[str, Any]) -> dict[str, Any]:
    return {
        "full_name": item.get("full_name"),
        "layer": item.get("layer"),
        "extension": item.get("extension"),
        "kind": item.get("kind"),
        "kind_ru": item.get("kind_ru"),
        "name": item.get("name"),
        "synonym": item.get("synonym"),
        "change_state": item.get("change_state"),
        "parts_count": item.get("parts_count"),
        "text_diff_parts": item.get("text_diff_parts"),
        "active_missing_parts": item.get("active_missing_parts"),
        "added_terms": item.get("added_terms") or [],
        "removed_terms": item.get("removed_terms") or [],
        "payload_roles": sorted({
            str((part or {}).get("payload_role"))
            for part in item.get("parts") or []
            if (part or {}).get("payload_role")
        }),
        "parts": [
            {
                "file_name": part.get("file_name"),
                "payload_role": part.get("payload_role"),
                "active_exists": part.get("active_exists"),
                "summary": part.get("summary"),
                "delta_chars": part.get("delta_chars"),
            }
            for part in item.get("parts") or []
            if isinstance(part, dict)
        ],
    }


def build_list(
    report_path: Path,
    *,
    layer: str | None,
    kind: str | None,
    extension: str | None,
    payload_role: str | None,
    active_missing: bool | None,
    text_diff: bool | None,
) -> dict[str, Any]:
    report = load_json(report_path)
    summary = report.get("agent_summary") or {}
    source_items = summary.get("object_changes") or []
    items: list[dict[str, Any]] = []
    for item in source_items:
        if not isinstance(item, dict):
            continue
        if layer and str(item.get("layer") or "").casefold() != layer.casefold():
            continue
        if kind:
            wanted = kind.casefold()
            if str(item.get("kind") or "").casefold() != wanted and str(item.get("kind_ru") or "").casefold() != wanted:
                continue
        if extension and str(item.get("extension") or "").casefold() != extension.casefold():
            continue
        if not has_payload_role(item, payload_role):
            continue
        if not has_active_missing(item, active_missing):
            continue
        if not has_text_diff(item, text_diff):
            continue
        items.append(compact_object(item))

    return {
        "schema": "onec_saved_state_object_change_list.v1",
        "report": str(report_path),
        "database": report.get("database"),
        "filters": {
            "layer": layer,
            "kind": kind,
            "extension": extension,
            "payload_role": payload_role,
            "active_missing": active_missing,
            "text_diff": text_diff,
        },
        "objects": items,
        "system_changes": summary.get("system_changes") or [],
        "counts": {
            "objects": len(items),
            "total_objects": len(source_items),
            "system_changes": len(summary.get("system_changes") or []),
        },
        "safety": {
            "read_only": True,
            "sql_write_performed": False,
            "public_terms_are_1c_objects": True,
        },
    }


def optional_bool(value: str | None) -> bool | None:
    if value is None:
        return None
    normalized = value.strip().casefold()
    if normalized in {"1", "true", "yes", "y", "да"}:
        return True
    if normalized in {"0", "false", "no", "n", "нет"}:
        return False
    raise argparse.ArgumentTypeError(f"Expected boolean value, got: {value}")


def main() -> int:
    parser = argparse.ArgumentParser(description="List changed 1C objects from a saved-state object report.")
    parser.add_argument("--report", type=Path, required=True)
    parser.add_argument("--layer")
    parser.add_argument("--kind")
    parser.add_argument("--extension")
    parser.add_argument("--payload-role")
    parser.add_argument("--active-missing", type=optional_bool)
    parser.add_argument("--text-diff", type=optional_bool)
    parser.add_argument("--output", type=Path)
    args = parser.parse_args()

    result = build_list(
        args.report,
        layer=args.layer,
        kind=args.kind,
        extension=args.extension,
        payload_role=args.payload_role,
        active_missing=args.active_missing,
        text_diff=args.text_diff,
    )
    if args.output:
        write_json(args.output, result)
    print(json.dumps({"output": str(args.output) if args.output else None, "schema": result["schema"], "counts": result["counts"]}, ensure_ascii=False))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
