from __future__ import annotations
import yaml
import typer
from pathlib import Path
from typing import List, Dict, Any, Optional
from rich.console import Console
from pydantic import BaseModel

from sibi_flux.core import SecureResource
from sibi_flux.utils.security import is_valid_identifier, is_valid_module_path
from sibi_flux.init.reader_proposer import AppReaderConfig

console = Console()

class ReaderExtender(SecureResource):
    """
    Generates app-specific Reader extensions from readers.yaml.
    Hardened with SecureResource for sandboxed I/O.
    """
    
    def __init__(self, **kwargs: Any) -> None:
        super().__init__(**kwargs)

    def create_readers(self, domain: str, force: bool = False) -> None:
        """
        Processes the domain's reader blueprint and generates the extension modules.
        """
        # Target generated assets directory
        gen_dir = self.project_root / "_gen" / "assets" / "readers"
        gen_dir.mkdir(parents=True, exist_ok=True)
        if not (gen_dir / "__init__.py").exists():
            (gen_dir / "__init__.py").touch()

        # Configuration from blueprints
        readers_dir = self.project_root / "blueprints" / "readers"
        blueprint_file = readers_dir / f"{domain}.yaml"
        config_path = self.get_secure_path(blueprint_file)
        target_file = self.get_secure_path(gen_dir / f"{domain}.py")

        if not config_path.exists():
            console.print(f"[yellow]Info: No Reader blueprints found for domain '{domain}'.[/yellow]")
            if force and target_file.exists():
                target_file.unlink()
                console.print(f"  [yellow]Cleanup: Deleted stale generated asset {target_file.name}[/yellow]")
            return

        # 1. Load Configuration
        with self.open_secure(config_path, "r") as f:
            raw_data = yaml.safe_load(f) or {}
            config = AppReaderConfig(**raw_data)

        if not config.readers:
            console.print(f"[yellow]Info: Empty Reader list for '{app_name}'.[/yellow]")
            return

        # 2. Generate Python Code
        target_file = self.get_secure_path(gen_dir / f"{domain}.py")
        if target_file.exists() and not force:
            console.print(f"  [yellow]Skipping {target_file.name}: File already exists. Use --force to overwrite.[/yellow]")
            return

        console.print(f"  [blue]Generating readers: {target_file.name} ({len(config.readers)} readers)[/blue]")

        # Build content with hierarchical structure
        domain_prefix = "".join([p.capitalize() for p in domain.split("_") if p])
        domain_base_class = f"{domain_prefix}BaseReader"

        content = [
            "from __future__ import annotations",
            "from sibi_flux.parquet.readers.base import BaseReader",
            "",
            "# --- Base Classes ---",
            "",
            f"class {domain_base_class}(BaseReader):",
            f"    \"\"\"Shared configuration for all {domain_prefix} readers.\"\"\"",
            "    fs_name = \"etl\"",
            "    storage_module_path = \"conf.storage\"",
            "    partition_on = \"partition_date\"",
            ""
        ]

        # Group readers by storage_variable for depot-base class generation
        readers_by_depot = {}
        for r in config.readers:
            if r.storage_variable not in readers_by_depot:
                readers_by_depot[r.storage_variable] = []
            readers_by_depot[r.storage_variable].append(r)

        for storage_var, readers in readers_by_depot.items():
            depot_base_name = storage_var.replace("_storage", "")
            depot_suffix = "".join([p.capitalize() for p in depot_base_name.split("_") if p])
            
            # Avoid redundant names if depot name already includes domain name
            if domain_prefix.lower() in depot_base_name.lower():
                depot_class_name = f"{depot_suffix}BaseReader"
            else:
                depot_class_name = f"{domain_prefix}{depot_suffix}BaseReader"
                
            # Avoid collision with domain_base_class itself
            if depot_class_name == domain_base_class:
                depot_class_name = f"{depot_suffix}DepotBaseReader"

            content.extend([
                f"class {depot_class_name}({domain_base_class}):",
                f"    \"\"\"Base reader for {depot_base_name} storage.\"\"\"",
                f"    storage_variable = \"{storage_var}\"",
                ""
            ])

            content.append(f"# --- {depot_base_name.capitalize()} Readers ---")
            for r in readers:
                # If specific reader name starts with depot prefix, we keep it as is
                # Otherwise it might be redundant
                reader_code = [
                    f"class {r.name}({depot_class_name}):",
                    f"    storage_subpath = \"{r.storage_subpath}\"" if r.storage_subpath else "    pass",
                    ""
                ]
                content.extend(reader_code)

        # Build full content
        self.write_text_secure(target_file, "\n".join(content))
        console.print(f"[green]Successfully generated {target_file.name} for domain '{domain}'.[/green]")

def create_readers(domain: str, force: bool = False) -> None:
    """Entry point for CLI calls."""
    extender = ReaderExtender()
    extender.create_readers(domain, force=force)
