import sys
import os
import typer
from pathlib import Path
import yaml

# Ensure project root and src are in sys.path
if os.getcwd() not in sys.path:
    sys.path.insert(0, os.getcwd())
sys.path.insert(0, os.path.join(os.getcwd(), "src"))

from typing import List, Optional, Any
from pydantic import BaseModel, ConfigDict, Field
from sibi_flux.datacube.cli import app, set_context_defaults

# --- Nested Configuration Models ---


class DefaultsConfig(BaseModel):
    base_datacube_class: str = "Datacube"
    base_import: str = "sibi_flux:Datacube"
    backend: str = "sqlalchemy"
    class_suffix: str = "Dc"
    env_file: str = ".env.linux"


class GenerationConfig(BaseModel):
    enable_field_maps: bool = True
    fields_subpackage: str = "fields"
    exclusions: List[str] = Field(default_factory=list)


class TargetPaths(BaseModel):
    datacubes_dir: str
    field_maps_dir: str


class RepositoryPaths(BaseModel):
    # global_field_repository_file: str # Used by generator logic, validated via extra=ignore if needed or explicit
    global_field_repository_file: str
    global_field_translations_file: str
    global_datacube_registry_file: str = "datacube_registry.yaml"


class DiscoveryPaths(BaseModel):
    all_tables_file: str = "all_tables.yaml"
    rules_file: str = "discovery_rules.yaml"
    whitelist_file: str = "whitelist.yaml"


class PathsConfig(BaseModel):
    target: TargetPaths
    repositories: RepositoryPaths
    discovery: DiscoveryPaths
    # global_datacube_registry_file: str = "datacube_registry.yaml" # Moved to repositories


class LocalizationDefault(BaseModel):
    source_lang: str = "es"
    target_lang: str = "en"


class LocalizationConfig(BaseModel):
    default: LocalizationDefault


class ImportSpec(BaseModel):
    module: str
    symbol: str


class DatabaseConfig(BaseModel):
    id: str
    connection_ref: str
    db_domain: str
    import_spec: ImportSpec


class DiscoveryParamConfig(BaseModel):
    defaults: DefaultsConfig
    generation: GenerationConfig
    paths: PathsConfig
    # discovery: DiscoveryConfig # Moved to paths.discovery
    localization: LocalizationConfig
    databases: List[DatabaseConfig] = Field(default_factory=list)

    model_config = ConfigDict(extra="ignore")


if __name__ == "__main__":
    # Inject Solutions Defaults

    # Load and merge YAML files from project's conf/ directory
    generators_dir = Path(__file__).parent
    project_root = generators_dir.parent.parent.parent
    conf_dir = project_root / "conf"
    
    raw_params = {}
    config_files = ["discovery_params.yaml", "databases.yaml", "storage.yaml", "osmnx.yaml", "api.yaml"]
    
    for filename in config_files:
        path = conf_dir / filename
        if path.exists():
            with open(path, "r") as f:
                content = yaml.safe_load(f) or {}
                raw_params.update(content)

    try:
        # Validate Configuration
        config = DiscoveryParamConfig(**raw_params)

        # Resolve Paths
        # Note: registry file is commonly relative to the gen_dc.py or project root.
        # Now assuming relative to project root as per new config structure
        DEFAULT_CONFIG = Path(config.paths.repositories.global_datacube_registry_file)
        FIELD_REGISTRY_YAML = Path(
            config.paths.repositories.global_field_translations_file
        )

        # Project Root is 2 levels up from generators/datacubes/ (where this file typically lives)
        project_root = generators_dir.parent.parent

        # Helper for resolution
        def resolve_project_path(rel_path):
            if rel_path and not Path(rel_path).is_absolute():
                return str((project_root / rel_path).resolve())
            return rel_path

        # Resolve Discovery Paths (New Location: paths.discovery)
        if "paths" in raw_params and "discovery" in raw_params["paths"]:
            disc = raw_params["paths"]["discovery"]
            for key in ["whitelist_file", "rules_file", "all_tables_file"]:
                if key in disc:
                    disc[key] = resolve_project_path(disc[key])

        # Resolve Target Paths to Absolute (relative to Project Root)
        if "paths" in raw_params:
            if "target" in raw_params["paths"]:
                target = raw_params["paths"]["target"]
                for key in ["datacubes_dir", "field_maps_dir"]:
                    if key in target:
                        rel_path = target[key]
                        if rel_path and not Path(rel_path).is_absolute():
                            abs_path = (project_root / rel_path).resolve()
                            target[key] = str(abs_path)

            # Resolve Repositories (New Home for Registry)
            if "repositories" in raw_params["paths"]:
                repos = raw_params["paths"]["repositories"]
                for key in [
                    "global_field_repository_file",
                    "global_field_translations_file",
                    "global_datacube_registry_file",
                ]:
                    if key in repos:
                        rel = repos[key]
                        if rel and not Path(rel).is_absolute():
                            repos[key] = str((project_root / rel).resolve())

        # Map `id` -> `name` and `connection_ref` -> `connection_obj` for CLI compatibility
        if "databases" in raw_params:
            for db in raw_params["databases"]:
                if "id" in db and "name" not in db:
                    db["name"] = db["id"]
                if "connection_ref" in db and "connection_obj" not in db:
                    db["connection_obj"] = db["connection_ref"]
                # Also ensure global_import is present if import_spec is used
                if "import_spec" in db and "global_import" not in db:
                    spec = db["import_spec"]
                    db["global_import"] = (
                        f"from {spec['module']} import {spec['symbol']}"
                    )

        set_context_defaults(
            default_config=DEFAULT_CONFIG,
            field_translations_file=FIELD_REGISTRY_YAML,
            valid_paths=[config.paths.target.datacubes_dir],
            valid_fieldmap_paths=[config.paths.target.field_maps_dir],
            params=raw_params,
        )
        app()
    except Exception as e:
        # Print valid error message and exit
        typer.echo(f"Configuration Error in {generators_dir}:")
        typer.echo(e)
        # Import traceback to print full stack trace for debugging if needed, but simple error is usually enough for config

        sys.exit(1)
