from __future__ import annotations

from pathlib import Path
from typing import Any, Dict, List, Literal

from pydantic import BaseModel, ConfigDict, Field
from sync_state_machine.config import (
    JsonlDataSourceConfig,
    DataSourceConfig,
    PersistConfig,
    LoggingConfig,
    build_config,
    list_preset_names,
    load_named_preset_overrides,
    load_overrides_from_file,
)


PROJECT_ROOT = Path(__file__).resolve().parents[1]

DEFAULT_NODE_TYPES: List[str] = [
    "company",
    "supplier",
    "user",
    "project",
    "contract",
    "contract_change",
    "construction_task",
    "construction_task_detail",
    "material",
    "material_detail",
    "contract_settlement",
    "contract_settlement_detail",
    "personnel",
    "personnel_detail",
    "preparation",
    "production",
    "lar",
    "units",
]


class PipelineUiConfig(BaseModel):
    model_config = ConfigDict(extra="forbid", validate_assignment=True)

    mode: Literal["jsonl_to_jsonl", "jsonl_to_api"] = "jsonl_to_jsonl"

    node_types: List[str] = Field(default_factory=lambda: list(DEFAULT_NODE_TYPES))

    local_datasource: DataSourceConfig = Field(
        default_factory=lambda: JsonlDataSourceConfig(
            type="jsonl",
            jsonl_dir=str(PROJECT_ROOT / "filtered_datasource" / "datasource" / "ecm-2025-12-02"),
        )
    )
    remote_datasource: DataSourceConfig = Field(
        default_factory=lambda: JsonlDataSourceConfig(
            type="jsonl",
            jsonl_dir=str(PROJECT_ROOT / "remote_datasource" / "datasource"),
        )
    )

    persist: PersistConfig = Field(
        default_factory=lambda: PersistConfig(
            db_path=str(PROJECT_ROOT / "test_results" / "sync_state_machine" / "ui_pipeline.db"),
            enable=True,
            wipe_on_start=False,
        )
    )
    logging: LoggingConfig = Field(default_factory=LoggingConfig)

    strategies: Dict[str, Dict[str, Any]] = Field(default_factory=dict)


def default_ui_config() -> PipelineUiConfig:
    return preset_ui_config("simple_sm")


def list_ui_presets() -> List[str]:
    return list_preset_names()


def preset_ui_config(preset_name: str) -> PipelineUiConfig:
    overrides, _, _ = load_named_preset_overrides(PROJECT_ROOT, preset_name)
    run_cfg = build_config(project_root=PROJECT_ROOT, overrides=overrides)
    mode: Literal["jsonl_to_jsonl", "jsonl_to_api"] = (
        "jsonl_to_api" if getattr(run_cfg.remote_datasource, "type", "jsonl") == "api" else "jsonl_to_jsonl"
    )

    strategies: Dict[str, Dict[str, Any]] = {}
    for runtime in run_cfg.strategies:
        item: Dict[str, Any] = {
            "config": runtime.config.model_dump(),
        }
        strategies[runtime.node_type] = item

    return PipelineUiConfig(
        mode=mode,
        node_types=list(run_cfg.node_types),
        local_datasource=run_cfg.local_datasource.model_copy(deep=True),
        remote_datasource=run_cfg.remote_datasource.model_copy(deep=True),
        persist=run_cfg.persist.model_copy(deep=True),
        logging=run_cfg.logging.model_copy(deep=True),
        strategies=strategies,
    )


def file_ui_config(config_file: str) -> PipelineUiConfig:
    path = Path(config_file)
    if not path.is_absolute():
        path = PROJECT_ROOT / path
    path = path.resolve()

    if not path.exists() or not path.is_file():
        raise FileNotFoundError(f"Config file not found: {path}")

    overrides = load_overrides_from_file(path, PROJECT_ROOT)
    run_cfg = build_config(project_root=PROJECT_ROOT, overrides=overrides)
    mode: Literal["jsonl_to_jsonl", "jsonl_to_api"] = (
        "jsonl_to_api" if getattr(run_cfg.remote_datasource, "type", "jsonl") == "api" else "jsonl_to_jsonl"
    )

    strategies: Dict[str, Dict[str, Any]] = {}
    for runtime in run_cfg.strategies:
        item: Dict[str, Any] = {
            "config": runtime.config.model_dump(),
        }
        strategies[runtime.node_type] = item

    return PipelineUiConfig(
        mode=mode,
        node_types=list(run_cfg.node_types),
        local_datasource=run_cfg.local_datasource.model_copy(deep=True),
        remote_datasource=run_cfg.remote_datasource.model_copy(deep=True),
        persist=run_cfg.persist.model_copy(deep=True),
        logging=run_cfg.logging.model_copy(deep=True),
        strategies=strategies,
    )
