"""Tests for the Docker build service generator."""

from __future__ import annotations

from pathlib import Path

import pytest

from prisme.generators.base import GeneratorContext
from prisme.generators.build import BuildGenerator
from prisme.spec.fields import FieldSpec, FieldType
from prisme.spec.infrastructure import DockerBuildServiceConfig
from prisme.spec.model import ModelSpec
from prisme.spec.project import ProjectSpec
from prisme.spec.stack import FileStrategy, StackSpec


@pytest.fixture
def basic_stack() -> StackSpec:
    return StackSpec(
        name="test-project",
        version="1.0.0",
        models=[
            ModelSpec(
                name="Item",
                fields=[FieldSpec(name="name", type=FieldType.STRING, required=True)],
            )
        ],
    )


class TestBuildGeneratorNoConfig:
    """Tests when build config is absent."""

    def test_no_project_spec_returns_empty(self, basic_stack: StackSpec, tmp_path: Path) -> None:
        ctx = GeneratorContext(domain_spec=basic_stack, output_dir=tmp_path, dry_run=True)
        gen = BuildGenerator(ctx)
        assert gen.generate_files() == []

    def test_no_build_config_returns_empty(self, basic_stack: StackSpec, tmp_path: Path) -> None:
        ctx = GeneratorContext(
            domain_spec=basic_stack,
            output_dir=tmp_path,
            dry_run=True,
            project_spec=ProjectSpec(name="test-project"),
        )
        gen = BuildGenerator(ctx)
        assert gen.generate_files() == []


class TestBuildGeneratorGitHub:
    """Tests for GitHub-based Docker builds (default)."""

    def test_generates_github_build_workflow(self, basic_stack: StackSpec, tmp_path: Path) -> None:
        ctx = GeneratorContext(
            domain_spec=basic_stack,
            output_dir=tmp_path,
            dry_run=True,
            project_spec=ProjectSpec(
                name="test-project",
                build=DockerBuildServiceConfig(provider="github"),
            ),
        )
        gen = BuildGenerator(ctx)
        files = gen.generate_files()
        assert len(files) == 1
        assert files[0].path == Path(".github/workflows/build-docker.yml")
        assert files[0].strategy == FileStrategy.GENERATE_ONCE
        assert "Build Docker Images" in files[0].content
        assert "ghcr.io" in files[0].content

    def test_github_build_uses_buildx(self, basic_stack: StackSpec, tmp_path: Path) -> None:
        ctx = GeneratorContext(
            domain_spec=basic_stack,
            output_dir=tmp_path,
            dry_run=True,
            project_spec=ProjectSpec(
                name="test-project",
                build=DockerBuildServiceConfig(provider="github"),
            ),
        )
        gen = BuildGenerator(ctx)
        files = gen.generate_files()
        assert "docker/build-push-action" in files[0].content


class TestBuildGeneratorHetzner:
    """Tests for Hetzner-based Docker builds."""

    def test_generates_hetzner_build_workflow(self, basic_stack: StackSpec, tmp_path: Path) -> None:
        ctx = GeneratorContext(
            domain_spec=basic_stack,
            output_dir=tmp_path,
            dry_run=True,
            project_spec=ProjectSpec(
                name="test-project",
                build=DockerBuildServiceConfig(
                    provider="hetzner",
                    build_server_type="cx32",
                    build_location="nbg1",
                ),
            ),
        )
        gen = BuildGenerator(ctx)
        files = gen.generate_files()
        assert len(files) == 1
        assert "Hetzner" in files[0].content
        assert "HCLOUD_TOKEN" in files[0].content
        assert "cx32" in files[0].content
        assert "nbg1" in files[0].content

    def test_hetzner_build_creates_and_destroys_vm(
        self, basic_stack: StackSpec, tmp_path: Path
    ) -> None:
        ctx = GeneratorContext(
            domain_spec=basic_stack,
            output_dir=tmp_path,
            dry_run=True,
            project_spec=ProjectSpec(
                name="test-project",
                build=DockerBuildServiceConfig(provider="hetzner"),
            ),
        )
        gen = BuildGenerator(ctx)
        files = gen.generate_files()
        content = files[0].content
        assert "server create" in content
        assert "server delete" in content


class TestBuildGeneratorAWS:
    """Tests for AWS-based Docker builds."""

    def test_generates_aws_build_workflow(self, basic_stack: StackSpec, tmp_path: Path) -> None:
        ctx = GeneratorContext(
            domain_spec=basic_stack,
            output_dir=tmp_path,
            dry_run=True,
            project_spec=ProjectSpec(
                name="test-project",
                build=DockerBuildServiceConfig(
                    provider="aws",
                    aws_region="us-east-1",
                    ecr_repository="my-app",
                ),
            ),
        )
        gen = BuildGenerator(ctx)
        files = gen.generate_files()
        assert len(files) == 1
        assert "ECR" in files[0].content
        assert "AWS_ACCESS_KEY_ID" in files[0].content
        assert "us-east-1" in files[0].content

    def test_aws_build_uses_ecr_login(self, basic_stack: StackSpec, tmp_path: Path) -> None:
        ctx = GeneratorContext(
            domain_spec=basic_stack,
            output_dir=tmp_path,
            dry_run=True,
            project_spec=ProjectSpec(
                name="test-project",
                build=DockerBuildServiceConfig(provider="aws"),
            ),
        )
        gen = BuildGenerator(ctx)
        files = gen.generate_files()
        assert "amazon-ecr-login" in files[0].content


class TestBuildGeneratorCustomConfig:
    """Tests for custom build configuration."""

    def test_custom_registry(self, basic_stack: StackSpec, tmp_path: Path) -> None:
        ctx = GeneratorContext(
            domain_spec=basic_stack,
            output_dir=tmp_path,
            dry_run=True,
            project_spec=ProjectSpec(
                name="test-project",
                build=DockerBuildServiceConfig(
                    provider="github",
                    registry="docker.io",
                ),
            ),
        )
        gen = BuildGenerator(ctx)
        files = gen.generate_files()
        assert "docker.io" in files[0].content

    def test_multi_platform(self, basic_stack: StackSpec, tmp_path: Path) -> None:
        ctx = GeneratorContext(
            domain_spec=basic_stack,
            output_dir=tmp_path,
            dry_run=True,
            project_spec=ProjectSpec(
                name="test-project",
                build=DockerBuildServiceConfig(
                    provider="github",
                    platforms=["linux/amd64", "linux/arm64"],
                ),
            ),
        )
        gen = BuildGenerator(ctx)
        files = gen.generate_files()
        assert "linux/amd64,linux/arm64" in files[0].content
