# -*- coding: utf-8 -*-
"""
Diamond RD Player - Search Index Builder (Compressed)

- Loads multiple master JSON lists
- Deduplicates by info_hash / magnet
- Builds compressed search index for Smart Search
- Automatically rebuilds when ANY source list changes
"""

import json
import hashlib
import re
import gzip
import os

import xbmc
import xbmcaddon
import xbmcvfs
import requests

ADDON = xbmcaddon.Addon()
ADDON_ID = ADDON.getAddonInfo("id")

# -----------------------------------------------------
# MASTER LIST SOURCES
# -----------------------------------------------------
MASTER_URLS = [
    "https://uck.st/splite_movies/master_list_1.json",
    "https://uck.st/top_movies/top_movies.json",
]

DATA_DIR = xbmcvfs.translatePath(
    "special://profile/addon_data/{0}/".format(ADDON_ID)
)

INDEX_PATH = os.path.join(DATA_DIR, "search_index.json.gz")
LEGACY_INDEX_PATH = os.path.join(DATA_DIR, "search_index.json")
FINGERPRINT_PATH = os.path.join(DATA_DIR, "index_fingerprint.json")


# -----------------------------------------------------
# Helper: tokenizer
# -----------------------------------------------------
def _tokenize(text):
    return [t for t in re.split(r"[^a-z0-9]+", text.lower()) if t]


# -----------------------------------------------------
# Helper: hash whole dataset (unchanged)
# -----------------------------------------------------
def _hash(data):
    try:
        return hashlib.md5(
            json.dumps(data, sort_keys=True).encode("utf-8")
        ).hexdigest()
    except Exception:
        return None


# -----------------------------------------------------
# Helper: derive unique key per movie (UNCHANGED)
# -----------------------------------------------------
def _movie_key(mv):
    if mv.get("info_hash"):
        return mv["info_hash"].lower()

    magnet = mv.get("magnet") or ""
    if magnet:
        m = re.search(r"btih:([a-fA-F0-9]+)", magnet)
        if m:
            return m.group(1).lower()

    title = (mv.get("title") or "").lower()
    year = str(mv.get("year") or "")
    return "fallback::{0}::{1}".format(title, year)


# -----------------------------------------------------
# Fingerprint helpers (NEW — ONLY ADDITION)
# -----------------------------------------------------
def _fetch_fingerprint():
    fp = {}
    for url in MASTER_URLS:
        try:
            r = requests.get(url, timeout=15)
            if not r.ok:
                fp[url] = None
                continue
            fp[url] = hashlib.md5(r.content).hexdigest()
        except Exception:
            fp[url] = None
    return fp


def _load_fingerprint():
    if not xbmcvfs.exists(FINGERPRINT_PATH):
        return None
    try:
        with open(FINGERPRINT_PATH, "r", encoding="utf-8") as f:
            return json.load(f)
    except Exception:
        return None


def _save_fingerprint(fp):
    try:
        if not xbmcvfs.exists(DATA_DIR):
            xbmcvfs.mkdirs(DATA_DIR)
        with open(FINGERPRINT_PATH, "w", encoding="utf-8") as f:
            json.dump(fp, f, indent=2)
    except Exception:
        pass


# -----------------------------------------------------
# Load + merge all master lists with dedupe (UNCHANGED)
# -----------------------------------------------------
def _load_all_masters():
    xbmc.log("[RDIndex] Loading master lists...", xbmc.LOGINFO)

    merged = []
    seen = set()

    for url in MASTER_URLS:
        try:
            xbmc.log("[RDIndex] Fetching {0}".format(url), xbmc.LOGINFO)
            r = requests.get(url, timeout=15)
            if not r.ok:
                xbmc.log("[RDIndex] HTTP {0} for {1}".format(r.status_code, url), xbmc.LOGWARNING)
                continue

            data = r.json()
            if not isinstance(data, list):
                xbmc.log("[RDIndex] Invalid JSON (not list): {0}".format(url), xbmc.LOGWARNING)
                continue

            for mv in data:
                key = _movie_key(mv)
                if key in seen:
                    continue
                seen.add(key)
                merged.append(mv)

        except Exception as e:
            xbmc.log("[RDIndex] Error loading {0}: {1}".format(url, e), xbmc.LOGWARNING)

    xbmc.log("[RDIndex] Merged unique movies: {0}".format(len(merged)), xbmc.LOGINFO)
    return merged


# -----------------------------------------------------
# Save compressed index (UNCHANGED)
# -----------------------------------------------------
def _save_index(payload):
    try:
        if not xbmcvfs.exists(DATA_DIR):
            xbmcvfs.mkdirs(DATA_DIR)

        raw = json.dumps(payload, separators=(",", ":")).encode("utf-8")

        with gzip.open(INDEX_PATH, "wb") as f:
            f.write(raw)

        xbmc.log("[RDIndex] Index saved: {0}".format(INDEX_PATH), xbmc.LOGINFO)
        return True
    except Exception as e:
        xbmc.log("[RDIndex] Failed saving index: {0}".format(e), xbmc.LOGERROR)
        return False


# -----------------------------------------------------
# MAIN: build_index (REBUILT, NOT REWRITTEN)
# -----------------------------------------------------
def build_index(progress_callback=None, force=False):

    # Detect source list changes (NEW)
    old_fp = _load_fingerprint()
    new_fp = _fetch_fingerprint()

    if old_fp != new_fp:
        xbmc.log("[RDIndex] Source lists changed → forcing rebuild", xbmc.LOGINFO)
        force = True

    # Cleanup legacy index (UNCHANGED)
    try:
        if xbmcvfs.exists(LEGACY_INDEX_PATH):
            xbmcvfs.delete(LEGACY_INDEX_PATH)
            xbmc.log("[RDIndex] Deleted legacy index", xbmc.LOGINFO)
    except Exception:
        pass

    if not force and xbmcvfs.exists(INDEX_PATH):
        xbmc.log("[RDIndex] Index already exists, skipping rebuild.", xbmc.LOGINFO)
        return True

    movies = _load_all_masters()
    if not movies:
        xbmc.log("[RDIndex] No movies loaded.", xbmc.LOGERROR)
        return False

    token_map = {}
    total = len(movies)

    for i, mv in enumerate(movies):
        title = (mv.get("title") or "").lower()
        year = str(mv.get("year") or "").strip()

        quality_bits = []
        for q in ("2160p", "1080p", "720p", "4k", "hdr", "dv", "dolby", "uhd", "remux"):
            if q in title:
                quality_bits.append(q)

        combined = title
        if year:
            combined += " " + year
        if quality_bits:
            combined += " " + " ".join(quality_bits)

        tokens = set(_tokenize(combined))
        for tok in tokens:
            token_map.setdefault(tok, []).append(i)

        if progress_callback and total > 0 and i % 300 == 0:
            progress_callback(int((float(i) / total) * 100))

    payload = {
        "_hash": _hash(movies),
        "movies": movies,
        "token_map": token_map,
    }

    if progress_callback:
        progress_callback(98)

    ok = _save_index(payload)

    if ok:
        _save_fingerprint(new_fp)

    if progress_callback:
        progress_callback(100)

    return ok
