"""Intelligent intake wizard for NIKAME.

3-layer confirmation flow:
1. Domain Mapping (Entities/Relationships)
2. Feature Selection (Infrastructure)
3. Infrastructure Tuning (Credentials/Scale)
"""

from __future__ import annotations

from typing import Any

import click
import questionary

from nikame.cli.commands.domain import DomainUnderstandingEngine
from nikame.config.loader import load_config_from_dict
from nikame.config.schema import (
    AuthConfig,
    CacheConfig,
    DatabasesConfig,
    DataModelConfig,
    FieldConfig,
    MessagingConfig,
    NikameConfig,
    StorageConfig,
)


class NikameWizard:
    """Manages the interactive project setup wizard."""
    def __init__(self, prefilled_answers: dict | None = None, headless: bool = False) -> None:
        self.prefilled_answers = prefilled_answers or {}
        self._headless = headless or bool(self.prefilled_answers)
        # Only initialize the heavy domain engine when interactive
        if not self._headless:
            self.engine = DomainUnderstandingEngine()
        else:
            self.engine = None  # type: ignore[assignment]

    def _ask(self, key: str, default_asker: Any) -> Any:
        """Bypass questionary if key is in prefilled_answers."""
        if key in self.prefilled_answers:
            return self.prefilled_answers[key]
        ans = default_asker.ask()
        if ans is None:
            raise click.Abort()
        return ans

    def run(self) -> NikameConfig:
        """Execute the full wizard flow."""
        click.clear()
        click.secho("🚀 NIKAME V2: Intelligent Project Setup", fg="cyan", bold=True)
        click.echo("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")

        # Layer -1: Project Metadata
        project_name = self._ask("project_name", questionary.text(
            "What is the name of your project?",
            default="nikame-app",
        ))
        
        if not project_name:
             raise click.Abort()

        # Layer 0: One-liner description
        description = self._ask("description", questionary.text(
            "What are you building today?",
            placeholder="e.g., A RAG platform for legal document search with sub-second latency",
        ))

        if not description:
             click.secho("Description required. Exiting.", fg="red")
             raise click.Abort()

        # Run Domain Engine (skip in headless mode to avoid LLM calls)
        if self._headless:
            # Build a minimal config from prefilled entities
            entities = self.prefilled_answers.get("confirmed_entities", ["User"])
            models = {}
            for ent in entities:
                models[ent] = DataModelConfig(
                    fields={
                        "id": FieldConfig(type="int", required=True, unique=True),
                        "name": FieldConfig(type="str", required=True),
                    }
                )
            config = NikameConfig(name=project_name.lower().replace(" ", "-"), models=models)
        else:
            with click.progressbar(length=100, label="Analyzing domain...") as bar:
                config = self.engine.analyze(description)
                config.name = self.engine._sanitize_name(project_name)
                bar.update(100)

        # Layer 1: Domain Mapping (Entities)
        config = self._layer_domain_mapping(config)

        # Layer 2: Feature Selection (Infra)
        config = self._layer_feature_selection(config)

        # Layer 3: Infra Tuning (Credentials handled by CredentialVault later)
        config = self._layer_infra_tuning(config)

        return config

    def resume(self, session: Any) -> NikameConfig:
        """Resume from a WizardSession object directly into Layer 3."""
        # Convert WizardSession to a NikameConfig skeleton
        config = load_config_from_dict(session.to_config_dict() if hasattr(session, 'to_config_dict') else session.model_dump())
        
        # Drop directly to Layer 3 for infra tuning confirmation
        click.secho(f"Resuming {session.name}...", fg="cyan", bold=True)
        return self._layer_infra_tuning(config)

    def _layer_domain_mapping(self, config: NikameConfig) -> NikameConfig:
        """Confirm and refine extracted entities."""
        click.secho("\nLayer 1: Domain Entities", fg="yellow", bold=True)
        
        entities = list(config.models.keys())
        if not entities:
            entities = ["User"] # Default
            
        confirmed_entities = self._ask("confirmed_entities", questionary.checkbox(
            "I detected these core entities. Select the ones you want to keep:",
            choices=[questionary.Choice(e, checked=True) for e in entities],
        ))

        if confirmed_entities is None:
             raise click.Abort()

        # Remove unselected
        for e in list(config.models.keys()):
            if e not in confirmed_entities:
                del config.models[e]

        # Add new ones
        if "new_entities" in self.prefilled_answers:
            for name in self.prefilled_answers["new_entities"]:
                config.models[name] = DataModelConfig(
                    fields={
                        "id": FieldConfig(type="int", required=True, unique=True),
                        "name": FieldConfig(type="str", required=True)
                    }
                )
        else:
            new_entity = True
            while new_entity:
                name = questionary.text("Add another entity (leave blank to continue):").ask()
                if not name:
                    new_entity = False
                else:
                    config.models[name] = DataModelConfig(
                        fields={
                            "id": FieldConfig(type="int", required=True, unique=True),
                            "name": FieldConfig(type="str", required=True)
                        }
                    )
        
        return config

    def _layer_feature_selection(self, config: NikameConfig) -> NikameConfig:
        """Confirm infrastructure components."""
        click.secho("\nLayer 2: Infrastructure Selection", fg="yellow", bold=True)
        
        choices = [
            questionary.Choice("PostgreSQL (Database)", value="postgres", checked=config.databases is not None and config.databases.postgres is not None),
            questionary.Choice("Redis/Dragonfly (Cache)", value="cache", checked=config.cache is not None),
            questionary.Choice("Redpanda/Kafka (Streaming)", value="messaging", checked=config.messaging is not None),
            questionary.Choice("MinIO/S3 (Storage)", value="storage", checked=config.storage is not None),
            questionary.Choice("Qdrant (Vector DB)", value="qdrant", checked=config.databases is not None and config.databases.qdrant is not None),
            questionary.Choice("Authentication (Keycloak/Postgres)", value="auth", checked=config.auth is not None),
        ]

        selected = self._ask("selected_features", questionary.checkbox(
            "Verify your infrastructure stack:",
            choices=choices
        ))

        if selected is None:
            raise click.Abort()

        if "postgres" not in selected: config.databases.postgres = None if config.databases else None
        if "cache" not in selected: config.cache = None
        if "messaging" not in selected: config.messaging = None
        if "storage" not in selected: config.storage = None
        if "qdrant" not in selected and config.databases: config.databases.qdrant = None
        if "auth" not in selected: config.auth = None

        return config

    def _layer_infra_tuning(self, config: NikameConfig) -> NikameConfig:
        """High-level tuning."""
        if self._headless:
            return config

        click.secho("\nLayer 3: Infrastructure Tuning", fg="yellow", bold=True)
        
        env = self._ask("target", questionary.select(
            "Primary deployment target:",
            choices=["local", "kubernetes", "aws", "gcp"],
            default=config.environment.target
        ))
        
        if env:
            config.environment.target = env

        scale = self._ask("scale", questionary.select(
            "Expected scale:",
            choices=["small", "medium", "large"],
            default=config.project.scale
        ))
        
        if scale:
            config.project.scale = scale

        return config
