#!/usr/bin/env python3
"""Run the full 1C SQL read-view pipeline for one metadata object."""

from __future__ import annotations

import argparse
import base64
import json
import os
import hashlib
import subprocess
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 resolve_object  # noqa: E402


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


def find_metadata(summary_path: Path, *, kind: str, name: str) -> Path | None:
    summary = load_json(summary_path)
    matches = [
        row
        for row in summary.get("outputs") or []
        if str(row.get("kind") or "").casefold() == kind.casefold()
        and str(row.get("name") or "").casefold() == name.casefold()
    ]
    if not matches:
        return None
    if len(matches) > 1:
        raise SystemExit(f"Ambiguous metadata object in {summary_path}: {kind}.{name}")
    return Path(matches[0]["output"])


def safe_name(value: str) -> str:
    keep = []
    for char in value:
        if char.isascii() and (char.isalnum() or char in ("-", "_")):
            keep.append(char)
        else:
            keep.append(f"u{ord(char):04x}")
    result = "".join(keep).strip("-")
    digest = hashlib.sha1(value.encode("utf-8")).hexdigest()[:8]
    if len(result) > 48:
        result = result[:48].rstrip("-_")
    return f"{result or 'object'}-{digest}"


def run(command: list[str], *, env: dict[str, str] | None = None) -> None:
    printable = " ".join(command)
    print(printable, flush=True)
    completed = subprocess.run(command, env=env)
    if completed.returncode != 0:
        raise SystemExit(completed.returncode)


def powershell_exe() -> str:
    return os.environ.get("POWERSHELL_EXE") or "powershell"


def main() -> int:
    parser = argparse.ArgumentParser(description="Build a 1C SQL read view by kind/name.")
    parser.add_argument("--kind")
    parser.add_argument("--name")
    parser.add_argument("--kind-b64", help="UTF-8 base64 encoded kind.")
    parser.add_argument("--name-b64", help="UTF-8 base64 encoded name.")
    parser.add_argument("--top", type=int, default=5)
    parser.add_argument("--view", choices=["effective", "base", "extension"], default="effective")
    parser.add_argument("--extension")
    parser.add_argument("--summary", type=Path, required=True)
    parser.add_argument("--validation", type=Path, required=True)
    parser.add_argument("--route-index", type=Path, required=True)
    parser.add_argument("--enum-presentation-map", type=Path)
    parser.add_argument("--output-dir", type=Path, required=True)
    parser.add_argument("--server", default=os.environ.get("ONEC_SQL_SERVER"))
    parser.add_argument("--database", default=os.environ.get("ONEC_SQL_DATABASE"))
    parser.add_argument("--user", default=os.environ.get("ONEC_SQL_USER"))
    parser.add_argument("--password", default=os.environ.get("ONEC_SQL_PASSWORD"))
    args = parser.parse_args()

    if args.kind_b64:
        args.kind = base64.b64decode(args.kind_b64).decode("utf-8")
    if args.name_b64:
        args.name = base64.b64decode(args.name_b64).decode("utf-8")
    if not args.kind or not args.name:
        raise SystemExit("Use --kind/--name or --kind-b64/--name-b64.")
    if args.view == "extension" and not args.extension:
        raise SystemExit("Use --extension with --view extension.")

    missing = [name for name in ("server", "database", "user", "password") if not getattr(args, name)]
    if missing:
        raise SystemExit(f"Missing SQL connection settings: {', '.join(missing)}")

    route_index = load_json(args.route_index)
    resolution = resolve_object(route_index, kind=args.kind, name=args.name, limit=50)
    canonical = resolution.get("canonical")
    if not canonical:
        raise SystemExit(f"Object not found: {args.kind}.{args.name}")
    args.kind = str(canonical["kind"])
    args.name = str(canonical["name"])

    prefix = f"{safe_name(args.kind)}-{safe_name(args.name)}"
    args.output_dir.mkdir(parents=True, exist_ok=True)
    metadata_path = args.output_dir / f"metadata-{prefix}.json"
    metadata = build_metadata(route_index, kind=args.kind, name=args.name)
    metadata_path.write_text(json.dumps(metadata, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")

    projection_path = args.output_dir / f"sql-read-projection-{prefix}.json"
    read_result_path = args.output_dir / f"sql-read-result-{prefix}.json"
    reference_path = args.output_dir / f"sql-reference-resolution-{prefix}.json"
    composite_path = args.output_dir / f"sql-composite-reference-resolution-{prefix}.json"
    composite_value_path = args.output_dir / f"sql-composite-value-resolution-{prefix}.json"
    enum_map_path = args.enum_presentation_map or args.output_dir / "enum-presentation-map.json"
    view_path = args.output_dir / f"sql-read-view-{prefix}.json"

    python = sys.executable
    ps_env = os.environ.copy()
    ps_env.update(
        {
            "ONEC_SQL_SERVER": args.server,
            "ONEC_SQL_DATABASE": args.database,
            "ONEC_SQL_USER": args.user,
            "ONEC_SQL_PASSWORD": args.password,
        }
    )

    run(
        [
            python,
            "plugins/1c/tools/build_sql_read_projection.py",
            "--metadata",
            str(metadata_path),
            "--validation",
            str(args.validation),
            "--output",
            str(projection_path),
            "--top",
            str(args.top),
            "--view",
            args.view,
        ]
        + (["--extension", args.extension] if args.extension else [])
    )
    run(
        [
            powershell_exe(),
            "-NoProfile",
            "-ExecutionPolicy",
            "Bypass",
            "-File",
            "scripts/execute_1c_sql_read_projection.ps1",
            "-ProjectionPath",
            str(projection_path),
            "-OutputPath",
            str(read_result_path),
        ],
        env=ps_env,
    )
    run(
        [
            powershell_exe(),
            "-NoProfile",
            "-ExecutionPolicy",
            "Bypass",
            "-File",
            "scripts/resolve_1c_sql_read_references.ps1",
            "-ReadResultPath",
            str(read_result_path),
            "-RouteIndexPath",
            str(args.route_index),
            "-OutputPath",
            str(reference_path),
        ],
        env=ps_env,
    )
    run(
        [
            powershell_exe(),
            "-NoProfile",
            "-ExecutionPolicy",
            "Bypass",
            "-File",
            "scripts/resolve_1c_sql_composite_references.ps1",
            "-ReadResultPath",
            str(read_result_path),
            "-RouteIndexPath",
            str(args.route_index),
            "-OutputPath",
            str(composite_path),
        ],
        env=ps_env,
    )
    run(
        [
            python,
            "scripts/resolve_1c_sql_composite_values.py",
            "--read-result",
            str(read_result_path),
            "--output",
            str(composite_value_path),
        ]
    )
    if not enum_map_path.is_file():
        run(
            [
                python,
                "scripts/build_1c_enum_presentation_map.py",
                "--index",
                str(args.route_index),
                "--output",
                str(enum_map_path),
            ]
        )
    run(
        [
            python,
            "scripts/build_1c_sql_read_view.py",
            "--read-result",
            str(read_result_path),
            "--reference-resolution",
            str(reference_path),
            "--composite-reference-resolution",
            str(composite_path),
            "--composite-value-resolution",
            str(composite_value_path),
            "--enum-presentation-map",
            str(enum_map_path),
            "--output",
            str(view_path),
        ]
    )

    view = load_json(view_path)
    print(
        json.dumps(
            {
                "schema": "onec_sql_read_object_view_run.v1",
                "kind": args.kind,
                "name": args.name,
                "requested_view": args.view,
                "extension": args.extension,
                "resolution": {
                    "schema": resolution.get("schema"),
                    "canonical": canonical,
                    "summary": resolution.get("summary"),
                },
                "metadata": str(metadata_path),
                "projection": str(projection_path),
                "read_result": str(read_result_path),
                "reference_resolution": str(reference_path),
                "composite_reference_resolution": str(composite_path),
                "composite_value_resolution": str(composite_value_path),
                "enum_presentation_map": str(enum_map_path),
                "view_path": str(view_path),
                "summary": view.get("summary"),
            },
            ensure_ascii=True,
            indent=2,
        ),
        flush=True,
    )
    return 0


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