from autoshorts.strategy.production_registry import (
    ExistingAssetCheck,
    PlannedKeyframe,
    PremiumVisualPolicy,
    ProductionStage,
    ReviewPackageRequired,
    WebsiteCompanionPackageRequired,
    block_unmanaged_duplicate_topic,
    load_format_families,
    load_scam_type_atlas,
    load_topic_registry,
    render_allowed,
    validate_existing_asset_check,
    validate_format_family_registry,
    validate_no_real_sensitive_data,
    validate_premium_visual_policy,
    validate_review_package_required,
    validate_scambaiting_policy,
    validate_scam_type_atlas,
    validate_stage_sequence,
    validate_topic_registry,
    validate_website_companion_package_required,
)


def valid_asset_check() -> ExistingAssetCheck:
    return ExistingAssetCheck(
        topic_id="story-fake-support-popup-v001",
        scam_type_id="technical_support_scam",
        keywords=("fake support popup", "remote access"),
        script="scripts/render_tt003_true_scam_story_support_popup.py",
        renderer="scripts/render_tt003_true_scam_story_support_popup.py",
        keyframes=("/tmp/keyframe1.png",),
        website_page="/redflags/fake-support-popup/",
        selected_source_of_truth="topic_registry:tt003-true-scam-story-fake-support-popup",
        checked=True,
    )


def valid_review_package() -> ReviewPackageRequired:
    return ReviewPackageRequired(
        candidate_id="story-fake-support-popup-v001",
        format_family="TRUE_SCAM_STORY",
        scam_type_id="technical_support_scam",
        topic_id="tt003-true-scam-story-fake-support-popup",
        script_version="v001",
        script_hash="abc123",
        existing_assets_checked=valid_asset_check(),
        selected_script_path="scripts/render_tt003_true_scam_story_support_popup.py",
        visual_policy=PremiumVisualPolicy(),
        blocked_legacy_assets=("tt002-spot-the-trap-quiz-delivery-old",),
        planned_keyframes=(
            PlannedKeyframe(
                index=1,
                scene_description="Premium AI image of a fake support popup on a laptop, no real brands or numbers.",
                visible_problem="browser warning tries to rush the viewer",
                safety_constraints=("no real domains", "no phone numbers"),
            ),
        ),
        caption_style="static phrase segments, active-word highlight, no box, no frame",
        voice="Gianna Premium Clone v1",
        website_companion_slug="fake-support-popup",
        cta="Send this to someone who panics when a warning appears.",
        expected_metric="shares_per_view",
        risks=("story must remain common-pattern educational",),
        approval_command="APPROVE_REVIEW_PACKAGE story-fake-support-popup-v001 abc123",
    )


def valid_website_companion() -> WebsiteCompanionPackageRequired:
    return WebsiteCompanionPackageRequired(
        slug="fake-support-popup",
        title="Fake Support Popup",
        hook="A scary browser popup tries to rush you into the next action.",
        scam_type_id="technical_support_scam",
        redFlag="The warning tells you to call support or approve remote access.",
        whyItWorks="It makes the screen feel official and urgent.",
        saferMove="Close the tab and open the real app or support page yourself.",
        ifAlreadyClicked=("Disconnect remote access.", "Contact your provider from an official channel."),
        checklist=("Close the tab", "Do not call the popup", "Use official support"),
        checklistDetails=("If remote access was approved, disconnect it first.",),
        videoUrl=None,
        thumbnail=None,
        toolRelevance=("browser notification settings",),
        affiliateCategory="security_basics",
        seoTitle="Fake support popup: what to do",
        metaDescription="How to handle a fake support popup without calling the scammer.",
        body="A fake support popup is a common pattern, not a real support message.",
    )


def test_format_family_registry_loads_and_uses_current_mix():
    registry = load_format_families()
    result = validate_format_family_registry(registry)

    assert result.is_valid
    assert registry["mix_percent"] == {
        "RED_FLAG_SHORT": 50,
        "ALREADY_CLICKED": 20,
        "TRUE_SCAM_STORY": 15,
        "SPOT_THE_TRAP_QUIZ": 10,
        "SCAM_BREAKDOWN": 5,
    }


def test_scam_type_atlas_loads_and_requires_safer_move_and_recovery_steps():
    atlas = load_scam_type_atlas()
    result = validate_scam_type_atlas(atlas)

    assert result.is_valid
    ids = {entry["scam_type_id"] for entry in atlas["entries"]}
    assert "technical_support_scam" in ids
    assert "fake_browser_notification" in ids
    assert len(ids) >= 20


def test_topic_registry_records_tt003_reference_and_tt002_rejected_learning_case():
    atlas = load_scam_type_atlas()
    registry = load_topic_registry()
    result = validate_topic_registry(registry, atlas)

    assert result.is_valid
    topics = {topic["topic_id"]: topic for topic in registry["topics"]}
    tt003 = topics["tt003-true-scam-story-fake-support-popup"]
    assert tt003["approved_visual_style"] == "premium_ai_keyframes_only"
    assert "positive baseline" in tt003["notes"]
    assert tt003["claim_mode"] == "generic_pattern / educational_pattern"

    tt002 = topics["tt002-spot-the-trap-quiz-delivery-old"]
    assert tt002["status"] == "rejected"
    assert tt002["reuse_allowed"] is False
    assert "powerpoint-like" in tt002["blocked_reason"]


def test_topic_registry_blocks_unmanaged_duplicate_topic():
    registry = load_topic_registry()

    duplicate = block_unmanaged_duplicate_topic(
        registry,
        topic_id="tt003-true-scam-story-fake-support-popup",
        scam_type_id="technical_support_scam",
        format_family="TRUE_SCAM_STORY",
    )
    assert not duplicate.is_valid
    assert "reuse registry source of truth" in duplicate.errors[0]

    rejected = block_unmanaged_duplicate_topic(
        registry,
        topic_id="tt002-spot-the-trap-quiz-delivery-old",
        scam_type_id="fake_delivery_text",
        format_family="SPOT_THE_TRAP_QUIZ",
    )
    assert not rejected.is_valid
    assert "rejected" in rejected.errors[0]


def test_existing_asset_check_required_before_render():
    missing = ExistingAssetCheck(topic_id="x", scam_type_id="technical_support_scam", keywords=("support",))
    result = validate_existing_asset_check(missing)

    assert not result.is_valid
    assert "EXISTING_ASSET_CHECK is required before production" in result.errors


def test_visual_policy_blocks_renderer_owned_graphics_and_powerpoint_ui():
    result = validate_premium_visual_policy(
        PremiumVisualPolicy(renderer_owned_diagrams=True, powerpoint_like_graphics=True)
    )

    assert not result.is_valid
    assert "renderer_owned_diagrams=true" in " ".join(result.errors)
    assert "powerpoint_like_graphics=true" in " ".join(result.errors)


def test_premium_ai_keyframes_only_required_for_release_candidate():
    result = validate_premium_visual_policy(PremiumVisualPolicy(premium_ai_keyframes=False))

    assert not result.is_valid
    assert "premium_ai_keyframes are required" in " ".join(result.errors)


def test_old_renderer_cannot_be_selected_unless_explicitly_approved():
    result = validate_premium_visual_policy(PremiumVisualPolicy(old_mockup_renderer=True))

    assert not result.is_valid
    assert "old_mockup_renderer=true" in " ".join(result.errors)


def test_state_machine_blocks_skipped_stages():
    result = validate_stage_sequence([ProductionStage.IDEA, ProductionStage.SCAM_TYPE_SELECTED])

    assert not result.is_valid
    assert "skipped stages" in result.errors[0]


def test_review_package_required_before_render_and_caption_style_locked():
    package = valid_review_package()
    result = validate_review_package_required(package)

    assert result.is_valid

    bad = ReviewPackageRequired(**{**package.__dict__, "caption_style": "boxed caption card"})
    bad_result = validate_review_package_required(bad)
    assert not bad_result.is_valid
    assert "static active-word" in " ".join(bad_result.errors)


def test_render_allowed_requires_review_package_and_keyframe_qa():
    result = render_allowed(
        stages=[ProductionStage.IDEA, ProductionStage.FORMAT_SELECTED, ProductionStage.SCAM_TYPE_SELECTED],
        review_package=None,
    )

    assert not result.is_valid
    assert "ReviewPackage is required before render" in result.errors
    assert "no render before KEYFRAME_QA_PASSED" in result.errors


def test_website_companion_package_required_before_upload_pack():
    stages = [stage for stage in ProductionStage][: ProductionStage.MANUAL_UPLOAD_PACK_READY.value and 14]
    result = render_allowed(stages=stages, review_package=valid_review_package(), final_or_upload_pack=True)

    assert not result.is_valid
    assert "WebsiteCompanionPackage is required before upload pack" in result.errors

    full = render_allowed(
        stages=[stage for stage in ProductionStage][:15],
        review_package=valid_review_package(),
        website_companion=valid_website_companion(),
        final_or_upload_pack=True,
    )
    assert full.is_valid


def test_website_companion_validates_required_recovery_fields():
    package = valid_website_companion()
    assert validate_website_companion_package_required(package).is_valid

    bad = WebsiteCompanionPackageRequired(**{**package.__dict__, "ifAlreadyClicked": ()})
    result = validate_website_companion_package_required(bad)
    assert not result.is_valid
    assert "ifAlreadyClicked" in " ".join(result.errors)


def test_scambaiting_hacking_action_content_blocked():
    result = validate_scambaiting_policy("Contact the scammer and hack back with malware.")

    assert not result.is_valid
    assert "scambaiting/hacking" in result.errors[0]


def test_no_real_domains_phone_bank_card_data_in_scam_examples():
    domain = validate_no_real_sensitive_data("The fake page is at courier-payments.com and asks for payment.")
    phone = validate_no_real_sensitive_data("Call +41 79 123 45 67 now.")
    iban = validate_no_real_sensitive_data("Send money to CH9300762011623852957.")
    safe = validate_no_real_sensitive_data("Use example.com only as reserved placeholder in tests.")

    assert not domain.is_valid
    assert not phone.is_valid
    assert not iban.is_valid
    assert safe.is_valid
