"""
Django Commands - Django manage.py bridge for the LightWave CLI.

SST Reference: packages/lightwave-core/lightwave/schema/definitions/cli.yaml
Domain: dj (runtime: python override)
"""

from __future__ import annotations

import os
import subprocess
import sys
from pathlib import Path
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from typing import Any

from lightwave.cli.runner import CommandError


def find_manage_py() -> Path:
    """Find the manage.py file in the workspace."""
    # Look in common locations
    search_paths = [
        Path.cwd() / "manage.py",
        Path.cwd() / "lwm_core" / "manage.py",
        Path.cwd() / "lightwave-platform" / "lwm_core" / "manage.py",
    ]

    # Also check DJANGO_SETTINGS_MODULE
    settings_module = os.environ.get("DJANGO_SETTINGS_MODULE", "")
    if settings_module:
        # Try to find manage.py relative to settings
        parts = settings_module.split(".")
        if parts:
            for p in search_paths:
                parent = p.parent
                if (parent / parts[0]).exists():
                    return p

    for path in search_paths:
        if path.exists():
            return path

    raise CommandError("Could not find manage.py. Run from Django project directory or set DJANGO_SETTINGS_MODULE")


def run_django_command(
    command: str,
    args: list[str],
    *,
    json_output: bool = False,
    dry_run: bool = False,
    verbose: bool = False,
) -> dict[str, Any] | None:
    """
    Run a Django management command.

    SST: domains.dj.commands (runtime: python)
    - migrate: Run Django migrations
    - makemigrations: Create new migrations
    - check: Run Django system checks
    - shell: Open Django shell
    - collectstatic: Collect static files
    """
    manage_py = find_manage_py()

    # Build command
    cmd = [sys.executable, str(manage_py), command]

    # Map CLI flags to Django flags
    if command == "migrate":
        # SST flags: [--fake, --plan, --app]
        for i, arg in enumerate(args):
            if arg == "--fake":
                cmd.append("--fake")
            elif arg == "--plan":
                cmd.append("--plan")
            elif arg == "--app" and i + 1 < len(args):
                cmd.append(args[i + 1])

    elif command == "makemigrations":
        # SST flags: [--app, --empty, --name]
        for i, arg in enumerate(args):
            if arg == "--app" and i + 1 < len(args):
                cmd.append(args[i + 1])
            elif arg == "--empty":
                cmd.append("--empty")
            elif arg == "--name" and i + 1 < len(args):
                cmd.extend(["--name", args[i + 1]])

    elif command == "check":
        # SST flags: [--deploy, --fail-level]
        for i, arg in enumerate(args):
            if arg == "--deploy":
                cmd.append("--deploy")
            elif arg == "--fail-level" and i + 1 < len(args):
                cmd.extend(["--fail-level", args[i + 1]])

    elif command == "shell":
        # Try to use IPython if available
        try:
            import IPython  # noqa: F401

            cmd.extend(["-i", "ipython"])
        except ImportError:
            pass

    elif command == "collectstatic":
        # SST flags: [--no-input, --clear]
        for arg in args:
            if arg == "--no-input":
                cmd.append("--noinput")
            elif arg == "--clear":
                cmd.append("--clear")

    if verbose:
        print(f"Running: {' '.join(cmd)}")

    if dry_run:
        if json_output:
            return {"success": True, "dry_run": True, "command": cmd}
        print(f"[dry-run] Would run: {' '.join(cmd)}")
        return None

    # Run command
    if command == "shell":
        # Interactive shell - no capture
        result = subprocess.run(cmd)
    else:
        result = subprocess.run(cmd, capture_output=json_output)

    if json_output:
        return {
            "success": result.returncode == 0,
            "exit_code": result.returncode,
            "stdout": result.stdout.decode() if result.stdout else "",
            "stderr": result.stderr.decode() if result.stderr else "",
        }

    if result.returncode != 0:
        raise CommandError(f"Django {command} exited with code {result.returncode}")

    return None
