"""
Video API Router - Modular Video Entity System
Videos can be linked to multiple entities: shows, performances, songs, musicians
Building for scale - no shortcuts.
"""
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlmodel import Session, select
from database import get_session
from models import (
    Video, VideoShow, VideoPerformance, VideoSong, VideoMusician,
    Show, Performance, Song, Musician, Vertical,
    VideoType, VideoPlatform
)
from pydantic import BaseModel
from datetime import datetime
import re

router = APIRouter(prefix="/videos", tags=["videos"])


# --- Schemas ---

class VideoCreate(BaseModel):
    url: str
    title: Optional[str] = None
    description: Optional[str] = None
    platform: Optional[str] = "youtube"
    video_type: Optional[str] = "single_song"
    duration_seconds: Optional[int] = None
    thumbnail_url: Optional[str] = None
    vertical_id: Optional[int] = None
    # Link IDs (optional on create)
    show_ids: Optional[List[int]] = None
    performance_ids: Optional[List[int]] = None
    song_ids: Optional[List[int]] = None
    musician_ids: Optional[List[int]] = None


class VideoRead(BaseModel):
    id: int
    url: str
    title: Optional[str]
    description: Optional[str]
    platform: str
    video_type: str
    duration_seconds: Optional[int]
    thumbnail_url: Optional[str]
    external_id: Optional[str]
    recorded_date: Optional[datetime]
    published_date: Optional[datetime]
    created_at: datetime
    vertical_id: Optional[int]
    
    class Config:
        from_attributes = True


class VideoWithRelations(VideoRead):
    """Video with linked entities"""
    shows: List[dict] = []
    performances: List[dict] = []
    songs: List[dict] = []
    musicians: List[dict] = []


# --- Helpers ---

def extract_youtube_id(url: str) -> Optional[str]:
    """Extract YouTube video ID from URL"""
    patterns = [
        r'(?:youtube\.com/watch\?v=|youtu\.be/|youtube\.com/embed/)([a-zA-Z0-9_-]{11})',
    ]
    for pattern in patterns:
        match = re.search(pattern, url)
        if match:
            return match.group(1)
    return None


def detect_platform(url: str) -> str:
    """Detect video platform from URL"""
    url_lower = url.lower()
    if 'youtube.com' in url_lower or 'youtu.be' in url_lower:
        return "youtube"
    elif 'vimeo.com' in url_lower:
        return "vimeo"
    elif 'nugs.net' in url_lower:
        return "nugs"
    elif 'bandcamp.com' in url_lower:
        return "bandcamp"
    elif 'archive.org' in url_lower:
        return "archive"
    return "other"


# --- Endpoints ---

@router.get("/", response_model=List[VideoRead])
def list_videos(
    limit: int = Query(default=50, le=200),
    offset: int = 0,
    platform: Optional[str] = None,
    video_type: Optional[str] = None,
    vertical_id: Optional[int] = None,
    session: Session = Depends(get_session)
):
    """List all videos with optional filters"""
    query = select(Video).order_by(Video.created_at.desc())
    
    if platform:
        query = query.where(Video.platform == platform)
    if video_type:
        query = query.where(Video.video_type == video_type)
    if vertical_id:
        query = query.where(Video.vertical_id == vertical_id)
    
    query = query.offset(offset).limit(limit)
    videos = session.exec(query).all()
    
    # Convert to response format
    return [
        VideoRead(
            id=v.id,
            url=v.url,
            title=v.title,
            description=v.description,
            platform=v.platform.value if hasattr(v.platform, 'value') else str(v.platform),
            video_type=v.video_type.value if hasattr(v.video_type, 'value') else str(v.video_type),
            duration_seconds=v.duration_seconds,
            thumbnail_url=v.thumbnail_url,
            external_id=v.external_id,
            recorded_date=v.recorded_date,
            published_date=v.published_date,
            created_at=v.created_at,
            vertical_id=v.vertical_id,
        )
        for v in videos
    ]


@router.get("/stats")
def get_video_stats(session: Session = Depends(get_session)):
    """Get video statistics"""
    from sqlmodel import func
    
    total_videos = session.exec(select(func.count(Video.id))).one()
    
    # Count by platform
    youtube_count = session.exec(
        select(func.count(Video.id)).where(Video.platform == VideoPlatform.YOUTUBE)
    ).one()
    
    # Count by type
    full_show_count = session.exec(
        select(func.count(Video.id)).where(Video.video_type == VideoType.FULL_SHOW)
    ).one()
    
    return {
        "total_videos": total_videos,
        "youtube_videos": youtube_count,
        "full_show_videos": full_show_count,
    }


@router.get("/{video_id}", response_model=VideoWithRelations)
def get_video(video_id: int, session: Session = Depends(get_session)):
    """Get a single video with all relationships"""
    video = session.get(Video, video_id)
    if not video:
        raise HTTPException(status_code=404, detail="Video not found")
    
    # Build response with relations
    return VideoWithRelations(
        id=video.id,
        url=video.url,
        title=video.title,
        description=video.description,
        platform=video.platform.value if hasattr(video.platform, 'value') else str(video.platform),
        video_type=video.video_type.value if hasattr(video.video_type, 'value') else str(video.video_type),
        duration_seconds=video.duration_seconds,
        thumbnail_url=video.thumbnail_url,
        external_id=video.external_id,
        recorded_date=video.recorded_date,
        published_date=video.published_date,
        created_at=video.created_at,
        vertical_id=video.vertical_id,
        shows=[{"id": vs.show.id, "date": vs.show.date.isoformat(), "slug": vs.show.slug} for vs in video.shows if vs.show],
        performances=[{"id": vp.performance.id, "slug": vp.performance.slug} for vp in video.performances if vp.performance],
        songs=[{"id": vs.song.id, "title": vs.song.title, "slug": vs.song.slug} for vs in video.songs if vs.song],
        musicians=[{"id": vm.musician.id, "name": vm.musician.name, "slug": vm.musician.slug} for vm in video.musicians if vm.musician],
    )


@router.post("/", response_model=VideoRead)
def create_video(video_data: VideoCreate, session: Session = Depends(get_session)):
    """Create a new video with optional entity links"""
    
    # Auto-detect platform
    platform = detect_platform(video_data.url)
    
    # Extract external ID for YouTube
    external_id = None
    if platform == "youtube":
        external_id = extract_youtube_id(video_data.url)
    
    # Map string to enum
    try:
        platform_enum = VideoPlatform(platform)
    except ValueError:
        platform_enum = VideoPlatform.OTHER
    
    try:
        video_type_enum = VideoType(video_data.video_type or "single_song")
    except ValueError:
        video_type_enum = VideoType.OTHER
    
    # Create video
    video = Video(
        url=video_data.url,
        title=video_data.title,
        description=video_data.description,
        platform=platform_enum,
        video_type=video_type_enum,
        duration_seconds=video_data.duration_seconds,
        thumbnail_url=video_data.thumbnail_url,
        external_id=external_id,
        vertical_id=video_data.vertical_id,
    )
    session.add(video)
    session.commit()
    session.refresh(video)
    
    # Create relationships
    if video_data.show_ids:
        for show_id in video_data.show_ids:
            link = VideoShow(video_id=video.id, show_id=show_id)
            session.add(link)
    
    if video_data.performance_ids:
        for perf_id in video_data.performance_ids:
            link = VideoPerformance(video_id=video.id, performance_id=perf_id)
            session.add(link)
    
    if video_data.song_ids:
        for song_id in video_data.song_ids:
            link = VideoSong(video_id=video.id, song_id=song_id)
            session.add(link)
    
    if video_data.musician_ids:
        for musician_id in video_data.musician_ids:
            link = VideoMusician(video_id=video.id, musician_id=musician_id)
            session.add(link)
    
    session.commit()
    
    return VideoRead(
        id=video.id,
        url=video.url,
        title=video.title,
        description=video.description,
        platform=video.platform.value if hasattr(video.platform, 'value') else str(video.platform),
        video_type=video.video_type.value if hasattr(video.video_type, 'value') else str(video.video_type),
        duration_seconds=video.duration_seconds,
        thumbnail_url=video.thumbnail_url,
        external_id=video.external_id,
        recorded_date=video.recorded_date,
        published_date=video.published_date,
        created_at=video.created_at,
        vertical_id=video.vertical_id,
    )


# --- Entity-specific video endpoints ---

@router.get("/by-show/{show_id}", response_model=List[VideoRead])
def get_videos_for_show(show_id: int, session: Session = Depends(get_session)):
    """Get all videos linked to a specific show"""
    query = select(Video).join(VideoShow).where(VideoShow.show_id == show_id)
    videos = session.exec(query).all()
    return [
        VideoRead(
            id=v.id, url=v.url, title=v.title, description=v.description,
            platform=v.platform.value if hasattr(v.platform, 'value') else str(v.platform),
            video_type=v.video_type.value if hasattr(v.video_type, 'value') else str(v.video_type),
            duration_seconds=v.duration_seconds, thumbnail_url=v.thumbnail_url,
            external_id=v.external_id, recorded_date=v.recorded_date,
            published_date=v.published_date, created_at=v.created_at, vertical_id=v.vertical_id
        ) for v in videos
    ]


@router.get("/by-performance/{performance_id}", response_model=List[VideoRead])
def get_videos_for_performance(performance_id: int, session: Session = Depends(get_session)):
    """Get all videos linked to a specific performance"""
    query = select(Video).join(VideoPerformance).where(VideoPerformance.performance_id == performance_id)
    videos = session.exec(query).all()
    return [
        VideoRead(
            id=v.id, url=v.url, title=v.title, description=v.description,
            platform=v.platform.value if hasattr(v.platform, 'value') else str(v.platform),
            video_type=v.video_type.value if hasattr(v.video_type, 'value') else str(v.video_type),
            duration_seconds=v.duration_seconds, thumbnail_url=v.thumbnail_url,
            external_id=v.external_id, recorded_date=v.recorded_date,
            published_date=v.published_date, created_at=v.created_at, vertical_id=v.vertical_id
        ) for v in videos
    ]


@router.get("/by-song/{song_id}", response_model=List[VideoRead])
def get_videos_for_song(song_id: int, session: Session = Depends(get_session)):
    """Get all videos linked to a specific song"""
    query = select(Video).join(VideoSong).where(VideoSong.song_id == song_id)
    videos = session.exec(query).all()
    return [
        VideoRead(
            id=v.id, url=v.url, title=v.title, description=v.description,
            platform=v.platform.value if hasattr(v.platform, 'value') else str(v.platform),
            video_type=v.video_type.value if hasattr(v.video_type, 'value') else str(v.video_type),
            duration_seconds=v.duration_seconds, thumbnail_url=v.thumbnail_url,
            external_id=v.external_id, recorded_date=v.recorded_date,
            published_date=v.published_date, created_at=v.created_at, vertical_id=v.vertical_id
        ) for v in videos
    ]


@router.get("/by-musician/{musician_id}", response_model=List[VideoRead])
def get_videos_for_musician(musician_id: int, session: Session = Depends(get_session)):
    """Get all videos linked to a specific musician"""
    query = select(Video).join(VideoMusician).where(VideoMusician.musician_id == musician_id)
    videos = session.exec(query).all()
    return [
        VideoRead(
            id=v.id, url=v.url, title=v.title, description=v.description,
            platform=v.platform.value if hasattr(v.platform, 'value') else str(v.platform),
            video_type=v.video_type.value if hasattr(v.video_type, 'value') else str(v.video_type),
            duration_seconds=v.duration_seconds, thumbnail_url=v.thumbnail_url,
            external_id=v.external_id, recorded_date=v.recorded_date,
            published_date=v.published_date, created_at=v.created_at, vertical_id=v.vertical_id
        ) for v in videos
    ]


@router.get("/by-band/{vertical_slug}", response_model=List[VideoRead])
def get_videos_for_band(
    vertical_slug: str,
    limit: int = Query(default=50, le=200),
    session: Session = Depends(get_session)
):
    """Get all videos for a band/vertical"""
    vertical = session.exec(select(Vertical).where(Vertical.slug == vertical_slug)).first()
    if not vertical:
        raise HTTPException(status_code=404, detail="Band not found")
    
    query = select(Video).where(Video.vertical_id == vertical.id).order_by(Video.created_at.desc()).limit(limit)
    videos = session.exec(query).all()
    return [
        VideoRead(
            id=v.id, url=v.url, title=v.title, description=v.description,
            platform=v.platform.value if hasattr(v.platform, 'value') else str(v.platform),
            video_type=v.video_type.value if hasattr(v.video_type, 'value') else str(v.video_type),
            duration_seconds=v.duration_seconds, thumbnail_url=v.thumbnail_url,
            external_id=v.external_id, recorded_date=v.recorded_date,
            published_date=v.published_date, created_at=v.created_at, vertical_id=v.vertical_id
        ) for v in videos
    ]


# --- Link management endpoints ---

@router.post("/{video_id}/link-show/{show_id}")
def link_video_to_show(video_id: int, show_id: int, session: Session = Depends(get_session)):
    """Link a video to a show"""
    video = session.get(Video, video_id)
    show = session.get(Show, show_id)
    if not video or not show:
        raise HTTPException(status_code=404, detail="Video or show not found")
    
    existing = session.exec(
        select(VideoShow).where(VideoShow.video_id == video_id, VideoShow.show_id == show_id)
    ).first()
    if existing:
        return {"message": "Already linked"}
    
    link = VideoShow(video_id=video_id, show_id=show_id)
    session.add(link)
    session.commit()
    return {"message": "Linked successfully"}


@router.post("/{video_id}/link-performance/{performance_id}")
def link_video_to_performance(
    video_id: int, 
    performance_id: int,
    timestamp_start: Optional[int] = Query(default=None),
    timestamp_end: Optional[int] = Query(default=None),
    session: Session = Depends(get_session)
):
    """Link a video to a performance with optional timestamps"""
    video = session.get(Video, video_id)
    performance = session.get(Performance, performance_id)
    if not video or not performance:
        raise HTTPException(status_code=404, detail="Video or performance not found")
    
    existing = session.exec(
        select(VideoPerformance).where(
            VideoPerformance.video_id == video_id, 
            VideoPerformance.performance_id == performance_id
        )
    ).first()
    if existing:
        return {"message": "Already linked"}
    
    link = VideoPerformance(
        video_id=video_id, 
        performance_id=performance_id,
        timestamp_start=timestamp_start,
        timestamp_end=timestamp_end
    )
    session.add(link)
    session.commit()
    return {"message": "Linked successfully"}


@router.post("/{video_id}/link-song/{song_id}")
def link_video_to_song(video_id: int, song_id: int, session: Session = Depends(get_session)):
    """Link a video to a song"""
    video = session.get(Video, video_id)
    song = session.get(Song, song_id)
    if not video or not song:
        raise HTTPException(status_code=404, detail="Video or song not found")
    
    existing = session.exec(
        select(VideoSong).where(VideoSong.video_id == video_id, VideoSong.song_id == song_id)
    ).first()
    if existing:
        return {"message": "Already linked"}
    
    link = VideoSong(video_id=video_id, song_id=song_id)
    session.add(link)
    session.commit()
    return {"message": "Linked successfully"}


@router.post("/{video_id}/link-musician/{musician_id}")
def link_video_to_musician(
    video_id: int, 
    musician_id: int,
    role: Optional[str] = Query(default=None),
    session: Session = Depends(get_session)
):
    """Link a video to a musician"""
    video = session.get(Video, video_id)
    musician = session.get(Musician, musician_id)
    if not video or not musician:
        raise HTTPException(status_code=404, detail="Video or musician not found")
    
    existing = session.exec(
        select(VideoMusician).where(VideoMusician.video_id == video_id, VideoMusician.musician_id == musician_id)
    ).first()
    if existing:
        return {"message": "Already linked"}
    
    link = VideoMusician(video_id=video_id, musician_id=musician_id, role=role)
    session.add(link)
    session.commit()
    return {"message": "Linked successfully"}


# --- Legacy compatibility: Also return youtube_link from existing Show/Performance fields ---

@router.get("/legacy/all")
def get_legacy_videos(
    limit: int = Query(default=100, le=500),
    offset: int = Query(default=0),
    session: Session = Depends(get_session)
):
    """Legacy endpoint: Get shows and performances with youtube_link fields (for backwards compatibility)"""
    from models import Venue
    
    # Get performances with youtube_link
    perf_query = (
        select(
            Performance.id,
            Performance.youtube_link,
            Performance.show_id,
            Song.id.label("song_id"),
            Song.title.label("song_title"),
            Song.slug.label("song_slug"),
            Show.date,
            Show.slug.label("show_slug"),
            Venue.name.label("venue_name"),
            Venue.city.label("venue_city"),
            Venue.state.label("venue_state"),
        )
        .join(Song, Performance.song_id == Song.id)
        .join(Show, Performance.show_id == Show.id)
        .outerjoin(Venue, Show.venue_id == Venue.id)
        .where(Performance.youtube_link != None)
        .order_by(Show.date.desc())
        .limit(limit)
        .offset(offset)
    )
    
    perf_results = session.exec(perf_query).all()
    
    performances = [
        {
            "type": "performance",
            "id": r[0],
            "youtube_link": r[1],
            "show_id": r[2],
            "song_id": r[3],
            "song_title": r[4],
            "date": r[6].isoformat() if r[6] else None,
            "show_slug": r[7],
            "venue_name": r[8],
            "venue_city": r[9],
            "venue_state": r[10],
        }
        for r in perf_results
    ]
    
    # Get shows with youtube_link
    show_query = (
        select(
            Show.id,
            Show.youtube_link,
            Show.date,
            Show.slug,
            Venue.name.label("venue_name"),
            Venue.city.label("venue_city"),
            Venue.state.label("venue_state"),
        )
        .outerjoin(Venue, Show.venue_id == Venue.id)
        .where(Show.youtube_link != None)
        .order_by(Show.date.desc())
        .limit(limit)
        .offset(offset)
    )
    
    show_results = session.exec(show_query).all()
    
    shows = [
        {
            "type": "full_show",
            "id": r[0],
            "youtube_link": r[1],
            "date": r[2].isoformat() if r[2] else None,
            "show_slug": r[3],
            "venue_name": r[4],
            "venue_city": r[5],
            "venue_state": r[6],
        }
        for r in show_results
    ]
    
    return {
        "performances": performances,
        "shows": shows,
        "total_performances": len(performances),
        "total_shows": len(shows)
    }
