"""
Recommendations and releases routes for Ohm Stream Downloader API.
"""

import hashlib
import logging
from datetime import datetime
from typing import Optional, List, Dict, Any

from fastapi import APIRouter, Request, Query, HTTPException, Depends
from fastapi.templating import Jinja2Templates
from sqlmodel import Session, select

from app.recommendation_engine import RecommendationEngine
from app.models.auth import User
from app.models.settings import AppSettingsTable
from app.database import get_session
from app.routers.router_auth import get_optional_user, get_current_user_from_token
from app.routers.router_settings import _compute_auto_weights

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/api", tags=["recommendations"])
templates = Jinja2Templates(directory="templates")

# Add custom filters to Jinja2
def hash_filter(s):
    return hashlib.md5(s.encode()).hexdigest()[:10]

templates.env.filters["hash"] = hash_filter


def _get_effective_weights(session: Session, user_id: str) -> tuple:
    """Return (anime_enabled, series_enabled, anime_weight, series_weight)."""
    settings = session.exec(
        select(AppSettingsTable).where(AppSettingsTable.user_id == user_id)
    ).first()

    if settings is None:
        return True, True, 1, 1

    anime_enabled = getattr(settings, 'anime_enabled', True)
    series_enabled = getattr(settings, 'series_enabled', True)
    mode = getattr(settings, 'content_weight_mode', 'auto')
    download_dir = getattr(settings, 'download_dir', 'downloads')

    if mode == "auto":
        weights = _compute_auto_weights(download_dir)
        return anime_enabled, series_enabled, weights["anime_weight"], weights["series_weight"]
    else:
        aw = getattr(settings, 'content_weight_anime', 2)
        sw = getattr(settings, 'content_weight_series', 1)
        return anime_enabled, series_enabled, int(aw), int(sw)


def _weighted_mix(items_a: List[Dict], items_b: List[Dict], limit: int,
                  weight_a: int = 2, weight_b: int = 1) -> List[Dict]:
    """Mix two lists using weights. Distributes items proportionally and interleaves.

    If weight_a=2, weight_b=1 and limit=15:
      - slots_a ≈ 10, slots_b ≈ 5
      - B items are spaced evenly across the list
    If one list is shorter, the other fills remaining slots.
    """
    total_weight = weight_a + weight_b
    if total_weight == 0:
        return (items_a + items_b)[:limit]

    slots_a = round(limit * weight_a / total_weight)
    slots_b = limit - slots_a

    pick_a = min(slots_a, len(items_a))
    pick_b = min(slots_b, len(items_b))

    # Redistribute unfilled slots
    if pick_a < slots_a:
        pick_b = min(pick_b + (slots_a - pick_a), len(items_b))
    elif pick_b < slots_b:
        pick_a = min(pick_a + (slots_b - pick_b), len(items_a))

    a = items_a[:pick_a]
    b = items_b[:pick_b]

    total = pick_a + pick_b
    if total == 0:
        return []
    if pick_b == 0:
        return a[:limit]
    if pick_a == 0:
        return b[:limit]

    # Place B items at evenly spaced positions, fill gaps with A
    result = [None] * total
    for i, item in enumerate(b):
        pos = round(i * (total - 1) / max(pick_b - 1, 1))
        result[pos] = item
    a_idx = 0
    for i in range(total):
        if result[i] is None:
            result[i] = a[a_idx]
            a_idx += 1

    return result[:limit]


@router.get("/recommendations")
async def get_recommendations(
    request: Request,
    limit: int = 15,
    html: bool = Query(False),
    content_type: Optional[str] = Query(None, description="Filter: 'anime', 'series', or None for all"),
    current_user: Optional[User] = Depends(get_optional_user),
    session: Session = Depends(get_session),
):
    """Get personalized recommendations based on user settings (anime + series)"""
    is_htmx = request.headers.get("HX-Request")

    if current_user is None and (html or is_htmx):
        return templates.TemplateResponse(
            "components/login_prompt.html", {"request": request}
        )

    if current_user is None:
        raise HTTPException(status_code=401, detail="Authentication required")

    anime_enabled, series_enabled, anime_weight, series_weight = _get_effective_weights(session, current_user.id)
    recommendations = []

    try:
        if anime_enabled:
            engine = RecommendationEngine(download_dir="downloads")
            try:
                anime_recs = await engine.get_personalized_recommendations(limit=limit)
                for r in anime_recs:
                    r['content_type'] = 'anime'
                recommendations.extend(anime_recs)
            finally:
                await engine.close()

        if series_enabled:
            try:
                from app.downloaders.series_sites.fs7 import FS7Downloader
                downloader = FS7Downloader()
                series_recs = await downloader.get_latest_series(limit=limit)
                for r in series_recs:
                    r['content_type'] = 'series'
                recommendations.extend(series_recs)
            except Exception as e:
                logger.warning(f"Series recommendations fetch failed: {e}")

        if content_type and content_type != "all":
            recommendations = [r for r in recommendations if r.get("content_type") == content_type]
        else:
            anime_items = [r for r in recommendations if r.get("content_type") == "anime"]
            series_items = [r for r in recommendations if r.get("content_type") == "series"]
            recommendations = _weighted_mix(anime_items, series_items, limit,
                                            weight_a=anime_weight, weight_b=series_weight)

        if html or is_htmx:
            return templates.TemplateResponse(
                "components/recommendations_list.html",
                {"request": request, "recommendations": recommendations}
            )

        return {"recommendations": recommendations, "count": len(recommendations)}
    except Exception as e:
        logger.error(f"Recommendations error: {e}", exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/releases/latest")
async def get_latest_releases(
    request: Request,
    limit: int = 20,
    html: bool = Query(False),
    content_type: Optional[str] = Query(None, description="Filter: 'anime', 'series', or None for all"),
    current_user: Optional[User] = Depends(get_optional_user),
    session: Session = Depends(get_session),
):
    """Get latest releases based on user settings (anime + series)"""
    from app.recommendations import get_latest_releases_with_info

    is_htmx = request.headers.get("HX-Request")

    if current_user is None and (html or is_htmx):
        return templates.TemplateResponse(
            "components/login_prompt.html", {"request": request}
        )

    if current_user is None:
        raise HTTPException(status_code=401, detail="Authentication required")

    anime_enabled, series_enabled, anime_weight, series_weight = _get_effective_weights(session, current_user.id)
    releases = []

    try:
        if anime_enabled:
            anime_releases = await get_latest_releases_with_info(limit=limit)
            for r in anime_releases:
                r['content_type'] = 'anime'
            releases.extend(anime_releases)

        if series_enabled:
            try:
                from app.downloaders.series_sites.fs7 import FS7Downloader
                downloader = FS7Downloader()
                series_releases = await downloader.get_latest_series(limit=limit)
                for r in series_releases:
                    r['content_type'] = 'series'
                releases.extend(series_releases)
            except Exception as e:
                logger.warning(f"Series releases fetch failed: {e}")

        if content_type and content_type != "all":
            releases = [r for r in releases if r.get("content_type") == content_type]
        else:
            anime_items = [r for r in releases if r.get("content_type") == "anime"]
            series_items = [r for r in releases if r.get("content_type") == "series"]
            releases = _weighted_mix(anime_items, series_items, limit,
                                     weight_a=anime_weight, weight_b=series_weight)

        if html or is_htmx:
            return templates.TemplateResponse(
                "components/releases_list.html",
                {"request": request, "releases": releases}
            )

        return {
            "releases": releases,
            "count": len(releases),
            "updated": datetime.now().isoformat(),
        }
    except Exception as e:
        logger.error(f"Latest releases error: {e}", exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/releases/seasonal")
async def get_seasonal_anime(
    year: Optional[int] = None,
    season: Optional[str] = None,
):
    """Get current/previously seasonal anime"""
    from app.recommendations import AnimeReleasesFetcher

    fetcher = AnimeReleasesFetcher()

    try:
        anime = await fetcher.get_seasonal_anime(year, season)

        return {
            "anime": anime,
            "count": len(anime),
            "year": year or datetime.now().year,
            "season": season or "current",
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
    finally:
        await fetcher.close()


@router.get("/releases/scheduled")
async def get_scheduled_anime(day: Optional[str] = None):
    """Get anime scheduled for a specific day"""
    from app.recommendations import AnimeReleasesFetcher

    fetcher = AnimeReleasesFetcher()

    try:
        anime = await fetcher.get_scheduled_anime(day)

        return {"anime": anime, "count": len(anime), "day": day or "today"}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
    finally:
        await fetcher.close()


@router.get("/releases/top")
async def get_top_anime(
    type: str = "tv",
    limit: int = 15,
):
    """Get top rated anime"""
    from app.recommendations import AnimeReleasesFetcher

    fetcher = AnimeReleasesFetcher()

    try:
        anime = await fetcher.get_top_anime(type=type, limit=limit)

        return {"anime": anime, "count": len(anime)}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
    finally:
        await fetcher.close()


@router.get("/stats/downloads")
async def get_download_statistics(
    current_user: User = Depends(get_current_user_from_token),
):
    """Get download statistics and preferences"""
    engine = RecommendationEngine(download_dir="downloads")

    try:
        stats = await engine.get_download_stats()

        return stats
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
    finally:
        await engine.close()


@router.get("/series/latest")
async def get_latest_series(
    request: Request,
    limit: int = 20,
    html: bool = Query(False),
    current_user: Optional[User] = Depends(get_optional_user),
):
    """Get latest TV series releases from FS7 homepage"""
    if current_user is None and (html or request.headers.get("HX-Request")):
        return templates.TemplateResponse(
            "components/login_prompt.html", {"request": request}
        )

    if current_user is None:
        raise HTTPException(status_code=401, detail="Authentication required")

    try:
        from app.downloaders.series_sites.fs7 import FS7Downloader

        downloader = FS7Downloader()
        series = await downloader.get_latest_series(limit=limit)

        if html or request.headers.get("HX-Request"):
            return templates.TemplateResponse(
                "components/series_releases_list.html",
                {"request": request, "releases": series}
            )

        return {
            "releases": series,
            "count": len(series),
            "updated": datetime.now().isoformat(),
        }
    except Exception as e:
        logger.error(f"Latest series error: {e}", exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))
