# -*- coding: utf-8 -*-
import base64
import json
import urllib.parse

from resources.lib import proxy


_BLOCKED_HEADERS = {'host', 'connection', 'content-length', 'accept-encoding'}


def _emit(log_fn, message, level=None):
    if not log_fn:
        return
    try:
        log_fn(message, level) if level is not None else log_fn(message)
    except TypeError:
        try:
            log_fn(message)
        except Exception:
            pass
    except Exception:
        pass


def _parse_kodi_url(url):
    raw = url or ''
    clean, sep, header_blob = raw.partition('|')
    headers = {}
    if sep and header_blob:
        try:
            parsed = urllib.parse.parse_qsl(header_blob, keep_blank_values=True)
        except Exception:
            parsed = []
        for key, value in parsed:
            lk = (key or '').strip().lower()
            if not lk or lk in _BLOCKED_HEADERS:
                continue
            headers[key] = value
    return clean or raw, headers


def _encode_headers(headers):
    if not headers:
        return ''
    try:
        payload = json.dumps(headers, ensure_ascii=False, separators=(',', ':')).encode('utf-8')
        return base64.urlsafe_b64encode(payload).decode('ascii').rstrip('=')
    except Exception:
        return ''


def _setting_bool(addon, setting_id, default=False):
    try:
        raw = (addon.getSetting(setting_id) or '').strip().lower()
        if raw in ('true', '1', 'yes', 'on'):
            return True
        if raw in ('false', '0', 'no', 'off'):
            return False
    except Exception:
        pass
    return bool(default)


def is_live_proxy_enabled(addon):
    # Sem chave válida, mantém URL direta. Proxy é opt-in por padrão.
    return _setting_bool(addon, 'proxy_live_enabled', default=False)


def is_vod_proxy_enabled(addon):
    """Ativação independente do VOD; proxy é opt-in por padrão."""
    return _setting_bool(addon, 'proxy_vod_enabled', default=False)


def is_any_proxy_enabled(addon):
    return bool(is_live_proxy_enabled(addon) or is_vod_proxy_enabled(addon))


def set_live_proxy_enabled(addon, enabled, log_fn=None):
    try:
        addon.setSetting('proxy_live_enabled', 'true' if enabled else 'false')
        return True
    except Exception as exc:
        _emit(log_fn, f'Falha ao salvar estado do proxy live: {exc}')
        return False


def ensure_live_proxy_started(log_fn=None):
    try:
        return bool(proxy.start_proxy())
    except Exception as exc:
        _emit(log_fn, f'Falha ao iniciar proxy live: {exc}')
        return False


def stop_live_proxy_if_running(log_fn=None):
    try:
        return bool(getattr(proxy, 'stop_proxy', lambda: True)())
    except Exception as exc:
        _emit(log_fn, f'Falha ao desligar proxy live: {exc}')
        return False


def wrap_live_url_with_proxy(url, addon, strip_headers_fn, log_fn=None):
    raw_url = url or ''
    clean_url, headers = _parse_kodi_url(raw_url)
    clean_url = clean_url or strip_headers_fn(raw_url)
    if not clean_url:
        return clean_url or raw_url
    if clean_url.startswith('http://127.0.0.1:') and (
        ('/hlsretry?' in clean_url) or ('/tsdownloader?' in clean_url)
    ):
        return clean_url
    if not is_live_proxy_enabled(addon):
        return raw_url or clean_url
    if not ensure_live_proxy_started(log_fn=log_fn):
        return raw_url or clean_url
    try:
        port = int(getattr(proxy, 'get_proxy_port', lambda: 0)() or 0)
    except Exception:
        port = 0
    if not (1024 <= port <= 65535):
        _emit(log_fn, 'Proxy local não publicou uma porta válida; mantendo URL direta.')
        return raw_url or clean_url
    encoded_headers = _encode_headers(headers)
    try:
        clean_lower = (clean_url or '').lower().split('?', 1)[0].split('#', 1)[0]
        endpoint = 'tsdownloader' if clean_lower.endswith('.ts') else 'hlsretry'
        token = proxy.register_proxy_target(
            clean_url,
            header_blob=encoded_headers,
            kind='live',
            persist=True,
        )
        media_type = 'ts' if endpoint == 'tsdownloader' else 'm3u8'
        params = {'token': token, 'type': media_type} if token else {'url': clean_url}
        if not token and encoded_headers:
            params['headers'] = encoded_headers
        return 'http://127.0.0.1:%d/%s?%s' % (port, endpoint, urllib.parse.urlencode(params))
    except Exception as exc:
        _emit(log_fn, f'Falha ao montar URL do proxy live: {exc}')
        return raw_url or clean_url


def _is_local_oneplay_proxy_url(clean_url):
    try:
        raw = str(clean_url or '').strip()
        return raw.startswith('http://127.0.0.1:') and (
            ('/hlsretry?' in raw) or
            ('/tsdownloader?' in raw) or
            (raw.startswith('http://127.0.0.1:') and '/?' in raw)
        )
    except Exception:
        return False


def wrap_vod_url_with_proxy(url, addon, strip_headers_fn, log_fn=None):
    """Aplica o proxy nativo em VOD/episódios usando o mesmo toggle do proxy.

    Conservador:
    - não altera canais/live;
    - não proxifica URL local já proxificada;
    - HLS VOD usa /hlsretry; arquivo VOD direto usa o endpoint raiz no modelo XC Pro;
    - mantém headers Kodi originais codificados para o proxy repassar à origem.
    """
    raw_url = url or ''
    clean_url, headers = _parse_kodi_url(raw_url)
    clean_url = clean_url or strip_headers_fn(raw_url)
    if not clean_url:
        return clean_url or raw_url
    if _is_local_oneplay_proxy_url(clean_url):
        return clean_url
    if not is_vod_proxy_enabled(addon):
        return raw_url or clean_url
    if not ensure_live_proxy_started(log_fn=log_fn):
        return raw_url or clean_url
    try:
        port = int(getattr(proxy, 'get_proxy_port', lambda: 0)() or 0)
    except Exception:
        port = 0
    if not (1024 <= port <= 65535):
        _emit(log_fn, 'Proxy local não publicou uma porta válida; mantendo URL direta.')
        return raw_url or clean_url
    encoded_headers = _encode_headers(headers)
    try:
        parsed = urllib.parse.urlsplit(clean_url or '')
        path_lower = (parsed.path or '').lower()
        query_lower = (parsed.query or '').lower()
        is_hls = ('.m3u8' in path_lower) or ('output=m3u8' in query_lower) or ('type=m3u8' in query_lower)
        # DASH possui subrecursos relativos e não pode ser encapsulado no endpoint
        # de arquivo sem um reescritor MPD completo. Mantém URL direta para não
        # quebrar InputStream Adaptive; HLS e arquivos VOD seguem pelo proxy.
        if path_lower.endswith('.mpd') or '.mpd' in path_lower:
            return raw_url or clean_url
        target_kind = 'vod'
        token = proxy.register_proxy_target(
            clean_url,
            header_blob=encoded_headers,
            kind=target_kind,
            persist=True,
        )
        if is_hls:
            media_type = 'm3u8'
        else:
            media_type = (path_lower.rsplit('.', 1)[-1] if '.' in path_lower else 'mp4')
            if media_type not in ('mp4', 'mkv', 'avi', 'mov', 'wmv', 'webm', 'm4v', 'mpg', 'mpeg', 'ts'):
                media_type = 'mp4'
        params = {'token': token, 'type': media_type} if token else {'url': clean_url}
        if not token and encoded_headers:
            params['headers'] = encoded_headers
        if is_hls:
            # Marca HLS de VOD para o proxy tratar cada segmento de forma atômica:
            # download íntegro + retry antes de entregar qualquer byte ao player.
            if not token:
                params['kind'] = 'vod'
            return 'http://127.0.0.1:%d/hlsretry?%s' % (port, urllib.parse.urlencode(params))
        # Arquivo VOD direto: endpoint raiz com GET/HEAD/Range compatível.
        return 'http://127.0.0.1:%d/?%s' % (port, urllib.parse.urlencode(params))
    except Exception as exc:
        _emit(log_fn, f'Falha ao montar URL do proxy VOD: {exc}')
        return raw_url or clean_url
