"""Utilities and CLI for importing JSON-LD files into the semantics QuadStore."""

from __future__ import annotations

from pathlib import Path
from typing import List, Optional
import argparse
import os

from .ontology_manager import OntologyManager
from .quad_store import QuadStore
from .semantics_paths import (
    resolve_semantics_db_path,
    resolve_semantics_db_paths,
    resolve_semantics_dir,
)
from .package_discovery import ingest_installed_step_packages


def _select_db_kind(graph_type: str) -> str:
    gtype = str(graph_type or "").lower()
    if gtype == "pipeline":
        return "pipelines"
    if gtype == "step":
        return "steps"
    if gtype in {"pipeline_state", "pipeline_states"}:
        return "pipeline_states"
    return "ontology"


def ingest_jsonld_files(
    paths: List[Path],
    *,
    semantics_dir: Optional[Path] = None,
    graph_type: str = "custom",
    package: str = "custom",
) -> None:
    """
    Ingest JSON-LD files into the DuckDB-backed QuadStore.

    Graph IDs default to the absolute file path. When `graph_type == "step"`, the
    ingester splits per `cf:ProcessingStep` and stores each step under its `@id`.
    """
    base_dir = (semantics_dir or resolve_semantics_dir()).resolve()
    db_kind = _select_db_kind(graph_type)
    db_path = resolve_semantics_db_path(base_dir, kind=db_kind)
    store = QuadStore(db_path=db_path, semantics_dir=base_dir)
    store.init_schema(create_pipeline_tables=db_kind == "pipelines")

    split_steps = graph_type == "step"
    for path in paths:
        graph_id = str(Path(path).resolve())
        store.ingest_jsonld(
            Path(path),
            graph_id=graph_id,
            graph_type=graph_type,
            package=package,
            source_path=str(Path(path).resolve()),
            split_steps=split_steps,
        )


def rebuild_semantics_db(*, semantics_dir: Optional[Path] = None) -> Path:
    """
    Rebuild the semantics DBs from packaged ontology resources (and step packages if enabled).

    This is a destructive operation: it removes the existing DuckDB files.
    """
    base_dir = (semantics_dir or resolve_semantics_dir()).resolve()
    db_paths = resolve_semantics_db_paths(base_dir)
    for path in db_paths.as_dict().values():
        if path.exists():
            path.unlink()

    old_dir = os.environ.get("CF_SEMANTICS_DIR")
    try:
        os.environ["CF_SEMANTICS_DIR"] = str(base_dir)
        OntologyManager()
    finally:
        if old_dir is None:
            os.environ.pop("CF_SEMANTICS_DIR", None)
        else:
            os.environ["CF_SEMANTICS_DIR"] = old_dir

    return db_paths.ontology


def _parse_args(argv: Optional[List[str]] = None) -> argparse.Namespace:
    parser = argparse.ArgumentParser(prog="cf_ontology.ingest")
    source = parser.add_mutually_exclusive_group(required=True)
    source.add_argument(
        "--paths",
        nargs="+",
        help="One or more JSON-LD files to ingest.",
    )
    source.add_argument(
        "--installed-steps",
        action="store_true",
        help="Discover and ingest installed step packages (cogniflow.steps entry points).",
    )
    parser.add_argument(
        "--semantics-dir",
        default=None,
        help="Target semantics directory (defaults to workspace/semantics).",
    )
    parser.add_argument("--graph-type", default="custom", help="Graph type label.")
    parser.add_argument("--package", default="custom", help="Package label.")
    parser.add_argument(
        "--force",
        action="store_true",
        help="Re-ingest even if the stored content hash matches.",
    )
    return parser.parse_args(argv)


def main(argv: Optional[List[str]] = None) -> None:
    """CLI entrypoint for ingesting files or installed step packages."""
    args = _parse_args(argv)
    semantics_dir = Path(args.semantics_dir).expanduser() if args.semantics_dir else None
    if args.installed_steps:
        ingest_installed_step_packages(semantics_dir=semantics_dir, force=bool(args.force))
        return

    ingest_jsonld_files(
        [Path(p) for p in (args.paths or [])],
        semantics_dir=semantics_dir,
        graph_type=str(args.graph_type),
        package=str(args.package),
    )


if __name__ == "__main__":
    main()
