import pytest
from aura_core.blueprint.engine import (
    get_default_blueprint,
    get_section_definitions,
    get_section_by_key,
    get_depth_presets,
    validate_blueprint,
    blueprint_to_prompt_spec,
    calculate_completeness,
    SECTION_CATEGORIES,
    DEFAULT_SECTION_KEYS,
)
from aura_core.types import BlueprintConfig, SectionDefinition, BlueprintValidation


class TestSectionDefinitions:
    def test_all_17_sections_exist(self):
        sections = get_section_definitions()
        assert len(sections) == 17

    def test_section_keys_unique(self):
        sections = get_section_definitions()
        keys = [s.key for s in sections]
        assert len(keys) == len(set(keys))

    def test_required_sections_present(self):
        sections = get_section_definitions()
        required = [s for s in sections if s.required]
        required_keys = {s.key for s in required}
        assert "hero" in required_keys
        assert "footer" in required_keys

    def test_all_sections_have_fields(self):
        sections = get_section_definitions()
        for s in sections:
            assert len(s.fields) > 0, f"{s.key} has no fields"

    def test_all_sections_have_ai_instructions(self):
        sections = get_section_definitions()
        for s in sections:
            assert len(s.ai_instructions) > 20, f"{s.key} ai_instructions too short"

    def test_sections_have_order(self):
        sections = get_section_definitions()
        orders = [s.order for s in sections]
        assert orders == sorted(orders)

    def test_section_categories_valid(self):
        sections = get_section_definitions()
        valid_cats = set(SECTION_CATEGORIES.keys())
        for s in sections:
            assert s.category in valid_cats, f"{s.key} has invalid category {s.category}"


class TestGetSectionByKey:
    def test_existing_key(self):
        s = get_section_by_key("hero")
        assert s is not None
        assert s.key == "hero"
        assert s.label == "Hero Section"

    def test_missing_key_returns_none(self):
        assert get_section_by_key("nonexistent") is None

    def test_faq_section(self):
        s = get_section_by_key("faq")
        assert s is not None
        assert s.category == "trust"


class TestDepthPresets:
    def test_four_presets_exist(self):
        presets = get_depth_presets()
        assert len(presets) == 4
        assert "minimal" in presets
        assert "standard" in presets
        assert "comprehensive" in presets
        assert "legendary" in presets

    def test_minimal_has_fewest_sections(self):
        presets = get_depth_presets()
        assert len(presets["minimal"]["sections"]) < len(presets["comprehensive"]["sections"])

    def test_legendary_has_all_sections(self):
        presets = get_depth_presets()
        assert len(presets["legendary"]["sections"]) == 17

    def test_multipliers_increase_with_depth(self):
        presets = get_depth_presets()
        assert presets["minimal"]["content_multiplier"] < presets["standard"]["content_multiplier"]
        assert presets["standard"]["content_multiplier"] < presets["comprehensive"]["content_multiplier"]
        assert presets["comprehensive"]["content_multiplier"] < presets["legendary"]["content_multiplier"]


class TestGetDefaultBlueprint:
    def test_returns_blueprint_config(self):
        bp = get_default_blueprint()
        assert isinstance(bp, BlueprintConfig)

    def test_default_is_comprehensive(self):
        bp = get_default_blueprint()
        assert bp.depth == "comprehensive"

    def test_minimal_depth(self):
        bp = get_default_blueprint("minimal")
        assert bp.depth == "minimal"
        enabled = [s for s in bp.sections if s.enabled]
        assert len(enabled) < 10

    def test_legendary_all_enabled(self):
        bp = get_default_blueprint("legendary")
        enabled = [s for s in bp.sections if s.enabled]
        assert len(enabled) == 17
        assert bp.content_multiplier == 1.8

    def test_hero_always_enabled(self):
        for depth in ["minimal", "standard", "comprehensive", "legendary"]:
            bp = get_default_blueprint(depth)
            hero = next(s for s in bp.sections if s.key == "hero")
            assert hero.enabled is True

    def test_unknown_depth_defaults(self):
        bp = get_default_blueprint("nonexistent")
        assert bp.depth == "comprehensive"


class TestValidateBlueprint:
    def test_valid_blueprint(self):
        bp = get_default_blueprint()
        result = validate_blueprint(bp)
        assert isinstance(result, BlueprintValidation)
        assert result.valid is True
        assert len(result.errors) == 0

    def test_no_sections_invalid(self):
        bp = BlueprintConfig(
            depth="custom", depth_label="Custom", content_multiplier=1.0,
            sections=[], global_settings={}, visual_settings={},
        )
        result = validate_blueprint(bp)
        assert result.valid is False
        assert len(result.errors) > 0

    def test_missing_required_sections(self):
        sections = [
            SectionDefinition(
                key="about", label="About", description="About",
                enabled=True, required=False, category="core",
                fields=[], visual_options={}, ai_instructions="Write about section", order=0,
            )
        ]
        bp = BlueprintConfig(
            depth="custom", depth_label="Custom", content_multiplier=1.0,
            sections=sections, global_settings={}, visual_settings={},
        )
        result = validate_blueprint(bp)
        assert result.valid is False


class TestBlueprintToPromptSpec:
    def test_returns_two_strings(self):
        bp = get_default_blueprint("minimal")
        prompt_spec, json_schema = blueprint_to_prompt_spec(bp)
        assert isinstance(prompt_spec, str)
        assert isinstance(json_schema, str)
        assert len(prompt_spec) > 100
        assert len(json_schema) > 50

    def test_contains_section_keys(self):
        bp = get_default_blueprint("minimal")
        prompt_spec, json_schema = blueprint_to_prompt_spec(bp)
        assert "hero" in prompt_spec
        assert "hero" in json_schema

    def test_legendary_uses_overrides(self):
        bp = get_default_blueprint("legendary")
        prompt_spec, _ = blueprint_to_prompt_spec(bp)
        assert "Fortune 500" in prompt_spec or "CMO" in prompt_spec


class TestCalculateCompleteness:
    def test_empty_site_copy(self):
        bp = get_default_blueprint("minimal")
        result = calculate_completeness({}, bp)
        assert result["score"] == 0

    def test_partial_fill(self):
        bp = get_default_blueprint("minimal")
        site_copy = {"headline": "Welcome to Our Site", "subheadline": "The best place"}
        result = calculate_completeness(site_copy, bp)
        assert result["filled"] > 0
        assert result["score"] > 0

    def test_none_inputs(self):
        result = calculate_completeness(None, None)
        assert result["score"] == 0


class TestSectionCategories:
    def test_all_categories_present(self):
        expected = {"core", "persuasion", "trust", "conversion", "showcase", "content"}
        assert set(SECTION_CATEGORIES.keys()) == expected

    def test_categories_have_label_and_description(self):
        for key, cat in SECTION_CATEGORIES.items():
            assert "label" in cat, f"{key} missing label"
            assert "description" in cat, f"{key} missing description"
