"""Real integration tests: exercise the actual AI pipeline end-to-end.

These tests call the real OpenAI API, parse real responses through the validation
pipeline, and verify the full chain works. They cost API credits and take time,
but they test what actually matters.

Run with: pytest tests/test_llm_injection.py -v
Skip expensive tests: pytest tests/test_llm_injection.py -v -k "not slow"
"""
import json
import time
import pytest
from app.services.aura import build_package, analyze_domain
from app.services.blueprint import get_default_blueprint
from app.services.validators import validate_site_copy, validate_brand, validate_analysis


@pytest.fixture
def minimal_blueprint():
    return get_default_blueprint("minimal")


@pytest.fixture
def standard_blueprint():
    return get_default_blueprint("standard")


class TestAnalysisPipeline:
    """Test that analyze_domain returns valid, parseable, structurally correct output from real AI."""

    @pytest.mark.slow
    def test_analysis_returns_valid_structure(self):
        result = analyze_domain("coffeegrinder.com")

        assert isinstance(result, dict), f"Expected dict, got {type(result)}"
        assert "niches" in result, f"Missing 'niches' key. Keys: {list(result.keys())}"
        assert isinstance(result["niches"], list), f"niches should be list, got {type(result['niches'])}"
        assert len(result["niches"]) >= 1, "AI returned zero niches"

    @pytest.mark.slow
    def test_analysis_niches_have_required_fields(self):
        result = analyze_domain("urbanfitness.com")

        for i, niche in enumerate(result.get("niches", [])):
            assert isinstance(niche, dict), f"Niche {i} is not a dict"
            assert "name" in niche, f"Niche {i} missing 'name'"
            assert len(niche["name"]) > 0, f"Niche {i} has empty name"

    @pytest.mark.slow
    def test_analysis_passes_validation(self):
        result = analyze_domain("gardentoolbox.com")

        validated, report = validate_analysis(result)
        assert report.is_valid or len(report.repairs) > 0, \
            f"Analysis failed validation with no repairs possible: {report.errors}"


class TestBuildPackagePipeline:
    """Test that build_package produces a complete, valid package from real AI responses."""

    @pytest.mark.slow
    def test_minimal_package_completes(self, minimal_blueprint):
        result = build_package(
            domain="testminimal.com",
            chosen_niche="Home Fitness Equipment",
            niche_data={"name": "Home Fitness Equipment", "description": "Home workout gear and accessories"},
            blueprint=minimal_blueprint,
        )

        assert isinstance(result, dict), f"Expected dict, got {type(result)}"
        assert "brand" in result, f"Missing 'brand'. Keys: {list(result.keys())}"
        assert "site_copy" in result, f"Missing 'site_copy'. Keys: {list(result.keys())}"
        assert "sales_letter" in result, f"Missing 'sales_letter'. Keys: {list(result.keys())}"

    @pytest.mark.slow
    def test_brand_output_validates(self, minimal_blueprint):
        result = build_package(
            domain="brandtest.com",
            chosen_niche="Organic Skincare",
            niche_data={"name": "Organic Skincare", "description": "Natural beauty and skincare products"},
            blueprint=minimal_blueprint,
        )

        brand = result.get("brand", {})
        validated_brand, brand_report = validate_brand(brand, auto_repair=True)

        assert "options" in validated_brand, "Brand missing options after validation"
        assert len(validated_brand.get("options", [])) >= 1, "Brand has zero name options"
        assert "color_primary" in validated_brand, "Brand missing color_primary"

    @pytest.mark.slow
    def test_site_copy_has_enabled_sections(self, minimal_blueprint):
        result = build_package(
            domain="sectiontest.com",
            chosen_niche="Pet Supplies",
            niche_data={"name": "Pet Supplies", "description": "Premium pet food and accessories"},
            blueprint=minimal_blueprint,
        )

        site_copy = result.get("site_copy", {})
        enabled_keys = [s["key"] for s in minimal_blueprint.get("sections", []) if s.get("enabled")]

        found_sections = [k for k in enabled_keys if k in site_copy]
        coverage = len(found_sections) / len(enabled_keys) if enabled_keys else 0

        assert coverage >= 0.5, \
            f"AI only generated {len(found_sections)}/{len(enabled_keys)} sections. " \
            f"Missing: {set(enabled_keys) - set(found_sections)}"

    @pytest.mark.slow
    def test_sales_letter_is_substantial(self, minimal_blueprint):
        result = build_package(
            domain="salestest.com",
            chosen_niche="Digital Marketing Tools",
            niche_data={"name": "Digital Marketing Tools", "description": "SEO and social media management software"},
            blueprint=minimal_blueprint,
        )

        sales_letter = result.get("sales_letter", "")
        assert isinstance(sales_letter, str), f"Sales letter is {type(sales_letter)}, not str"
        assert len(sales_letter) > 200, f"Sales letter too short ({len(sales_letter)} chars) — likely truncated or empty"
        assert not sales_letter.strip().startswith("{"), "Sales letter looks like JSON, not prose"

    @pytest.mark.slow
    def test_site_copy_validates_through_pipeline(self, minimal_blueprint):
        result = build_package(
            domain="validatetest.com",
            chosen_niche="Online Cooking Classes",
            niche_data={"name": "Online Cooking Classes", "description": "Virtual culinary education"},
            blueprint=minimal_blueprint,
        )

        site_copy = result.get("site_copy", {})
        validated_copy, copy_report = validate_site_copy(site_copy, auto_repair=True)
        assert copy_report.is_valid or len(copy_report.repairs) > 0, \
            f"Site copy failed validation: {copy_report.errors}"


class TestContextInfluencesOutput:
    """Test that providing assembled_context actually reaches the AI and influences output."""

    @pytest.mark.slow
    def test_context_with_specific_brand_preference(self, minimal_blueprint):
        context_with_preference = (
            "--- GLOBAL CONTEXT ---\n"
            "Brand Voice: The client specifically wants a warm, rustic, handcrafted tone. "
            "They despise corporate-speak. Their target audience is rural homesteaders aged 35-55. "
            "Color preference: earthy greens and warm browns. "
            "Key differentiator: All products are handmade by Appalachian artisans.\n"
            "--- END ---"
        )

        result = build_package(
            domain="rusticcraft.com",
            chosen_niche="Handmade Home Goods",
            niche_data={"name": "Handmade Home Goods", "description": "Artisan-crafted household items"},
            blueprint=minimal_blueprint,
            assembled_context=context_with_preference,
        )

        assert "brand" in result
        assert "site_copy" in result

        brand = result.get("brand", {})
        site_copy = result.get("site_copy", {})
        hero = site_copy.get("hero", {})

        full_output = json.dumps(result, default=str).lower()
        context_signals = ["handmade", "artisan", "craft", "rustic", "homestead"]
        matches = [s for s in context_signals if s in full_output]
        assert len(matches) >= 2, \
            f"Context specified rustic/artisan/handmade theme but output only matched {matches} " \
            f"out of {context_signals}. Context may not be reaching AI effectively."

    @pytest.mark.slow
    def test_brandkit_context_influences_sales_letter(self, minimal_blueprint):
        brandkit = (
            "BRAND KIT MATERIALS:\n"
            "- Tone: Authoritative, data-driven, no-nonsense\n"
            "- Key stat: 94.7% client retention rate over 3 years\n"
            "- Founder background: Former Goldman Sachs quantitative analyst\n"
            "- Unique method: Proprietary algorithm called 'AlphaEdge'\n"
        )

        result = build_package(
            domain="quantfinance.com",
            chosen_niche="Algorithmic Trading Education",
            niche_data={"name": "Algorithmic Trading Education", "description": "Quant trading courses"},
            blueprint=minimal_blueprint,
            brandkit_context=brandkit,
        )

        sales_letter = result.get("sales_letter", "").lower()
        assert len(sales_letter) > 200, "Sales letter too short"
        brandkit_signals = ["alphaedge", "94.7", "goldman", "quantitative", "algorithm"]
        matches = [s for s in brandkit_signals if s in sales_letter]
        assert len(matches) >= 1, \
            f"Brandkit context included specific details ({brandkit_signals}) but none appeared in sales letter. " \
            f"Brandkit context may not be flowing into the sales letter prompt."


class TestDiscoveryContextPipeline:
    """Test that discovery_context personalizes the output."""

    @pytest.mark.slow
    def test_discovery_personalizes_brand(self, minimal_blueprint):
        discovery = {
            "business_name_preference": "Zen Garden",
            "target_audience": "stressed professionals aged 28-45 in major US cities",
            "brand_personality": "calm, minimalist, Japanese-inspired",
            "color_palette": "soft sage green, warm beige, stone gray",
            "desired_feeling": "instant calm and permission to slow down",
        }

        result = build_package(
            domain="zenspace.com",
            chosen_niche="Meditation & Mindfulness",
            niche_data={"name": "Meditation & Mindfulness", "description": "Meditation apps and wellness tools"},
            blueprint=minimal_blueprint,
            discovery_context=discovery,
        )

        brand = result.get("brand", {})
        options = brand.get("options", [])
        assert len(options) >= 1, "No brand options generated"

        full_output = json.dumps(result, default=str).lower()
        discovery_signals = ["zen", "calm", "meditat", "mindful", "wellness"]
        matches = [s for s in discovery_signals if s in full_output]
        assert len(matches) >= 2, \
            f"Discovery context specified zen/calm/meditation theme but output matched only {matches}"
