#!/usr/bin/env python3
"""Return agent-facing 1C object metadata for base/effective/extension views."""

from __future__ import annotations

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

sys.path.insert(0, str(Path(__file__).resolve().parent))
from build_1c_metadata_from_resolved_object import build_metadata  # noqa: E402
from resolve_1c_object import load_json  # noqa: E402


def decode_arg(value: str | None, encoded: str | None) -> str | None:
    if encoded:
        return base64.b64decode(encoded).decode("utf-8")
    return value


def ru_types(value_type: dict[str, Any] | None) -> list[str]:
    if not value_type:
        return []
    presentation = value_type.get("presentation") or {}
    return list(presentation.get("ru") or value_type.get("types") or [])


def canonical_types(value_type: dict[str, Any] | None) -> list[str]:
    if not value_type:
        return []
    return list(value_type.get("types") or [])


def attribute_payload(
    item: dict[str, Any],
    *,
    action: str,
    origin: dict[str, Any],
    value_type: dict[str, Any] | None = None,
    include_storage: bool,
    extra: dict[str, Any] | None = None,
) -> dict[str, Any]:
    vt = value_type if value_type is not None else item.get("value_type")
    payload: dict[str, Any] = {
        "name": item.get("name"),
        "synonym": item.get("synonym"),
        "type": ", ".join(ru_types(vt)),
        "types": ru_types(vt),
        "canonical_types": canonical_types(vt),
        "is_composite": bool((vt or {}).get("is_composite")),
        "uuid": item.get("uuid"),
        "origin": origin,
        "effective_action": action,
    }
    if include_storage:
        payload["storage"] = {
            "storage_routes": item.get("storage_routes") or [],
            "physical_columns": item.get("physical_columns") or [],
        }
    if extra:
        payload.update(extra)
    return payload


def effective_attributes(metadata: dict[str, Any], *, include_storage: bool) -> list[dict[str, Any]]:
    result = []
    for item in metadata.get("attributes") or []:
        source = item.get("source") or "base"
        extension_name = item.get("extension_name")
        if source == "extension":
            origin = {"layer": "extension", "extension": extension_name}
            action = "added"
        elif item.get("extension_overrides"):
            origin = {"layer": "base+extension", "extensions": sorted({row.get("extension_name") for row in item.get("extension_overrides") or [] if row.get("extension_name")})}
            action = "modified"
        else:
            origin = {"layer": "base"}
            action = "base"
        result.append(attribute_payload(item, action=action, origin=origin, include_storage=include_storage))
    return result


def base_attributes(metadata: dict[str, Any], *, include_storage: bool) -> list[dict[str, Any]]:
    result = []
    for item in metadata.get("attributes") or []:
        if (item.get("source") or "base") != "base":
            continue
        vt = item.get("base_value_type") or item.get("value_type")
        extra = {}
        if item.get("base_value_type"):
            extra["effective_type"] = ", ".join(ru_types(item.get("value_type")))
            extra["effective_canonical_types"] = canonical_types(item.get("value_type"))
        result.append(
            attribute_payload(
                item,
                action="base",
                origin={"layer": "base"},
                value_type=vt,
                include_storage=include_storage,
                extra=extra,
            )
        )
    return result


def extension_attributes(metadata: dict[str, Any], *, extension: str, include_storage: bool) -> list[dict[str, Any]]:
    result = []
    for item in metadata.get("attributes") or []:
        if (item.get("source") == "extension") and item.get("extension_name") == extension:
            result.append(
                attribute_payload(
                    item,
                    action="added",
                    origin={"layer": "extension", "extension": extension},
                    include_storage=include_storage,
                )
            )
        for override in item.get("extension_overrides") or []:
            if override.get("extension_name") != extension:
                continue
            result.append(
                attribute_payload(
                    item,
                    action="modified",
                    origin={"layer": "extension", "extension": extension},
                    value_type=override.get("value_type") or item.get("value_type"),
                    include_storage=include_storage,
                    extra={
                        "base_uuid": item.get("uuid"),
                        "overlay_uuid": override.get("uuid"),
                        "base_type": ", ".join(ru_types(item.get("base_value_type") or item.get("value_type"))),
                        "base_canonical_types": canonical_types(item.get("base_value_type") or item.get("value_type")),
                        "object_belonging": override.get("object_belonging"),
                        "extended_configuration_object": override.get("extended_configuration_object"),
                        "source_path": override.get("path"),
                    },
                )
            )
    return result


def section_payload(item: dict[str, Any], *, include_storage: bool) -> dict[str, Any]:
    payload = {
        "name": item.get("name"),
        "synonym": item.get("synonym"),
        "uuid": item.get("uuid"),
        "origin": {"layer": item.get("source") or "base"},
    }
    if include_storage:
        payload["storage"] = {
            "storage_routes": item.get("storage_routes") or [],
            "physical_tables": item.get("physical_tables") or [],
        }
    return payload


def build_object_metadata(
    index: dict[str, Any],
    *,
    kind: str,
    name: str,
    view: str,
    extension: str | None,
    include_storage: bool,
) -> dict[str, Any]:
    metadata = build_metadata(index, kind=kind, name=name)
    identity = metadata.get("identity") or {}
    if view == "effective":
        attributes = effective_attributes(metadata, include_storage=include_storage)
    elif view == "base":
        attributes = base_attributes(metadata, include_storage=include_storage)
    elif view == "extension":
        if not extension:
            raise SystemExit("Use --extension with --view extension.")
        attributes = extension_attributes(metadata, extension=extension, include_storage=include_storage)
    else:
        raise SystemExit(f"Unsupported view: {view}")

    tabular_sections = [section_payload(item, include_storage=include_storage) for item in metadata.get("tabular_sections") or []]
    if view == "extension":
        # Section overlays are not merged yet; keep this explicit instead of
        # pretending extension-only tabular sections were analyzed.
        tabular_sections = []

    result = {
        "schema": "onec_object_metadata.v1",
        "view": view,
        "extension": extension if view == "extension" else None,
        "object": {
            "kind": metadata.get("kind"),
            "name": identity.get("name"),
            "synonym": (identity.get("synonyms") or {}).get("ru"),
            "uuid": identity.get("guid"),
        },
        "attributes": attributes,
        "tabular_sections": tabular_sections,
        "effective_metadata": metadata.get("effective_metadata"),
        "resolution": metadata.get("resolution"),
        "counts": {
            "attributes": len(attributes),
            "tabular_sections": len(tabular_sections),
        },
        "diagnostics": {
            "source_schema": metadata.get("schema"),
            "storage_included": include_storage,
            "extension_section_merge": "not_implemented" if view == "extension" else "base_sections_returned",
        },
    }
    return result


def main() -> int:
    parser = argparse.ArgumentParser(description="Get agent-facing 1C object metadata.")
    parser.add_argument("--index", type=Path, required=True)
    parser.add_argument("--kind")
    parser.add_argument("--name")
    parser.add_argument("--kind-b64")
    parser.add_argument("--name-b64")
    parser.add_argument("--view", choices=["effective", "base", "extension"], default="effective")
    parser.add_argument("--extension")
    parser.add_argument("--include-storage", action="store_true")
    parser.add_argument("--output", type=Path)
    args = parser.parse_args()

    kind = decode_arg(args.kind, args.kind_b64)
    name = decode_arg(args.name, args.name_b64)
    if not kind or not name:
        raise SystemExit("Use --kind/--name or --kind-b64/--name-b64.")

    result = build_object_metadata(
        load_json(args.index),
        kind=kind,
        name=name,
        view=args.view,
        extension=args.extension,
        include_storage=args.include_storage,
    )
    text = json.dumps(result, ensure_ascii=False, indent=2) + "\n"
    if args.output:
        args.output.parent.mkdir(parents=True, exist_ok=True)
        args.output.write_text(text, encoding="utf-8")
        print(json.dumps({"output": str(args.output), "counts": result["counts"], "view": result["view"]}, ensure_ascii=False))
    else:
        print(text)
    return 0


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