"""Tests for the AWS Batch generator."""

from __future__ import annotations

from pathlib import Path

import pytest

from prisme.generators.base import GeneratorContext
from prisme.generators.batch import BatchGenerator
from prisme.spec.fields import FieldSpec, FieldType
from prisme.spec.infrastructure import AWSBatchConfig, AWSBatchJobSpec
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)],
            )
        ],
    )


@pytest.fixture
def batch_project_spec() -> ProjectSpec:
    return ProjectSpec(
        name="test-project",
        batch=AWSBatchConfig(
            enabled=True,
            region="eu-west-1",
            jobs=[
                AWSBatchJobSpec(
                    name="data-etl",
                    command=["python", "-m", "app.jobs.etl"],
                    vcpus=2,
                    memory_mb=4096,
                    schedule="rate(1 hour)",
                ),
                AWSBatchJobSpec(
                    name="report-gen",
                    command=["python", "-m", "app.jobs.report"],
                    vcpus=4,
                    memory_mb=8192,
                ),
            ],
        ),
    )


@pytest.fixture
def batch_context(
    basic_stack: StackSpec, batch_project_spec: ProjectSpec, tmp_path: Path
) -> GeneratorContext:
    return GeneratorContext(
        domain_spec=basic_stack,
        output_dir=tmp_path,
        dry_run=True,
        project_spec=batch_project_spec,
    )


class TestBatchGeneratorNoConfig:
    """Tests when batch 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 = BatchGenerator(ctx)
        assert gen.generate_files() == []

    def test_no_batch_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 = BatchGenerator(ctx)
        assert gen.generate_files() == []

    def test_batch_disabled_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",
                batch=AWSBatchConfig(enabled=False),
            ),
        )
        gen = BatchGenerator(ctx)
        assert gen.generate_files() == []

    def test_batch_enabled_no_jobs_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",
                batch=AWSBatchConfig(enabled=True, jobs=[]),
            ),
        )
        gen = BatchGenerator(ctx)
        assert gen.generate_files() == []


class TestBatchGeneratorFullConfig:
    """Tests for full batch generation."""

    def test_generates_terraform_config(self, batch_context: GeneratorContext) -> None:
        gen = BatchGenerator(batch_context)
        files = gen.generate_files()
        tf = next((f for f in files if f.path == Path("deploy/aws-batch/main.tf")), None)
        assert tf is not None
        assert tf.strategy == FileStrategy.GENERATE_ONCE

    def test_generates_deploy_workflow(self, batch_context: GeneratorContext) -> None:
        gen = BatchGenerator(batch_context)
        files = gen.generate_files()
        wf = next((f for f in files if f.path == Path(".github/workflows/deploy-batch.yml")), None)
        assert wf is not None
        assert wf.strategy == FileStrategy.GENERATE_ONCE

    def test_total_file_count(self, batch_context: GeneratorContext) -> None:
        gen = BatchGenerator(batch_context)
        files = gen.generate_files()
        assert len(files) == 2

    def test_terraform_has_batch_resources(self, batch_context: GeneratorContext) -> None:
        gen = BatchGenerator(batch_context)
        files = gen.generate_files()
        tf = next(f for f in files if f.path == Path("deploy/aws-batch/main.tf"))
        assert "aws_batch_compute_environment" in tf.content
        assert "aws_batch_job_queue" in tf.content
        assert "aws_batch_job_definition" in tf.content

    def test_terraform_has_job_definitions(self, batch_context: GeneratorContext) -> None:
        gen = BatchGenerator(batch_context)
        files = gen.generate_files()
        tf = next(f for f in files if f.path == Path("deploy/aws-batch/main.tf"))
        assert "data-etl" in tf.content
        assert "report-gen" in tf.content

    def test_terraform_has_eventbridge_for_scheduled(self, batch_context: GeneratorContext) -> None:
        gen = BatchGenerator(batch_context)
        files = gen.generate_files()
        tf = next(f for f in files if f.path == Path("deploy/aws-batch/main.tf"))
        # data-etl has a schedule, so EventBridge should be present
        assert "aws_cloudwatch_event_rule" in tf.content
        assert "rate(1 hour)" in tf.content

    def test_terraform_has_correct_region(self, batch_context: GeneratorContext) -> None:
        gen = BatchGenerator(batch_context)
        files = gen.generate_files()
        tf = next(f for f in files if f.path == Path("deploy/aws-batch/main.tf"))
        assert "eu-west-1" in tf.content

    def test_terraform_has_resource_specs(self, batch_context: GeneratorContext) -> None:
        gen = BatchGenerator(batch_context)
        files = gen.generate_files()
        tf = next(f for f in files if f.path == Path("deploy/aws-batch/main.tf"))
        assert "VCPU" in tf.content
        assert "MEMORY" in tf.content

    def test_workflow_has_aws_credentials(self, batch_context: GeneratorContext) -> None:
        gen = BatchGenerator(batch_context)
        files = gen.generate_files()
        wf = next(f for f in files if f.path == Path(".github/workflows/deploy-batch.yml"))
        assert "AWS_ACCESS_KEY_ID" in wf.content
        assert "AWS_SECRET_ACCESS_KEY" in wf.content

    def test_all_files_have_generate_once_strategy(self, batch_context: GeneratorContext) -> None:
        gen = BatchGenerator(batch_context)
        files = gen.generate_files()
        for f in files:
            assert f.strategy == FileStrategy.GENERATE_ONCE
