import typer
import subprocess
import time
import os
import shutil
from pathlib import Path
from typing import Optional
from rich.console import Console
from rich.panel import Panel
from rich.prompt import Confirm
from python_on_whales import DockerClient

app = typer.Typer(help="Reflowfy CLI Tool for easy deployment and management.")
console = Console()
docker = DockerClient()


def get_package_path() -> Path:
    """Get the path to the installed reflowfy package."""
    import reflowfy
    return Path(reflowfy.__file__).parent


def get_helm_chart_path() -> Path:
    """Get path to the bundled Helm chart. Falls back to local ./helm/reflowfy if available."""
    # Priority 1: Local development (./helm/reflowfy)
    local_chart = Path("./helm/reflowfy")
    if local_chart.exists():
        return local_chart
    
    # Priority 2: Bundled in package
    bundled_chart = get_package_path() / "helm" / "reflowfy"
    if bundled_chart.exists():
        return bundled_chart
    
    raise FileNotFoundError(
        "Helm chart not found. Ensure you're in the project root or have installed reflowfy with bundled charts."
    )


def get_dockerfiles_path() -> Path:
    """Get path to Dockerfiles (templates for init or dev source)."""
    # Priority 1: Current directory (Development mode)
    if Path("Dockerfile.api").exists() and Path("pyproject.toml").exists():
        return Path(".")
    
    # Priority 2: Templates bundled in package (Production/Init mode)
    return get_package_path() / "templates"

@app.command()
def build(
    registry: str = typer.Option(..., help="Private registry URL (e.g. registry.lab.local)"),
    project: str = typer.Option("reflowfy", help="Project/Namespace name"),
    push: bool = typer.Option(True, help="Push images to registry after building")
):
    """
    Build and push Reflowfy images to a private registry (OpenShift Ready).
    """
    console.print(Panel(f"Building images for registry: [bold cyan]{registry}[/bold cyan]"))

    images = ["api", "reflow-manager", "worker"]
    
    for svc in images:
        tag = f"{registry}/{project}/{svc}:latest"
        dockerfile = f"Dockerfile.{svc}"
        if svc == "api": # Dockerfile mapping tweak if needed
            dockerfile = "Dockerfile.api"
        elif svc == "reflow-manager":
             dockerfile = "Dockerfile.reflow-manager"
        
        dockerfiles_path = get_dockerfiles_path()
        dockerfile_full = dockerfiles_path / dockerfile
        
        console.print(f"📦 Building [bold]{svc}[/bold] from {dockerfiles_path}...", style="yellow")
        try:
             docker.build(str(dockerfiles_path), file=str(dockerfile_full), tags=[tag])
             console.print(f"✅ Built [bold]{tag}[/bold]", style="green")
             
             if push:
                 console.print(f"🚀 Pushing [bold]{tag}[/bold]...", style="blue")
                 docker.push(tag)
                 console.print(f"✅ Pushed [bold]{tag}[/bold]", style="green")
        except Exception as e:
            console.print(f"❌ Failed to build/push {svc}: {e}", style="red")
            raise typer.Exit(code=1)

    console.print(Panel("🎉 Build & Push Complete!", style="bold green"))


@app.command()
def deploy(
    registry: str = typer.Option(..., help="Registry where images are stored"),
    kafka: str = typer.Option(..., help="External Kafka Broker (host:port)"),
    db_host: Optional[str] = typer.Option(None, help="External DB Host (optional)"),
    namespace: str = typer.Option("reflowfy", help="Kubernetes namespace")
):
    """
    Deploy specific for OpenShift / Red Hat Lab.
    """
    console.print(Panel("Deploying to OpenShift..."))

    # Find Helm chart (bundled or local)
    try:
        chart_path = get_helm_chart_path()
        console.print(f"📦 Using Helm chart at: {chart_path}", style="dim")
    except FileNotFoundError as e:
        console.print(f"❌ {e}", style="red")
        raise typer.Exit(code=1)

    # Construct Helm command
    cmd = [
        "helm", "upgrade", "--install", "reflowfy", str(chart_path),
        "--set", f"global.imageRegistry={registry}",
        "--set", f"kafka.external.bootstrapServers={kafka}",
        "--set", "kafka.enabled=false", # Force external Kafka
        "--set", "api.service.type=ClusterIP",
        "--set", "reflowManager.service.type=ClusterIP"
    ]
    
    if db_host:
         cmd.extend(["--set", f"postgresql.external.host={db_host}", "--set", "postgresql.enabled=false"])

    console.print(f"🔧 Running Helm command...", style="yellow")
    try:
        subprocess.run(cmd, check=True)
        console.print("✅ Helm Upgrade successful", style="green")
    except subprocess.CalledProcessError:
        console.print("❌ Deployment failed", style="red")
        raise typer.Exit(code=1)

    # OpenShift Routes
    console.print("🌐 Creating OpenShift Routes...", style="blue")
    try:
        # Check if route exists, if not create
        subprocess.run(["oc", "expose", "svc/reflowfy-api", "--name=reflowfy-api"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        subprocess.run(["oc", "expose", "svc/reflowfy-reflow-manager", "--name=reflowfy-manager"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        console.print("✅ Routes created/verified", style="green")
    except FileNotFoundError:
        console.print("⚠️ 'oc' command not found. Skipping route creation.", style="yellow")

    console.print(Panel("🚀 Deployment Complete! Use 'oc get routes' to see URLs.", style="bold green"))


@app.command()
def check():
    """
    Verify deployment health.
    """
    console.print("🔍 Checking Pod Status...")
    subprocess.run(["kubectl", "get", "pods", "-l", "app.kubernetes.io/instance=reflowfy"])


@app.command()
def run(
    build: bool = typer.Option(False, "--build", "-b", help="Rebuild images before starting"),
    detach: bool = typer.Option(False, "--detach", "-d", help="Run in background")
):
    """
    Run locally using Docker Compose (Dev Mode).
    """
    console.print(Panel("🚀 Starting Local Development Stack"))
    
    cmd = ["docker-compose", "up"]
    if detach:
        cmd.append("-d")
    if build:
        cmd.append("--build")
        
    try:
        subprocess.run(cmd)
    except KeyboardInterrupt:
        console.print("\n👋 Stopping...")


@app.command()
def init(
    path: str = typer.Argument(".", help="Directory to initialize (defaults to current)"),
    name: str = typer.Option("my_pipeline", help="Name of your first pipeline"),
):
    """
    Initialize a new Reflowfy project with a sample pipeline.
    """
    target_dir = Path(path)
    target_dir.mkdir(parents=True, exist_ok=True)
    
    console.print(Panel(f"📦 Initializing Reflowfy project in: {target_dir.absolute()}"))
    
    # Create pipelines directory
    pipelines_dir = target_dir / "pipelines"
    pipelines_dir.mkdir(exist_ok=True)
    
    # Create sample pipeline
    sample_pipeline = pipelines_dir / f"{name}.py"
    sample_pipeline.write_text(f'''"""
{name} - A sample Reflowfy pipeline
"""
from reflowfy import Pipeline, ListSource, ConsoleDestination

@Pipeline.register("{name}")
def {name}():
    return Pipeline(
        name="{name}",
        source=ListSource(items=[
            {{"id": 1, "name": "Item 1"}},
            {{"id": 2, "name": "Item 2"}},
            {{"id": 3, "name": "Item 3"}},
        ]),
        destination=ConsoleDestination(),
        transformations=[
            # Add your transformations here
        ]
    )
''')
    console.print(f"  ✅ Created pipeline: pipelines/{name}.py", style="green")
    
    # Create __init__.py for pipelines
    (pipelines_dir / "__init__.py").write_text(f"from .{name} import {name}\n")
    console.print(f"  ✅ Created pipelines/__init__.py", style="green")
    
    # Copy Dockerfiles if not present
    try:
        src_path = get_dockerfiles_path()
        for dockerfile in ["Dockerfile.api", "Dockerfile.reflow-manager", "Dockerfile.worker", "docker-compose.yml"]:
            src_file = src_path / dockerfile
            dest_file = target_dir / dockerfile
            if src_file.exists() and not dest_file.exists():
                shutil.copy(src_file, dest_file)
                console.print(f"  ✅ Copied {dockerfile}", style="green")
    except Exception as e:
        console.print(f"  ⚠️ Could not copy Dockerfiles: {e}", style="yellow")
    
    console.print(Panel(f"""
🎉 Project initialized!

Next steps:
  1. cd {target_dir.absolute()}
  2. Edit pipelines/{name}.py to customize your pipeline
  3. reflowfy run --build    (test locally)
  4. reflowfy build --registry <your-registry>
  5. reflowfy deploy --registry <your-registry> --kafka <kafka:9092>
""", style="bold green"))


if __name__ == "__main__":
    app()
