from __future__ import annotations
import re
from typing import Optional, List
import time
import logging
from youtube_transcript_api import YouTubeTranscriptApi, NoTranscriptFound, TranscriptsDisabled
import json as _json
from urllib.request import urlopen as _urlopen
from urllib.parse import quote as _quote
from .common import make_structured
from ..config import settings

_YT_RE = re.compile(r"(?:v=|youtu\.be/|/shorts/)([A-Za-z0-9_-]{11})")

def _video_id(url_or_id: str) -> Optional[str]:
    if len(url_or_id) == 11 and re.match(r"^[A-Za-z0-9_-]{11}$", url_or_id):
        return url_or_id
    m = _YT_RE.search(url_or_id)
    return m.group(1) if m else None

def _format_transcript(tr: List[dict]) -> str:
    lines = []
    for item in tr:
        start = float(item.get("start", 0.0))
        text = item.get("text","").replace("\n"," ")
        mm = int(start // 60); ss = int(start % 60)
        lines.append(f"[{mm:02d}:{ss:02d}] {text}")
    return "\n".join(lines)

# Prefer instance API; fall back to generated transcript if needed
def _fetch_transcript(vid: str, *, retries: int = 2, delay: float = 0.6) -> List[dict]:
    """Fetch transcript with minimal retry and diagnostic logging.

    Retries transient generic Exceptions (network / HTTP). Specific absence exceptions are raised immediately.
    """
    langs = ["en", "en-US", "en-GB"]
    ytt = YouTubeTranscriptApi()
    attempt = 0
    while True:
        attempt += 1
        try:
            return ytt.fetch(vid, languages=langs).to_raw_data()
        except NoTranscriptFound:
            # try auto-generated English transcript
            listing = ytt.list(vid)
            return listing.find_generated_transcript(langs).fetch().to_raw_data()
        except TranscriptsDisabled:
            raise
        except Exception as e:  # transient or unexpected
            if settings.debug:
                logging.getLogger("granule.ingest.youtube").warning(
                    "Transcript fetch attempt %s failed for %s: %s", attempt, vid, repr(e)
                )
            if attempt > retries:
                raise
            time.sleep(delay)

def _fetch_title(vid: str) -> str | None:
    """Try to pull the video title via YouTube oEmbed (no extra deps)."""
    try:
        oembed_url = f"https://www.youtube.com/oembed?url=https://www.youtube.com/watch?v={_quote(vid)}&format=json"
        with _urlopen(oembed_url, timeout=5) as resp:  # type: ignore
            data = _json.loads(resp.read().decode("utf-8"))
            return data.get("title") if isinstance(data, dict) else None
    except Exception:  # pragma: no cover - network variability
        return None

def ingest_youtube(url_or_id: str, title: str | None = None):
    vid = _video_id(url_or_id) or url_or_id
    log = logging.getLogger("granule.ingest.youtube")
    # Resolve title if not explicitly provided
    resolved_title = title or _fetch_title(vid) or "YouTube Video"
    try:
        tr = _fetch_transcript(vid)
        text = _format_transcript(tr)
        doc = make_structured(
            text,
            kind="youtube",
            url=f"https://www.youtube.com/watch?v={vid}",
            title=resolved_title,
        )
        return doc
    except (NoTranscriptFound, TranscriptsDisabled) as e:
        if settings.debug:
            log.info("Transcript unavailable for %s (%s): %s", vid, type(e).__name__, str(e))
        placeholder = make_structured(
            f"[NO TRANSCRIPT AVAILABLE for {vid}]",
            kind="youtube",
            url=f"https://www.youtube.com/watch?v={vid}",
            title=resolved_title,
        )
        placeholder.extras["ingest_error"] = {
            "type": type(e).__name__,
            "message": str(e),
            "stage": "fetch",
        }
        return placeholder
    except Exception as e:  # unexpected
        if settings.debug:
            log.error("Unexpected ingest failure for %s: %s", vid, repr(e))
        placeholder = make_structured(
            f"[NO TRANSCRIPT AVAILABLE for {vid}]",
            kind="youtube",
            url=f"https://www.youtube.com/watch?v={vid}",
            title=resolved_title,
        )
        placeholder.extras["ingest_error"] = {
            "type": type(e).__name__,
            "message": str(e),
            "stage": "unexpected",
        }
        return placeholder