# -*- coding: utf-8 -*-
# Quasarr
# Project by https://github.com/rix1337

import html
import time
import traceback
import warnings
from datetime import datetime

import requests
from bs4 import BeautifulSoup, XMLParsedAsHTMLWarning

from quasarr.constants import (
    SEARCH_CAT_BOOKS,
    SEARCH_CAT_MOVIES,
    SEARCH_CAT_MUSIC,
    SEARCH_CAT_SHOWS,
)
from quasarr.providers.hostname_issues import clear_hostname_issue, mark_hostname_issue
from quasarr.providers.imdb_metadata import get_localized_title, get_year
from quasarr.providers.log import debug, error, trace, warn
from quasarr.providers.utils import (
    generate_download_link,
    get_base_search_category_id,
    is_imdb_id,
    is_valid_release,
)

warnings.filterwarnings(
    "ignore", category=XMLParsedAsHTMLWarning
)  # we dont want to use lxml

hostname = "wx"


def wx_feed(shared_state, start_time, search_category):
    """
    Fetch latest releases from RSS feed.
    """
    releases = []
    host = shared_state.values["config"]("Hostnames").get(hostname)

    base_category = get_base_search_category_id(search_category)

    if base_category in [SEARCH_CAT_BOOKS, SEARCH_CAT_MUSIC]:
        debug(
            f"<d>Skipping <y>{search_category}</y> on <g>{hostname.upper()}</g> (category not supported)!</d>"
        )
        return releases

    rss_url = f"https://{host}/rss"
    headers = {
        "User-Agent": shared_state.values["user_agent"],
    }

    try:
        r = requests.get(rss_url, headers=headers, timeout=10)
        r.raise_for_status()

        soup = BeautifulSoup(r.content, "html.parser")
        items = soup.find_all("entry")

        if not items:
            items = soup.find_all("item")

        if not items:
            warn("No entries found in RSS feed")
            return releases

        trace(f"Found {len(items)} entries in RSS feed")

        for item in items:
            try:
                title_tag = item.find("title")
                if not title_tag:
                    continue

                title = title_tag.get_text(strip=True)
                if not title:
                    continue

                title = html.unescape(title)
                title = title.replace("]]>", "").replace("<![CDATA[", "")
                title = title.replace(" ", ".")

                link_tag = item.find("link", rel="alternate")
                if link_tag and link_tag.has_attr("href"):
                    source = link_tag["href"]
                else:
                    link_tag = item.find("link")
                    if not link_tag:
                        continue
                    source = link_tag.get_text(strip=True)

                if not source:
                    continue

                pub_date = item.find("updated") or item.find("pubDate")
                if pub_date:
                    published = pub_date.get_text(strip=True)
                else:
                    # Fallback: use current time if no pubDate found
                    published = datetime.now().strftime("%a, %d %b %Y %H:%M:%S +0000")

                mb = 0
                size = 0
                imdb_id = None
                password = host.upper()

                link = generate_download_link(
                    shared_state,
                    title,
                    source,
                    mb,
                    password,
                    imdb_id or "",
                    hostname,
                )

                releases.append(
                    {
                        "details": {
                            "title": title,
                            "hostname": hostname,
                            "imdb_id": imdb_id,
                            "link": link,
                            "size": size,
                            "date": published,
                            "source": source,
                        },
                        "type": "protected",
                    }
                )

            except Exception as e:
                debug(f"Error parsing RSS entry: {e}")
                continue

    except Exception as e:
        error(f"Error loading feed: {e}")
        mark_hostname_issue(
            hostname, "feed", str(e) if "e" in dir() else "Error occurred"
        )
        return releases

    elapsed_time = time.time() - start_time
    debug(f"Time taken: {elapsed_time:.2f}s")

    if releases:
        clear_hostname_issue(hostname)
    return releases


def wx_search(
    shared_state,
    start_time,
    search_category,
    search_string,
    season=None,
    episode=None,
):
    """
    Search using internal API.
    Deduplicates results by fulltitle - each unique release appears only once.
    """
    releases = []
    host = shared_state.values["config"]("Hostnames").get(hostname)

    base_category = get_base_search_category_id(search_category)

    if base_category in [SEARCH_CAT_BOOKS, SEARCH_CAT_MUSIC]:
        debug(f"<d>Skipping <y>{search_category}</>: unsupported category.</d>")
        return releases

    imdb_id = is_imdb_id(search_string)
    if imdb_id:
        debug(f"Received IMDb ID: <y>{imdb_id}</y>")
        title = get_localized_title(shared_state, imdb_id, "de")
        if not title:
            error(f"No title found for IMDb '{imdb_id}'")
            return releases
        trace(f"Resolved IMDb '{imdb_id}' to: '{title}'")
        search_string = html.unescape(title)
    else:
        debug(f"Using search string directly: '{search_string}'")

    api_url = f"https://api.{host}/start/search"

    headers = {
        "User-Agent": shared_state.values["user_agent"],
        "Accept": "application/json, text/plain, */*",
        "Referer": f"https://{host}/search",
    }

    params = {
        "__LOAD_P": "",
        "per_page": 50,
        "q": search_string,
        "selectedTypes": "",
        "selectedGenres": "",
        "types": "movie,series,anime",
        "genres": "",
        "years": year if (year := get_year(imdb_id)) else "",
        "ratings": "",
        "page": 1,
        "sortBy": "latest",
        "sortOrder": "desc",
    }

    if base_category == SEARCH_CAT_SHOWS:
        params["types"] = "series,anime"
    elif base_category == SEARCH_CAT_MOVIES:
        params["types"] = "movie"
    else:
        warn(f"Unknown search category: {search_category}")
        return releases

    trace(f"Searching: '{search_string}'")

    try:
        r = requests.get(api_url, headers=headers, params=params, timeout=10)
        r.raise_for_status()

        data = r.json()

        if "items" in data and "data" in data["items"]:
            items = data["items"]["data"]
        elif "data" in data:
            items = data["data"]
        elif "results" in data:
            items = data["results"]
        else:
            items = data if isinstance(data, list) else []

        trace(f"Found {len(items)} items in search results")

        # Track seen titles to deduplicate (mirrors have same fulltitle)
        seen_titles = set()

        for item in items:
            try:
                uid = item.get("uid")
                if not uid:
                    debug("Item has no UID, skipping")
                    continue

                trace(f"Fetching details for UID: {uid}")

                detail_url = f"https://api.{host}/start/d/{uid}"
                detail_r = requests.get(detail_url, headers=headers, timeout=10)
                detail_r.raise_for_status()

                detail_data = detail_r.json()

                if "item" in detail_data:
                    detail_item = detail_data["item"]
                else:
                    detail_item = detail_data

                item_imdb_id = detail_item.get("imdb_id") or detail_item.get("imdbid")
                if not item_imdb_id and "options" in detail_item:
                    item_imdb_id = detail_item["options"].get("imdb_id")

                if item_imdb_id and imdb_id and item_imdb_id != imdb_id:
                    debug(
                        f"IMDb-ID mismatch ({imdb_id} != {item_imdb_id}), skipping item"
                    )
                    continue

                if item_imdb_id is None:
                    item_imdb_id = imdb_id

                source = f"https://{host}/detail/{uid}"

                main_title = (
                    detail_item.get("fulltitle")
                    or detail_item.get("title")
                    or detail_item.get("name")
                )
                if main_title:
                    title = html.unescape(main_title)
                    title = title.replace(" ", ".")

                    if is_valid_release(
                        title, base_category, search_string, season, episode
                    ):
                        # Skip if we've already seen this exact title
                        if title in seen_titles:
                            debug(f"Skipping duplicate main title: {title}")
                        else:
                            seen_titles.add(title)
                            published = detail_item.get(
                                "updated_at"
                            ) or detail_item.get("created_at")
                            if not published:
                                published = datetime.now().strftime(
                                    "%a, %d %b %Y %H:%M:%S +0000"
                                )
                            password = f"www.{host}"

                            link = generate_download_link(
                                shared_state,
                                title,
                                source,
                                0,
                                password,
                                item_imdb_id,
                                hostname,
                            )

                            releases.append(
                                {
                                    "details": {
                                        "title": title,
                                        "hostname": hostname,
                                        "imdb_id": item_imdb_id,
                                        "link": link,
                                        "size": 0,
                                        "date": published,
                                        "source": source,
                                    },
                                    "type": "protected",
                                }
                            )

                if "releases" in detail_item and isinstance(
                    detail_item["releases"], list
                ):
                    trace(f"Found {len(detail_item['releases'])} releases for {uid}")

                    for release in detail_item["releases"]:
                        try:
                            release_title = release.get("fulltitle")
                            if not release_title:
                                continue

                            release_title = html.unescape(release_title)
                            release_title = release_title.replace(" ", ".")

                            if not is_valid_release(
                                release_title,
                                base_category,
                                search_string,
                                season,
                                episode,
                            ):
                                continue

                            # Skip if we've already seen this exact title (deduplication)
                            if release_title in seen_titles:
                                trace(f"Skipping duplicate release: {release_title}")
                                continue

                            seen_titles.add(release_title)

                            release_uid = release.get("uid")
                            if release_uid:
                                release_source = (
                                    f"https://{host}/detail/{uid}?release={release_uid}"
                                )
                            else:
                                release_source = source

                            release_published = (
                                release.get("updated_at")
                                or release.get("created_at")
                                or detail_item.get("updated_at")
                            )
                            if not release_published:
                                release_published = datetime.now().strftime(
                                    "%a, %d %b %Y %H:%M:%S +0000"
                                )
                            release_size = release.get("size", 0)
                            password = f"www.{host}"

                            link = generate_download_link(
                                shared_state,
                                release_title,
                                release_source,
                                release_size,
                                password,
                                item_imdb_id,
                                hostname,
                            )

                            releases.append(
                                {
                                    "details": {
                                        "title": release_title,
                                        "hostname": hostname,
                                        "imdb_id": item_imdb_id,
                                        "link": link,
                                        "size": release_size,
                                        "date": release_published,
                                        "source": release_source,
                                    },
                                    "type": "protected",
                                }
                            )

                        except Exception as e:
                            debug(f"Error parsing release: {e}")
                            continue
                else:
                    debug(f"No releases array found for {uid}")

            except Exception as e:
                debug(f"Error processing item: {e}")
                debug(f"{traceback.format_exc()}")
                continue

        trace(f"Returning {len(releases)} total releases (deduplicated)")

    except Exception as e:
        error(f"Error in search: {e}")
        mark_hostname_issue(
            hostname, "search", str(e) if "e" in dir() else "Error occurred"
        )

        debug(f"{traceback.format_exc()}")
        return releases

    elapsed_time = time.time() - start_time
    debug(f"Time taken: {elapsed_time:.2f}s")

    if releases:
        clear_hostname_issue(hostname)
    return releases
