"""Tests for email service generator."""

from __future__ import annotations

from pathlib import Path

import pytest

from prisme.generators import GeneratorContext
from prisme.generators.backend.email import EmailGenerator
from prisme.spec import FieldSpec, FieldType, ModelSpec, StackSpec
from prisme.spec.email import EmailServiceConfig, EmailTemplateSpec
from prisme.spec.project import ProjectSpec


@pytest.fixture
def basic_stack_spec() -> StackSpec:
    """Basic stack spec for testing."""
    return StackSpec(
        name="test-email-app",
        models=[
            ModelSpec(
                name="User",
                fields=[
                    FieldSpec(name="email", type=FieldType.STRING, required=True, unique=True),
                ],
            )
        ],
    )


@pytest.fixture
def email_enabled_project() -> ProjectSpec:
    """Project spec with email service enabled."""
    return ProjectSpec(
        name="test-email-app",
        email=EmailServiceConfig(
            enabled=True,
            from_address="TestApp <noreply@test.com>",
            reply_to="support@test.com",
            templates=[
                EmailTemplateSpec(
                    name="welcome",
                    subject="Welcome to {app_name}!",
                    variables=["user_name", "app_name"],
                ),
                EmailTemplateSpec(
                    name="order_confirmation",
                    subject="Order #{order_id} confirmed",
                    variables=["order_id", "customer_name", "total"],
                ),
            ],
        ),
    )


@pytest.fixture
def email_disabled_project() -> ProjectSpec:
    """Project spec with email service disabled (default)."""
    return ProjectSpec(name="test-email-app")


@pytest.fixture
def context_email_enabled(
    basic_stack_spec: StackSpec, email_enabled_project: ProjectSpec, tmp_path: Path
) -> GeneratorContext:
    """Generator context with email enabled."""
    return GeneratorContext(
        domain_spec=basic_stack_spec,
        output_dir=tmp_path,
        dry_run=True,
        project_spec=email_enabled_project,
    )


@pytest.fixture
def context_email_disabled(
    basic_stack_spec: StackSpec, email_disabled_project: ProjectSpec, tmp_path: Path
) -> GeneratorContext:
    """Generator context with email disabled."""
    return GeneratorContext(
        domain_spec=basic_stack_spec,
        output_dir=tmp_path,
        dry_run=True,
        project_spec=email_disabled_project,
    )


class TestEmailGenerator:
    """Tests for EmailGenerator."""

    def test_skips_when_disabled(self, context_email_disabled: GeneratorContext):
        """Generator returns empty list when email is disabled."""
        generator = EmailGenerator(context_email_disabled)
        files = generator.generate_files()
        assert files == []
        assert generator.skip_generation is True

    def test_generates_files_when_enabled(self, context_email_enabled: GeneratorContext):
        """Generator creates email service files when enabled."""
        generator = EmailGenerator(context_email_enabled)
        files = generator.generate_files()

        # Should generate: config, client, service, templates.py, __init__,
        # base.html, + 2 custom template HTMLs = 8 files
        assert len(files) == 8

    def test_generates_email_config(self, context_email_enabled: GeneratorContext):
        """Generator creates email config file."""
        generator = EmailGenerator(context_email_enabled)
        files = generator.generate_files()

        config_file = next(f for f in files if "config.py" in str(f.path))
        assert "EmailSettings" in config_file.content
        assert "RESEND_API_KEY" in config_file.content
        assert "noreply@test.com" in config_file.content

    def test_generates_email_client(self, context_email_enabled: GeneratorContext):
        """Generator creates Resend client file."""
        generator = EmailGenerator(context_email_enabled)
        files = generator.generate_files()

        client_file = next(f for f in files if "client.py" in str(f.path))
        assert "send_email" in client_file.content
        assert "send_email_async" in client_file.content
        assert "send_email_fire_and_forget" in client_file.content
        assert "resend" in client_file.content

    def test_generates_email_service(self, context_email_enabled: GeneratorContext):
        """Generator creates general-purpose email service."""
        generator = EmailGenerator(context_email_enabled)
        files = generator.generate_files()

        service_file = next(f for f in files if "service.py" in str(f.path))
        assert "send_templated_email" in service_file.content
        assert "send_templated_email_async" in service_file.content
        # Should have per-template convenience functions
        assert "send_welcome" in service_file.content
        assert "send_order_confirmation" in service_file.content

    def test_generates_template_renderer(self, context_email_enabled: GeneratorContext):
        """Generator creates template renderer."""
        generator = EmailGenerator(context_email_enabled)
        files = generator.generate_files()

        templates_file = next(f for f in files if "templates.py" in str(f.path))
        assert "render_template" in templates_file.content
        assert "list_templates" in templates_file.content

    def test_generates_base_html(self, context_email_enabled: GeneratorContext):
        """Generator creates base HTML email template."""
        generator = EmailGenerator(context_email_enabled)
        files = generator.generate_files()

        base_html = next(f for f in files if "base.html" in str(f.path))
        assert "<!DOCTYPE html>" in base_html.content
        assert "${body}" in base_html.content
        assert "Test Email App" in base_html.content

    def test_generates_custom_template_html(self, context_email_enabled: GeneratorContext):
        """Generator creates per-template HTML files."""
        generator = EmailGenerator(context_email_enabled)
        files = generator.generate_files()

        file_names = [str(f.path) for f in files]
        assert any("welcome.html" in name for name in file_names)
        assert any("order_confirmation.html" in name for name in file_names)

    def test_generates_init(self, context_email_enabled: GeneratorContext):
        """Generator creates __init__.py with proper exports."""
        generator = EmailGenerator(context_email_enabled)
        files = generator.generate_files()

        init_file = next(f for f in files if "__init__.py" in str(f.path))
        assert "send_email" in init_file.content
        assert "send_email_async" in init_file.content
        assert "send_welcome" in init_file.content
        assert "send_order_confirmation" in init_file.content

    def test_file_strategies(self, context_email_enabled: GeneratorContext):
        """Generator uses appropriate file strategies."""
        from prisme.spec.stack import FileStrategy

        generator = EmailGenerator(context_email_enabled)
        files = generator.generate_files()

        # Config and client should always be regenerated
        config_file = next(f for f in files if f.path.name == "config.py")
        assert config_file.strategy == FileStrategy.ALWAYS_OVERWRITE

        client_file = next(f for f in files if f.path.name == "client.py")
        assert client_file.strategy == FileStrategy.ALWAYS_OVERWRITE

        # Service should be generated once (user editable)
        service_file = next(f for f in files if f.path.name == "service.py")
        assert service_file.strategy == FileStrategy.GENERATE_ONCE

        # HTML templates generated once
        base_html = next(f for f in files if f.path.name == "base.html")
        assert base_html.strategy == FileStrategy.GENERATE_ONCE

    def test_uses_correct_package_name(self, context_email_enabled: GeneratorContext):
        """Generator uses correct Python package name in imports."""
        generator = EmailGenerator(context_email_enabled)
        files = generator.generate_files()

        client_file = next(f for f in files if "client.py" in str(f.path))
        assert "test_email_app" in client_file.content

    def test_no_templates_still_works(self, basic_stack_spec: StackSpec, tmp_path: Path):
        """Generator works with no custom templates defined."""
        project = ProjectSpec(
            name="test-app",
            email=EmailServiceConfig(enabled=True),
        )
        context = GeneratorContext(
            domain_spec=basic_stack_spec,
            output_dir=tmp_path,
            dry_run=True,
            project_spec=project,
        )
        generator = EmailGenerator(context)
        files = generator.generate_files()

        # config, client, service, templates.py, __init__, base.html = 6 files
        assert len(files) == 6

    def test_reply_to_in_config(self, context_email_enabled: GeneratorContext):
        """Reply-to address is included in generated config."""
        generator = EmailGenerator(context_email_enabled)
        files = generator.generate_files()

        config_file = next(f for f in files if "config.py" in str(f.path))
        assert "support@test.com" in config_file.content
