"""
seo_builder.py
--------------
Constructs SEOPayload from SummarizationResult + MediaMeta.
Pure function over schemas — no side effects, no filesystem writes.

Bugs fixed from the original seo_utils.py:
  - `kedomainywords_str` typo → keywords_str was always empty string
  - `thumbs_dir` NameError (undefined variable) in thumbnail branch
  - whisper_result.get("segments") AttributeError when whisper_result=None
  - `determine_remove_text` and `generate_file_id` defined twice (silent overwrite)
  - `get_from_list` used on a string (character slicer, not a list slicer)
  - `get_seo_data` bare `except: pass` masking real errors
  - domain hardcoded as "https://typicallyoutliers.com" — now comes from MediaMeta
  - audio_path called unconditionally even when None → AttributeError
"""
from __future__ import annotations

import logging
import os
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional

from .schemas import MediaMeta, SEOPayload, SummarizationResult, ThumbnailInfo

logger = logging.getLogger(__name__)

# Tags that carry no SEO value — filtered from seo_tags and keywords_str
_BANNED_TAGS: frozenset[str] = frozenset({
    "video", "audio", "file", "the", "and", "for", "this", "that",
})


# ── Internal builders ─────────────────────────────────────────────────────────

def _build_seo_title(keywords: List[str], title: str, max_length: int = 70) -> str:
    """
    Primary keyword leads, then the title.
    Truncates to max_length characters — never by indexing a list.
    """
    primary   = keywords[0] if keywords else ""
    candidate = f"{primary} - {title}" if primary else title
    return candidate[:max_length]


def _build_seo_description(summary: str, keywords: List[str], max_length: int = 300) -> str:
    """Append a keyword hint clause to the refined summary, then truncate."""
    kw_hint   = ", ".join(k for k in keywords[:5] if k)
    candidate = f"{summary.strip()} Topics covered: {kw_hint}." if kw_hint else summary.strip()
    return candidate[:max_length]


def _build_keywords_str(keywords: List[str], limit: int = 10) -> str:
    filtered = [k for k in keywords[:limit] if k.lower() not in _BANNED_TAGS]
    return ", ".join(filtered)


def _build_seo_tags(keywords: List[str]) -> List[str]:
    return [k for k in keywords if k.lower() not in _BANNED_TAGS]


def _resolve_thumbnail(
    meta:             MediaMeta,
    keywords:         List[str],
    whisper_segments: Optional[list] = None,
) -> ThumbnailInfo:
    """
    Three-tier thumbnail resolution:
      1. Whisper-scored optimal frame (if segments + thumbnails_dir are available)
      2. First path in thumbnail_paths list
      3. First file found in thumbnails_dir
    Returns an empty ThumbnailInfo rather than raising — SEO can proceed without a thumbnail.
    """
    # Tier 1: whisper-scored
    if (
        whisper_segments
        and meta.thumbnails_dir
        and os.path.isdir(meta.thumbnails_dir)
    ):
        try:
            from .seo_utils import pick_optimal_thumbnail, sort_frames
            image_files = sort_frames(directory=meta.thumbnails_dir)
            result = pick_optimal_thumbnail(
                {"segments": whisper_segments},
                keywords,
                thumbnail_paths=image_files,
                directory=meta.thumbnails_dir,
            )
            if result:
                frame_path, _score, matched_text = result
                return ThumbnailInfo(
                    file_path=frame_path,
                    alt_text=matched_text[:100],
                )
        except Exception as exc:
            logger.warning("[SEOBuilder] Whisper thumbnail scoring failed: %s", exc)

    # Tier 2: explicit list
    if meta.thumbnail_paths:
        path = meta.thumbnail_paths[0]
        return ThumbnailInfo(
            file_path=path,
            alt_text=os.path.splitext(os.path.basename(path))[0],
        )

    # Tier 3: directory scan
    if meta.thumbnails_dir and os.path.isdir(meta.thumbnails_dir):
        files = sorted(os.listdir(meta.thumbnails_dir))
        if files:
            name = files[0]
            return ThumbnailInfo(
                file_path=os.path.join(meta.thumbnails_dir, name),
                alt_text=os.path.splitext(name)[0],
            )

    return ThumbnailInfo()


def _iso_now() -> str:
    return datetime.now(timezone.utc).isoformat()


def _format_duration_iso(seconds: Optional[float]) -> Optional[str]:
    if seconds is None:
        return None
    m = int(seconds // 60)
    s = int(seconds % 60)
    return f"PT{m}M{s}S"


# ── Public API ────────────────────────────────────────────────────────────────

def build_seo_payload(
    summary_result:   SummarizationResult,
    meta:             MediaMeta,
    title:            Optional[str] = None,
    whisper_segments: Optional[list] = None,
) -> SEOPayload:
    """
    Build an SEOPayload from a SummarizationResult and MediaMeta.
    Pure function — no filesystem writes, no DB calls, no side effects.
    """
    resolved_title = title or meta.filename or summary_result.video_id
    keywords       = summary_result.keywords
    refined        = summary_result.refined_summary

    seo_title       = _build_seo_title(keywords, resolved_title)
    seo_description = _build_seo_description(refined, keywords)
    keywords_str    = _build_keywords_str(keywords)
    seo_tags        = _build_seo_tags(keywords)
    thumbnail       = _resolve_thumbnail(meta, keywords, whisper_segments)
    publication_date = _iso_now()
    duration_iso    = _format_duration_iso(meta.duration_seconds)

    schema_markup: Dict[str, Any] = {
        "@context":    "https://schema.org",
        "@type":       "VideoObject",
        "name":        seo_title,
        "description": seo_description,
        "thumbnailUrl": thumbnail.file_path,
        "duration":    duration_iso,
        "uploadDate":  publication_date,
        "contentUrl":  meta.video_path,
        "keywords":    seo_tags,
    }

    social_metadata: Dict[str, str] = {
        "og:title":            seo_title,
        "og:description":      seo_description,
        "og:image":            thumbnail.file_path or "",
        "og:video":            meta.video_path or "",
        "twitter:card":        "player",
        "twitter:title":       seo_title,
        "twitter:description": seo_description,
        "twitter:image":       thumbnail.file_path or "",
    }

    return SEOPayload(
        video_id=summary_result.video_id,
        seo_title=seo_title,
        seo_description=seo_description,
        seo_tags=seo_tags,
        keywords_str=keywords_str,
        thumbnail=thumbnail,
        duration_seconds=meta.duration_seconds,
        duration_formatted=meta.duration_formatted,
        schema_markup=schema_markup,
        social_metadata=social_metadata,
        uploader={"name": "typicallyoutliers", "url": meta.domain},
        publication_date=publication_date,
        canonical_url=meta.domain,
    )
