"""Brand profiles and brand-fit validation for public channels."""

from __future__ import annotations

from dataclasses import dataclass, replace

from autoshorts.ideas.candidate import ValidationResult, VideoCandidate, validate_candidate
from autoshorts.strategy.series import FORBIDDEN_PUBLIC_TOPIC_PATTERNS


@dataclass(frozen=True)
class BrandProfile:
    brand_id: str
    channel_name: str
    youtube_handle: str
    tiktok_handle: str
    tagline: str
    positioning: str
    audience_promise: str
    tone: tuple[str, ...]
    visual_rules: tuple[str, ...]
    default_hashtags: tuple[str, ...]
    youtube_tags: tuple[str, ...]
    public_youtube_description: str
    public_tiktok_bio: str
    forbidden_public_topics: tuple[str, ...]
    generic_ai_tips_patterns: tuple[str, ...]
    mechanism_keywords: tuple[str, ...]


TRUETRACE_SHORTS_BRAND = BrandProfile(
    brand_id="truetrace_shorts",
    channel_name="True Trace Shorts",
    youtube_handle="@TrueTraceShorts",
    tiktok_handle="@truetraceshorts",
    tagline="Systems over prompts.",
    positioning="Trace the real mechanism behind AI workflows, productivity systems, and tech hype.",
    audience_promise="Useful AI workflow systems, mechanism reveals, and hype checks without generic tips.",
    tone=("clear", "skeptical", "practical", "mechanism-first", "non-hype"),
    visual_rules=(
        "dark mechanism diagrams",
        "trace-line motif",
        "high contrast captions",
        "renderer-owned text",
        "no robot mascot as main identity",
        "no sensitive internal visuals",
    ),
    default_hashtags=("#AI", "#AISystems", "#Workflow", "#Productivity"),
    youtube_tags=(
        "AI",
        "AI systems",
        "workflow automation",
        "prompt engineering",
        "productivity systems",
        "AI productivity",
        "automation",
        "short form learning",
    ),
    public_youtube_description=(
        "True Trace Shorts traces the real mechanisms behind AI workflows, productivity systems, and tech hype.\n\n"
        "No prompt worship. No generic AI-tool lists. No fake guru theatre.\n\n"
        "Expect short, practical breakdowns on AI systems, workflow mistakes, hype checks, and simple rules "
        "for using AI without losing control."
    ),
    public_tiktok_bio="AI systems, workflow teardowns & hype checks. No prompt worship. Just mechanisms.",
    forbidden_public_topics=tuple(FORBIDDEN_PUBLIC_TOPIC_PATTERNS),
    generic_ai_tips_patterns=(
        "best ai tools",
        "ai tools you need",
        "unlock your full potential",
        "follow for more ai tips",
        "in this video",
        "game changer",
    ),
    mechanism_keywords=(
        "system",
        "systems",
        "workflow",
        "mechanism",
        "boundary",
        "trace",
        "hype",
        "verdict",
        "evidence",
        "rule",
        "autopsy",
        "failure",
        "fix",
    ),
)


def _is_blank(value: str) -> bool:
    return not (value or "").strip()


def _candidate_public_text(candidate: VideoCandidate) -> str:
    return " ".join(
        (
            candidate.title,
            candidate.hook,
            candidate.script_outline,
            candidate.visual_concept,
            candidate.caption,
            candidate.cta,
        )
    ).casefold()


def _forbidden_matches(text: str, brand: BrandProfile) -> tuple[str, ...]:
    matches: list[str] = []
    for canonical_topic in brand.forbidden_public_topics:
        patterns = FORBIDDEN_PUBLIC_TOPIC_PATTERNS.get(canonical_topic, (canonical_topic,))
        if any(pattern in text for pattern in patterns):
            matches.append(canonical_topic)
    return tuple(matches)


def _contains_forbidden_brand_text(brand: BrandProfile) -> tuple[str, ...]:
    public_text = " ".join(
        (
            brand.channel_name,
            brand.tagline,
            brand.positioning,
            brand.audience_promise,
            brand.public_youtube_description,
            brand.public_tiktok_bio,
            " ".join(brand.tone),
            " ".join(brand.visual_rules),
            " ".join(brand.default_hashtags),
            " ".join(brand.youtube_tags),
        )
    ).casefold()
    return _forbidden_matches(public_text, brand)


def validate_brand_profile(brand: BrandProfile) -> ValidationResult:
    errors: list[str] = []
    for field_name, value in {
        "brand_id": brand.brand_id,
        "channel_name": brand.channel_name,
        "youtube_handle": brand.youtube_handle,
        "tiktok_handle": brand.tiktok_handle,
        "tagline": brand.tagline,
        "positioning": brand.positioning,
        "audience_promise": brand.audience_promise,
        "public_youtube_description": brand.public_youtube_description,
        "public_tiktok_bio": brand.public_tiktok_bio,
    }.items():
        if _is_blank(value):
            errors.append(f"{field_name} is required")

    for field_name, values in {
        "tone": brand.tone,
        "visual_rules": brand.visual_rules,
        "default_hashtags": brand.default_hashtags,
        "youtube_tags": brand.youtube_tags,
        "forbidden_public_topics": brand.forbidden_public_topics,
        "generic_ai_tips_patterns": brand.generic_ai_tips_patterns,
        "mechanism_keywords": brand.mechanism_keywords,
    }.items():
        if not values:
            errors.append(f"{field_name} is required")
        elif any(_is_blank(value) for value in values):
            errors.append(f"{field_name} must not contain blank values")

    for hashtag in brand.default_hashtags:
        if not hashtag.startswith("#"):
            errors.append(f"default hashtag must start with #: {hashtag}")

    for match in _contains_forbidden_brand_text(brand):
        errors.append(f"brand profile uses forbidden public topic: {match}")

    return ValidationResult(is_valid=not errors, errors=tuple(errors))


def validate_candidate_brand_fit(candidate: VideoCandidate, brand: BrandProfile = TRUETRACE_SHORTS_BRAND) -> ValidationResult:
    errors: list[str] = []
    candidate_validation = validate_candidate(candidate)
    if not candidate_validation.is_valid:
        errors.extend(candidate_validation.errors)

    brand_validation = validate_brand_profile(brand)
    if not brand_validation.is_valid:
        errors.extend(brand_validation.errors)

    public_text = _candidate_public_text(candidate)
    for match in _forbidden_matches(public_text, brand):
        errors.append(f"candidate uses forbidden public topic: {match}")

    if not any(keyword in public_text for keyword in brand.mechanism_keywords):
        errors.append("candidate does not fit brand promise: mechanisms over hype")

    if any(pattern in public_text for pattern in brand.generic_ai_tips_patterns):
        errors.append("candidate uses generic AI tips positioning")

    return ValidationResult(is_valid=not errors, errors=tuple(dict.fromkeys(errors)))


def apply_brand_metadata(candidate: VideoCandidate, brand: BrandProfile = TRUETRACE_SHORTS_BRAND) -> VideoCandidate:
    candidate_validation = validate_candidate(candidate)
    if not candidate_validation.is_valid:
        raise ValueError("; ".join(candidate_validation.errors))
    brand_validation = validate_brand_profile(brand)
    if not brand_validation.is_valid:
        raise ValueError("; ".join(brand_validation.errors))

    hashtags = list(candidate.hashtags)
    for hashtag in brand.default_hashtags:
        if hashtag not in hashtags:
            hashtags.append(hashtag)

    policy_notes = list(candidate.policy_notes)
    for note in (f"Brand: {brand.brand_id}", f"Public tagline: {brand.tagline}"):
        if note not in policy_notes:
            policy_notes.append(note)

    branded = replace(candidate, hashtags=tuple(hashtags), policy_notes=tuple(policy_notes))
    brand_fit = validate_candidate_brand_fit(branded, brand)
    if not brand_fit.is_valid:
        raise ValueError("; ".join(brand_fit.errors))
    return branded
