"""Tests for validate edge cases, db commands, and misc CLI commands."""

from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING

from prisme.cli import main

if TYPE_CHECKING:
    from click.testing import CliRunner


VALID_SPEC = """\
from prisme.spec.stack import StackSpec
from prisme.spec.model import ModelSpec
from prisme.spec.fields import FieldSpec, FieldType

spec = StackSpec(
    name="test-project",
    version="1.0.0",
    models=[
        ModelSpec(
            name="Item",
            fields=[FieldSpec(name="name", type=FieldType.STRING, required=True)],
        )
    ],
)
"""

SPEC_WITH_DUPLICATE_MODELS = """\
from prisme.spec.stack import StackSpec
from prisme.spec.model import ModelSpec
from prisme.spec.fields import FieldSpec, FieldType

spec = StackSpec(
    name="test-project",
    version="1.0.0",
    models=[
        ModelSpec(
            name="Item",
            fields=[FieldSpec(name="name", type=FieldType.STRING)],
        ),
        ModelSpec(
            name="Item",
            fields=[FieldSpec(name="title", type=FieldType.STRING)],
        ),
    ],
)
"""


class TestValidateErrorPaths:
    """Tests for validate command error handling."""

    def test_validate_with_validation_error(self, cli_runner: CliRunner, tmp_path: Path) -> None:
        """Validate shows validation errors for specs with issues."""
        spec_file = tmp_path / "duplicate_models.py"
        spec_file.write_text(SPEC_WITH_DUPLICATE_MODELS)
        result = cli_runner.invoke(main, ["validate", str(spec_file)])
        assert result.exit_code != 0
        assert "error" in result.output.lower()

    def test_validate_with_no_stack_spec(self, cli_runner: CliRunner, tmp_path: Path) -> None:
        """Validate shows error when file has no StackSpec."""
        spec_file = tmp_path / "empty.py"
        spec_file.write_text("x = 42\n")
        result = cli_runner.invoke(main, ["validate", str(spec_file)])
        assert result.exit_code != 0

    def test_validate_with_runtime_error(self, cli_runner: CliRunner, tmp_path: Path) -> None:
        """Validate shows error when spec file raises runtime error."""
        spec_file = tmp_path / "broken.py"
        spec_file.write_text("raise RuntimeError('broken')\n")
        result = cli_runner.invoke(main, ["validate", str(spec_file)])
        assert result.exit_code != 0


class TestDbInit:
    """Tests for db init command."""

    def test_db_init_alembic_already_exists(self, cli_runner: CliRunner) -> None:
        """db init reports if alembic is already initialized."""
        with cli_runner.isolated_filesystem():
            Path("alembic.ini").write_text("[alembic]")
            result = cli_runner.invoke(main, ["db", "init"])
            assert result.exit_code == 0
            assert "already initialized" in result.output.lower()

    def test_db_init_no_spec(self, cli_runner: CliRunner) -> None:
        """db init without a spec file."""
        with cli_runner.isolated_filesystem():
            result = cli_runner.invoke(main, ["db", "init"])
            # Should fail or warn about no spec
            assert result.exit_code in (0, 1)


class TestDbMigrate:
    """Tests for db migrate command."""

    def test_db_migrate_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["db", "migrate", "--help"])
        assert result.exit_code == 0
        assert "migrate" in result.output.lower()


class TestDbReset:
    """Tests for db reset command."""

    def test_db_reset_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["db", "reset", "--help"])
        assert result.exit_code == 0


class TestDbSeed:
    """Tests for db seed command."""

    def test_db_seed_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["db", "seed", "--help"])
        assert result.exit_code == 0


class TestDevCommand:
    """Tests for dev command."""

    def test_dev_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["dev", "--help"])
        assert result.exit_code == 0
        assert "dev" in result.output.lower()


class TestInstallCommand:
    """Tests for install command."""

    def test_install_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["install", "--help"])
        assert result.exit_code == 0


class TestTestCommand:
    """Tests for test command."""

    def test_test_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["test", "--help"])
        assert result.exit_code == 0


class TestDockerGroup:
    """Tests for docker group commands."""

    def test_docker_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["docker", "--help"])
        assert result.exit_code == 0

    def test_docker_init_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["docker", "init", "--help"])
        assert result.exit_code == 0

    def test_docker_logs_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["docker", "logs", "--help"])
        assert result.exit_code == 0

    def test_docker_shell_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["docker", "shell", "--help"])
        assert result.exit_code == 0

    def test_docker_down_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["docker", "down", "--help"])
        assert result.exit_code == 0

    def test_docker_reset_db_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["docker", "reset-db", "--help"])
        assert result.exit_code == 0

    def test_docker_backup_db_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["docker", "backup-db", "--help"])
        assert result.exit_code == 0

    def test_docker_restore_db_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["docker", "restore-db", "--help"])
        assert result.exit_code == 0

    def test_docker_init_prod_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["docker", "init-prod", "--help"])
        assert result.exit_code == 0

    def test_docker_build_prod_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["docker", "build-prod", "--help"])
        assert result.exit_code == 0


class TestCIGroup:
    """Tests for CI group commands."""

    def test_ci_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["ci", "--help"])
        assert result.exit_code == 0

    def test_ci_init_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["ci", "init", "--help"])
        assert result.exit_code == 0

    def test_ci_status_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["ci", "status", "--help"])
        assert result.exit_code == 0

    def test_ci_validate_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["ci", "validate", "--help"])
        assert result.exit_code == 0


class TestDeployGroup:
    """Tests for deploy group commands."""

    def test_deploy_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["deploy", "--help"])
        assert result.exit_code == 0

    def test_deploy_init_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["deploy", "init", "--help"])
        assert result.exit_code == 0

    def test_deploy_plan_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["deploy", "plan", "--help"])
        assert result.exit_code == 0


class TestAuthGroup:
    """Tests for auth group commands."""

    def test_auth_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["auth", "--help"])
        assert result.exit_code == 0

    def test_auth_login_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["auth", "login", "--help"])
        assert result.exit_code == 0

    def test_auth_logout_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["auth", "logout", "--help"])
        assert result.exit_code == 0

    def test_auth_status_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["auth", "status", "--help"])
        assert result.exit_code == 0


class TestSubdomainGroup:
    """Tests for subdomain group commands."""

    def test_subdomain_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["subdomain", "--help"])
        assert result.exit_code == 0

    def test_subdomain_list_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["subdomain", "list", "--help"])
        assert result.exit_code == 0


class TestDevcontainerGroup:
    """Tests for devcontainer group commands."""

    def test_devcontainer_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["devcontainer", "--help"])
        assert result.exit_code == 0

    def test_devcontainer_up_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["devcontainer", "up", "--help"])
        assert result.exit_code == 0


class TestProjectsGroup:
    """Tests for projects group commands."""

    def test_projects_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["projects", "--help"])
        assert result.exit_code == 0


class TestProxyGroup:
    """Tests for proxy group commands."""

    def test_proxy_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["proxy", "--help"])
        assert result.exit_code == 0


class TestAdminGroup:
    """Tests for admin group commands."""

    def test_admin_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["admin", "--help"])
        assert result.exit_code == 0

    def test_admin_bootstrap_help(self, cli_runner: CliRunner) -> None:
        result = cli_runner.invoke(main, ["admin", "bootstrap", "--help"])
        assert result.exit_code == 0
