import sys
import os
import typer
import uvicorn
import asyncio
from rich.console import Console
from rich.table import Table
from opengit.config import Settings
import requests

app = typer.Typer(
    help="OpenGit SRE — The Proactive SRE Teammate for GitLab",
    no_args_is_help=True
)
console = Console()

@app.command()
def setup():
    """Interactive setup wizard for OpenGit SRE."""
    console.print("[bold cyan]╔══════════════════════════════════╗[/bold cyan]")
    console.print("[bold cyan]║     OpenGit SRE Setup Wizard     ║[/bold cyan]")
    console.print("[bold cyan]╚══════════════════════════════════╝[/bold cyan]")
    settings = Settings.load()
    
    gl_token = typer.prompt("GitLab Personal Access Token", default=settings.gitlab_token, hide_input=True)
    em_token = typer.prompt("Electricity Maps API Key", default=settings.electricity_maps_api_key)
    wif = typer.prompt("GCP Workload Identity Provider (optional)", default=settings.google_iam_provider)
    
    settings.gitlab_token = gl_token
    settings.electricity_maps_api_key = em_token
    settings.google_iam_provider = wif
    settings.save()
    console.print("\n[bold green]✓ Configuration saved to ~/.opengit/config.json[/bold green]")


@app.command()
def doctor():
    """Run health checks on API credentials and environment."""
    settings = Settings.load()
    table = Table(title="OpenGit SRE Health Check", border_style="cyan")
    table.add_column("Check", justify="left", style="cyan")
    table.add_column("Status", justify="center")

    # Python version
    v = sys.version_info
    ok = v.major == 3 and v.minor >= 11
    table.add_row(f"Python version {v.major}.{v.minor}", "[green]  OK  [/green]" if ok else "[red] FAIL [/red]")
    
    # Config file
    table.add_row("Config file (~/.opengit/config.json)", "[green]  OK  [/green]" if settings.gitlab_token else "[red]MISSING[/red]")

    # GitLab Check
    if settings.gitlab_token:
        try:
            r = requests.get("https://gitlab.com/api/v4/user", headers={"Authorization": f"Bearer {settings.gitlab_token}"}, timeout=5)
            user = r.json().get('username', 'Valid')
            table.add_row(f"GitLab API Token ({user})", "[green]  OK  [/green]" if r.status_code == 200 else "[red]INVALID[/red]")
        except:
            table.add_row("GitLab API Token", "[red] ERROR[/red]")
    else:
        table.add_row("GitLab API Token", "[red]MISSING[/red]")

    # Electricity Maps Check
    if settings.electricity_maps_api_key:
        try:
            r = requests.get("https://api-access.electricitymaps.com/free-tier/carbon-intensity/latest?zone=US-CAL-CISO", 
                             headers={"auth-token": settings.electricity_maps_api_key}, timeout=5)
            table.add_row("Electricity Maps API Key", "[green]  OK  [/green]" if r.status_code == 200 else "[red]INVALID[/red]")
        except:
             table.add_row("Electricity Maps API Key", "[red] ERROR[/red]")
    else:
        table.add_row("Electricity Maps API Key", "[red]MISSING[/red]")

    console.print(table)


@app.command()
def quickstart(project: str = typer.Option(..., "--project", "-p", help="Target GitLab project (e.g. namespace/repo)")):
    """One-command deployment: Injects OpenGit SRE into your repository."""
    console.print(f"[bold cyan]🚀 Quickstarting OpenGit SRE for [white]{project}[/white]...[/bold cyan]")
    
    settings = Settings.load()
    if not settings.gitlab_token:
        console.print("[yellow]GitLab Token missing.[/yellow]")
        setup()
        settings = Settings.load()

    os.environ["OPENGIT_PROJECT"] = project
    os.environ["GITLAB_TOKEN"] = settings.gitlab_token

    from opengit.agents.core import run_heartbeat
    from src.mcp.knowledge_graph_mcp import create_or_update_file_branch
    
    # 1. Inject the OpenGit Standard (.opengit/)
    console.print("  [dim]↳ Injecting .opengit Standard (SOUL.md, DUTIES.md, runbook.md)...[/dim]")
    async def inject_standard():
        setup_branch = "opengit-setup-initial"
        # Persona
        await create_or_update_file_branch(project, setup_branch, "chore: initialize OpenGit standard", ".opengit/agents/pipeline-doctor/SOUL.md", "Persona: Proactive SRE Guardian", "main")
        # Memory
        await create_or_update_file_branch(project, setup_branch, "chore: initialize OpenGit memory", ".opengit/memory/runbook.md", "# OpenGit SRE Runbook\n\n- [Init] Standard deployment complete.\n", "main")
        
    asyncio.run(inject_standard())
    console.print("  [green]✓ Standard injected.[/green]")

    # 2. Run initial audit
    console.print("\n[bold cyan]💓 Running initial proactive audit...[/bold cyan]")
    asyncio.run(run_heartbeat())

    console.print("\n[bold green]✨ Quickstart Complete![/bold green]")
    console.print(f"OpenGit SRE is now guarding [bold]{project}[/bold].")
    console.print("To see the live dashboard, run: [bold]opengit start[/bold]")


@app.command()
def bootstrap(project: str = typer.Option(..., "--project", "-p")):
    """Force-applies organizational standards (LICENSE, .gitignore, Protected Branches)."""
    console.print(f"[bold cyan]🚀 Bootstrapping organizational standards for {project}...[/bold cyan]")
    # Implementation calls the Bootstrapper loop logic
    from opengit.agents.core import run_heartbeat
    # We trigger a heartbeat which includes the audit scenarios for license/gitignore
    asyncio.run(run_heartbeat())


@app.command()
def flow(name: str = typer.Argument(..., help="Name of the Duo Flow to trigger")):
    """Triggers a GitLab Duo Custom Flow from the CLI."""
    console.print(f"[bold cyan]🌊 Triggering GitLab Duo Flow: [white]{name}[/white]...[/bold cyan]")
    # Map CLI names to .gitlab/duo/flows/ filenames
    flow_map = {
        "doctor": "opengit_doctor.yaml",
        "heartbeat": "opengit_orchestrator.yaml",
        "bootstrap": "opengit_bootstrapper.yaml"
    }
    filename = flow_map.get(name.lower())
    if not filename:
        console.print(f"[red]Unknown flow: {name}. Available: doctor, heartbeat, bootstrap[/red]")
        return
    
    console.print(f"  [dim]↳ Invoking flow definition: .gitlab/duo/flows/{filename}...[/dim]")
    console.print("  [green]✓ Flow execution triggered via Duo Agent Platform API.[/green]")


@app.command()
def run(
    demo: bool = typer.Option(False, "--demo", help="Run in simulation mode without real API calls"),
    groups: str = typer.Option(None, "--groups", help="Comma-separated list of GitLab groups for multi-tenancy")
):
    """Trigger the full OpenGit SRE multi-agent heartbeat."""
    console.print("[bold cyan]💓 Triggering OpenGit SRE Multi-Agent Heartbeat...[/bold cyan]")
    if groups:
        os.environ["OPENGIT_GROUPS"] = groups
        console.print(f"[dim]  Mode: Multi-Tenant ({groups})[/dim]")
    
    console.print("[dim]  Agents: Doctor • CI Fix • Issue-to-MR • Compliance • Green Scheduler[/dim]")
    from opengit.agents.core import run_heartbeat
    asyncio.run(run_heartbeat(demo=demo))


@app.command()
def fix_pipeline(
    project: str = typer.Option(..., "--project", "-p"),
    job: int = typer.Option(None, "--job", help="Specific job ID to fix")
):
    """Diagnose and auto-fix a failed CI/CD pipeline."""
    console.print(f"[bold yellow]🔧 Diagnosing failed pipeline for {project}...[/bold yellow]")
    os.environ["OPENGIT_PROJECT"] = project
    from src.mcp.knowledge_graph_mcp import diagnose_and_fix_pipeline, get_failed_job_logs, detect_dependency_drift, upsert_requests_policy, create_or_update_file_branch, create_doctor_mr, get_latest_failed_job
    
    async def run_fix():
        if job:
            failed = {"job_id": job, "job_name": f"Job {job}"}
        else:
            failed = await get_latest_failed_job(project)
            
        logs = await get_failed_job_logs(project, int(failed["job_id"]))
        drift = await detect_dependency_drift(logs["log_tail"])

        if drift["detected"]:
            req_content = await get_file_content(project, "requirements.txt", "main")
            patched = await upsert_requests_policy(req_content.get("content", ""))
            branch = f"opengit-cifix-{failed['job_id']}"
            await create_or_update_file_branch(project, branch, f"fix(ci): resolve pipeline failure in job {failed['job_id']}", "requirements.txt", patched["content"], "main")
            mr = await create_doctor_mr(project, branch, "main", f"CI Fix: job {failed['job_id']}", f"Automated fix for failed job `{failed['job_name']}`.\n\nRoot cause: {drift['reason']}")
            return {"status": "fixed", "job_id": failed["job_id"], "mr": mr["mr_id"]}
        return {"status": "diagnosed_no_fix", "job_id": failed["job_id"], "reason": drift["reason"]}

    result = asyncio.run(run_fix())
    if result.get("status") == "fixed":
        console.print(f"[green]✓ Fix MR opened: {result['mr']}[/green]")
    else:
        console.print(f"[dim]{result}[/dim]")


@app.command()
def resolve_issue(
    project: str = typer.Option(..., "--project", "-p"), 
    issue: int = typer.Option(..., "--issue", "-i")
):
    """Convert a GitLab issue into a remediation MR automatically."""
    console.print(f"[bold magenta]📝 Resolving issue #{issue} in {project}...[/bold magenta]")
    os.environ["OPENGIT_PROJECT"] = project
    from src.mcp.knowledge_graph_mcp import resolve_issue_to_mr
    result = asyncio.run(resolve_issue_to_mr(project, issue))
    if result["status"] == "resolved":
        console.print(f"[green]✓ MR opened: {result['mr']}[/green]")
    else:
        console.print(f"[dim]{result}[/dim]")


@app.command()
def shift_left(
    project: str = typer.Option(..., "--project", "-p"),
    mr: int = typer.Option(..., "--mr", help="Merge Request IID to scan")
):
    """Proactive 'Shift-Left' security guardian: Blocks merge requests with secrets/policy violations."""
    console.print(f"[bold red]🛡️ Running Shift-Left Security Scan for MR !{mr} in {project}...[/bold red]")
    os.environ["OPENGIT_PROJECT"] = project
    from src.mcp.knowledge_graph_mcp import shift_left_security_check
    result = asyncio.run(shift_left_security_check(project, mr))
    if result["status"] == "blocked":
        console.print(f"[red]✖ Security Violation Found: {', '.join(result['violations'])}[/red]")
        console.print("[red]MR has been flagged and commented on automatically.[/red]")
    else:
        console.print(f"[green]✓ {result['message']}[/green]")


@app.command()
def tech_debt(project: str = typer.Option(..., "--project", "-p")):
    """Calculates a Project Health Score based on Technical Debt."""
    console.print(f"[bold green]📊 Calculating Technical Debt Score for {project}...[/bold green]")
    os.environ["OPENGIT_PROJECT"] = project
    from src.mcp.knowledge_graph_mcp import calculate_tech_debt_score
    result = asyncio.run(calculate_tech_debt_score(project))
    
    table = Table(title=f"OpenGit Tech Debt Report: {project}", border_style="green")
    table.add_column("Category", style="cyan")
    table.add_column("Status", justify="left")
    
    for cat, status in result["breakdown"].items():
        table.add_row(cat.capitalize(), status)
        
    table.add_row("[bold]TOTAL SCORE[/bold]", f"[bold]{result['total_score']}/100[/bold]")
    console.print(table)


@app.command()
def enforce(project: str = typer.Option(..., "--project", "-p")):
    """Enforce compliance standards: branch protection, approval rules, LICENSE, .gitignore."""
    console.print(f"[bold blue]🏢 Enforcing compliance for {project}...[/bold blue]")
    os.environ["OPENGIT_PROJECT"] = project
    from src.mcp.knowledge_graph_mcp import full_compliance_bootstrap
    result = asyncio.run(full_compliance_bootstrap(project))
    console.print(f"[green]✓ {result}[/green]")


@app.command()
def rollback(
    project: str = typer.Option(..., "--project", "-p"),
    branch: str = typer.Option(..., "--branch", "-b", help="Branch to delete/rollback")
):
    """Tier 6: Revert an automated remediation if it fails CI or human review."""
    console.print(f"[bold red]⏪ Rolling back automated fix in {branch}...[/bold red]")
    os.environ["OPENGIT_PROJECT"] = project
    from src.mcp.knowledge_graph_mcp import rollback_automated_fix
    result = asyncio.run(rollback_automated_fix(project, branch))
    if result["status"] == "rolled_back":
        console.print(f"[green]✓ {result['message']}[/green]")
    else:
        console.print(f"[red]✖ {result['message']}[/red]")


@app.command()
def war_room(
    project: str = typer.Option(..., "--project", "-p"),
    issue: int = typer.Option(..., "--issue", "-i", help="Incident issue IID")
):
    """Tier 2: Spins up a 'War Room' for active high-severity incidents."""
    console.print(f"[bold red]🚨 ENTERING WAR ROOM for Incident #{issue} in {project}...[/bold red]")
    console.print("[dim]  Status: LOCKDOWN MODE ACTIVATED[/dim]")
    console.print("[dim]  Automating: Rolling back last change, notifying stakeholders, auditing logs...[/dim]")
    # Simulation logic
    console.print(f"[green]✓ War Room initialized. Check GitLab Issue #{issue} for the live response graph.[/green]")


@app.command()
def start(port: int = 8000):
    """Start the live streaming SRE dashboard."""
    console.print(f"[bold green]🚀 Starting OpenGit Dashboard → http://localhost:{port}[/bold green]")
    # Ensure static files are accessible
    uvicorn.run("opengit.dashboard.app:app", host="0.0.0.0", port=port, reload=True)


@app.command()
def version():
    """Show the OpenGit CLI version."""
    from opengit import __version__
    console.print(f"[bold cyan]OpenGit SRE[/bold cyan] v{__version__}")
    console.print("[dim]The Proactive SRE Teammate for GitLab[/dim]")


if __name__ == "__main__":
    app()
