# -*- coding: utf-8 -*-

WEBSITE = 'ANIMESUP'

import re
import difflib
import unicodedata
from urllib.parse import quote_plus, urljoin
from bs4 import BeautifulSoup
import requests

from resources.lib.resolver import Resolver

try:
    import xbmcaddon
    addon = xbmcaddon.Addon()
    DUBBED = addon.getLocalizedString(30200)
    SUBTITLED = addon.getLocalizedString(30202)
except:
    DUBBED = 'DUBLADO'
    SUBTITLED = 'LEGENDADO'

session = requests.Session()
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36'
session.headers.update({
    'User-Agent': USER_AGENT,
    'Accept-Language': 'en-US,en;q=0.9,pt-BR;q=0.8,pt;q=0.7',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Referer': 'https://www.animesup.info/',
})


class source:

    QUOTE_MIN_CHARS = 60
    QUOTE_MIN_WORDS = 8

    @classmethod
    def _normalize(cls, text):
        if not text:
            return ''
        return unicodedata.normalize('NFKD', text).encode('ascii', 'ignore').decode('ascii')

    @classmethod
    def _normalize_movie_hyphen(cls, title):
        if not title:
            return title
        return re.sub(r'\s*[\u002D\u2010\u2011\u2012\u2013\u2014\u2015-]\s*(the movie\b)', r' the movie', title, flags=re.I)

    @classmethod
    def _adjust_base_title(cls, title):
        if not title or '"' not in title:
            return title
        words = title.split()
        if len(title) < cls.QUOTE_MIN_CHARS and len(words) < cls.QUOTE_MIN_WORDS:
            return title
        return title.split('"', 1)[0].strip()

    @classmethod
    def _clean_title(cls, title):
        if not title:
            return ''
        t = cls._normalize(title.lower())
        t = re.sub(r'\bassistir\s+online\b', '', t)
        t = re.sub(r'\bonline\b', '', t)
        t = re.sub(r'[\"\u201c\u201d\'\`]', '', t)
        t = re.sub(r'[-_:]', ' ', t)
        t = re.sub(r'[()[\]]', '', t)
        t = re.sub(r'\b(\d+)(?:st|nd|rd|th|\xaa|\xba)\b', r'\1', t)
        return re.sub(r'\s+', ' ', t).strip()

    @classmethod
    def _strip_dublado(cls, text):
        return re.sub(r'\bdublado\b', '', text).strip()

    @classmethod
    def _has_extra_words(cls, base_clean, cand_clean):
        return cls._strip_dublado(cand_clean) != base_clean

    @classmethod
    def _extract_year(cls, text):
        if not text:
            return None
        m = re.search(r'\b(19|20)\d{2}\b', text)
        return int(m.group()) if m else None

    @classmethod
    def _extract_season_number(cls, text):
        if not text:
            return None
        for pattern in [
            r'\b(\d+)[\xaa\xba]?\s*(?:temporada|season|t|temp|s)\b',
            r'\b(temporada|season|t|temp|s)\s*(\d+)\b',
            r'\b(\d+)\s*(?:\xaa|\xba|st|nd|rd|th)?\s*(?:temporada|season)\b',
            r'\b(\d+)\b',
        ]:
            m = re.search(pattern, text.lower())
            if m:
                try:
                    num = int(m.group(1))
                    if 1 <= num <= 20:
                        return num
                except:
                    pass
        return None

    @classmethod
    def _similarity_score(cls, base_titles, candidate_title, base_year=None, cand_year=None):
        cand_clean = cls._clean_title(cls._normalize_movie_hyphen(candidate_title))
        best_score = 0.0
        for base_title in base_titles:
            adj_base = cls._adjust_base_title(base_title)
            base_clean = cls._clean_title(adj_base)
            if not base_clean:
                continue
            if cls._has_extra_words(base_clean, cand_clean):
                continue
            score = difflib.SequenceMatcher(None, base_clean, cls._strip_dublado(cand_clean)).ratio()
            if 'dublado' in cand_clean:
                score += 0.25
            if base_year and cand_year:
                score += 0.5 if base_year == cand_year else -0.5
            if score > best_score:
                best_score = score
        return best_score

    @classmethod
    def _extract_episode_links_from_page(cls, page_text):
        soup = BeautifulSoup(page_text, 'html.parser')
        episodes = {}
        for item in soup.find_all('div', class_='ultimosEpisodiosHomeItem'):
            num_div = item.find('div', class_='ultimosEpisodiosHomeItemInfosNum')
            if not num_div:
                continue
            m = re.search(r'epis[o\xf3]dio\s*(\d+)', num_div.get_text(strip=True), re.I)
            if not m:
                continue
            ep_num = int(m.group(1))
            a = item.find('a', href=True)
            if a and a['href'].startswith('/episodio/'):
                episodes[ep_num] = a['href']
        return episodes

    @classmethod
    def _build_page_url(cls, series_url, page_num):
        base = series_url.rstrip('/')
        return base if page_num <= 1 else '%s/page/%d' % (base, page_num)

    @classmethod
    def _get_episode_page_url(cls, series_url, episode_num):
        page_num = 1
        while True:
            url = cls._build_page_url(series_url, page_num)
            r = session.get(url)
            if not r.ok:
                break
            episodes = cls._extract_episode_links_from_page(r.text)
            if not episodes:
                break
            if episode_num in episodes:
                return urljoin('https://www.animesup.info/', episodes[episode_num])
            page_num += 1
        r = session.get(series_url)
        if r.ok:
            episodes = cls._extract_episode_links_from_page(r.text)
            if episodes:
                return urljoin('https://www.animesup.info/', episodes[min(episodes.keys())])
        return None

    @classmethod
    def _get_movie_episode_url(cls, page_text):
        soup = BeautifulSoup(page_text, 'html.parser')
        for item in soup.find_all('div', class_='ultimosEpisodiosHomeItem'):
            a = item.find('a', href=True)
            if a and a['href'].startswith('/episodio/'):
                return urljoin('https://www.animesup.info/', a['href'])
        return None

    @classmethod
    def _get_available_qualities(cls, episode_page_text):
        soup = BeautifulSoup(episode_page_text, 'html.parser')
        abas_box = soup.find('div', class_=re.compile(r'AbasBox', re.I))
        if not abas_box:
            return ['SD']
        available = []
        for aba in abas_box.find_all('div', class_=re.compile(r'Aba', re.I)):
            text = aba.get_text(strip=True).upper()
            if text in ('SD', 'HD'):
                available.append(text)
            elif text in ('FULLHD', 'FULL HD', 'FHD'):
                available.append('FULLHD')
        return available if available else ['SD']

    @classmethod
    def _extract_video_urls(cls, episode_page_text):
        videos = {}
        containers = re.split(r'<div class="playerContainer"', episode_page_text)[1:]
        for i, container in enumerate(containers[:3]):
            m = re.search(r"var\s+vid\s*=\s*'([^']+\.mp4)';", container)
            if not m:
                continue
            url = m.group(1).strip()
            if 'r2.cloudflarestorage.com' not in url:
                continue
            videos[('SD', 'HD', 'FULLHD')[i]] = url
        return videos

    @classmethod
    def _get_highest_quality_link(cls, episode_page_text, available):
        videos = cls._extract_video_urls(episode_page_text)
        for q in ('FULLHD', 'HD', 'SD'):
            if q in available and q in videos:
                return 'ANIMESUP -', videos[q]
        return 'ANIMESUP -', None

    @classmethod
    def search_animes(cls, mal_id, episode, anime_name, original_name, year=None):
        is_movie = episode is None
        if not is_movie:
            try:
                episode = int(episode)
            except:
                return []

        base_titles = [t for t in [anime_name, original_name] if t]
        if not base_titles:
            return []

        base_year = year
        anchors = []
        for search_title in base_titles:
            r = session.get('https://www.animesup.info/busca?busca=' + quote_plus(search_title))
            if not r.ok:
                continue
            soup = BeautifulSoup(r.text, 'html.parser')
            anchors = soup.find_all('a', href=re.compile(r'/(animes|anime-dublado)/[^/]+$'))
            if anchors:
                break

        if not anchors:
            return []

        candidates = []
        for a in anchors:
            raw_title = a.get_text(strip=True)
            page_url = urljoin('https://www.animesup.info/', a['href'])
            cand_year = cls._extract_year(raw_title)
            score = cls._similarity_score(base_titles, raw_title, base_year, cand_year)
            candidates.append({
                'title': raw_title,
                'url': page_url,
                'score': score,
                'year': cand_year,
                'season': cls._extract_season_number(raw_title),
                'clean_title': cls._clean_title(raw_title),
            })

        candidates.sort(key=lambda x: x['score'], reverse=True)

        expected_season = None
        if not is_movie:
            for t in base_titles:
                m = re.search(r'(?:season|part|temporada|s)\s*(\d+)', t.lower())
                if m:
                    expected_season = int(m.group(1))
                    break

        base_keywords = set()
        for t in base_titles:
            words = cls._clean_title(t).split()
            if len(words) > 1:
                base_keywords.update(words[:3])

        results = []
        seen = set()

        for c in candidates:
            accept = False
            if base_year and c['year'] and base_year == c['year']:
                accept = True
            elif not is_movie and expected_season and c['season'] == expected_season:
                accept = True
            elif not is_movie and expected_season and c['season'] == expected_season:
                if any(kw in c['clean_title'] for kw in base_keywords) and str(expected_season) in c['clean_title']:
                    accept = True
            if not accept:
                min_score = 0.75 if 'dublado' in c['title'].lower() else 0.55
                if c['score'] >= min_score:
                    accept = True

            if not accept or c['url'] in seen:
                continue
            seen.add(c['url'])

            r_page = session.get(c['url'])
            if not r_page.ok:
                continue

            ep_url = cls._get_movie_episode_url(r_page.text) if is_movie else cls._get_episode_page_url(c['url'], episode)
            if not ep_url:
                continue

            r_ep = session.get(ep_url)
            if not r_ep.ok:
                continue

            available = cls._get_available_qualities(r_ep.text)
            label, url = cls._get_highest_quality_link(r_ep.text, available)
            if not url:
                continue

            prefix = DUBBED if 'dublado' in c['title'].lower() else SUBTITLED
            results.append(('%s %s' % (label, prefix), url))

        return results

    @classmethod
    def resolve_animes(cls, url):
        resolved, sub = Resolver().resolverurls(url)
        return [(resolved or url, sub or '', USER_AGENT)]

    resolve_animes_movies = resolve_animes
    __site_url__ = ['https://www.animesup.info/']
