# -*- coding: utf-8 -*-
import socket
import re
from functools import wraps
import threading
import logging
import os
import io
import xtream
import hlsretry
import github
import base64
import json
import six
from six.moves.urllib.parse import quote_plus, unquote_plus, quote
import requests
import helper

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Dicionário para armazenar rotas e as funções associadas
routes = {}
try:
    static_folder = helper.translate(os.path.join(helper.homeDir, 'static'))
except:
    static_folder = 'static'

channels_api_gratis = 'https://gist.github.com/zoreu/71a09c340fb713ab408854adb6519a46'

def b64encode(text):
    texto_bytes = text.encode('utf-8')
    texto_base64 = base64.b64encode(texto_bytes)
    texto_base64_str = texto_base64.decode('utf-8')
    return texto_base64_str

def b64decode(text):
    texto_decodificado_bytes = base64.b64decode(text)
    texto_decodificado = texto_decodificado_bytes.decode('utf-8')
    return texto_decodificado

def route(path):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        routes[re.compile("^" + re.sub(r"<(\w+)>", r"(?P<\1>[^/]+)", path) + "$")] = wrapper
        return wrapper
    return decorator

def handle_request(request):
    try:
        headers = request.splitlines()
        if headers:
            method, path = headers[0].split()[:2]
            for pattern, func in routes.items():
                match = pattern.match(path)
                if match:
                    response_body = func(**match.groupdict())
                    return response_body
            return not_found_response()
        return bad_request_response()
    except Exception as e:
        return error_response(str(e))

def not_found_response():
    return ("HTTP/1.1 404 Not Found\r\nContent-Type: text/html\r\nAccess-Control-Allow-Origin: *\r\n\r\n<h1>404 Not Found</h1>")

def bad_request_response():
    return ("HTTP/1.1 400 Bad Request\r\nContent-Type: text/html\r\nAccess-Control-Allow-Origin: *\r\n\r\n<h1>400 Bad Request</h1>")

def error_response(error_message):
    return ("HTTP/1.1 500 Internal Server Error\r\nContent-Type: text/html\r\nAccess-Control-Allow-Origin: *\r\n\r\n<h1>500 Internal Server Error</h1><p>{}</p>".format(error_message))

def get_local_ip():
    try:
        # Cria um socket para descobrir o IP local
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(('10.255.255.255', 1))
        local_ip = s.getsockname()[0]
    except Exception as e:
        local_ip = '127.0.0.1'
    finally:
        try:
            s.close()
        except:
            pass
    return local_ip

stop_event = threading.Event()

def start_server(host='0.0.0.0', port=59100):
    """Função para iniciar o servidor socket e ouvir requisições."""
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind((host, port))
        s.listen()
        msg = 'Servidor web rodando em: http://{0}:{1}'.format(get_local_ip(), port)
        logger.info(msg)

        while not stop_event.is_set():  # Verifique o estado do evento
            try:
                conn, addr = s.accept()
                with conn:
                    request = conn.recv(64000).decode('utf-8')
                    response = handle_request(request)
                    if isinstance(response, str):
                        conn.sendall(response.encode('utf-8'))
                    else:
                        conn.sendall(response)
            except Exception as e:
                logger.error(f"Erro ao aceitar conexão: {e}")
        
        logger.info("Servidor encerrado.")
        try:
            os._exit(1)
        except:
            pass        

@route('/')
def home():
    return serve_static_file("home.html")

@route('/default.html')
def default():
    return serve_static_file("default.html")

@route('/addon-info.html')
def addon_info():
    return serve_static_file("addon-info.html", replacements={'{kodi_ver}': str(helper.kversion), '{addon_ver}': str(helper.addonVersion)})

@route('/canais.html')
def canais():
    chan = github.last_gist(channels_api_gratis)
    iptv = xtream.parselist(chan)
    loop_ = ''
    for n, (dns, username, password) in enumerate(iptv):
        server = n + 1
        dict_ = '{"dns": "%s", "username": "%s", "password": "%s"}'%(str(dns), str(username), str(password))
        hash_ = b64encode(dict_)
        hash_ = quote_plus(hash_)
        #loop_ += '<option value="{0}">Servidor {1}</option>\n'.format(hash_,str(server))
        loop_ += '<div data-value="{0}">Servidor {1}</div>'.format(hash_,str(server))
    return serve_static_file("canais.html", replacements={'{loop_}': loop_})

@route('/servidor/<codigo1>')
def servidor(codigo1):
    codigo1 = unquote_plus(codigo1)
    hash_decode = json.loads(b64decode(codigo1))
    dns, username, password = hash_decode['dns'], hash_decode['username'], hash_decode['password']
    cat = xtream.API(dns,username,password).channels_category()
    loop_ = ''
    if cat:
        for i in cat:
            name, url = i
            dict_ = '{"dns": "%s", "username": "%s", "password": "%s", "url": "%s"}'%(str(dns), str(username), str(password), str(url))
            hash_ = b64encode(dict_)
            hash_ = quote_plus(hash_)
            #loop_ += '<option value="{0}">{1}</option>\n'.format(hash_,str(name))
            loop_ += '<div data-value="{0}">{1}</div>'.format(hash_,str(name))
        return serve_static_file("canais_cat.html", replacements={'{loop_}': loop_})
    return serve_static_file("server_off.html")

@route('/tv/<codigo2>')
def servidor_tv(codigo2):
    codigo2 = unquote_plus(codigo2)
    hash_decode = json.loads(b64decode(codigo2))
    dns, username, password, url = hash_decode['dns'], hash_decode['username'], hash_decode['password'], hash_decode['url'] 
    cat = xtream.API(dns,username,password).channels_open(url)
    loop_ = ''
    for i in cat:
        name,link,thumb,desc = i
        dict_ = '{"name": "%s", "url": "%s"}'%(str(name), str(link))
        hash_ = b64encode(dict_)
        hash_ = quote_plus(hash_)
        #loop_ += '<option value="{0}">{1}</option>\n'.format(hash_,str(name))
        loop_ += '<div data-value="{0}">{1}</div>'.format(hash_,str(name))
    return serve_static_file("canais_select.html", replacements={'{loop_}': loop_})

@route('/playtv/<codigo3>')
def play_channel(codigo3):
    codigo3 = unquote_plus(codigo3)
    hash_decode = json.loads(b64decode(codigo3))
    name, url = hash_decode['name'], hash_decode['url'] 
    url = 'http://%s:%s/?url=%s'%(str(hlsretry.HOST_NAME),str(hlsretry.PORT_NUMBER),quote(url))
    return serve_static_file("player.html", replacements={'{nome_canal}': name, '{stream_url}': url})

@route('/doacao.html')
def doacao():
    return serve_static_file("doacao.html")

@route('/stop')
def stop():
    stop_event.set()
    content_type = "text/html"
    content = 'Servidor Encerrado'
    response = (
        "HTTP/1.1 200 OK\r\n"
        "Content-Type: {}\r\n"
        "Access-Control-Allow-Origin: *\r\n"
        "\r\n"
        "{}".format(content_type,content)
    )
    return response    



@route('/static/<file>')
def static(file):
    return serve_static_file(file)

def serve_static_file(filename, replacements=None):
    static_file = os.path.join(static_folder, filename)
    if os.path.exists(static_file):
        if filename.endswith(('.html', '.css', '.js')):
            with io.open(static_file, 'r', encoding='utf-8') as f:
                content = f.read()
            if replacements:
                for key, value in replacements.items():
                    content = content.replace(key, value)
            content_type = "text/html" if filename.endswith('.html') else "text/css" if filename.endswith('.css') else "application/javascript"
            response = (
                "HTTP/1.1 200 OK\r\n"
                "Content-Type: {}\r\n"
                "Access-Control-Allow-Origin: *\r\n"
                "\r\n"
                "{}".format(content_type,content)
            )
            return response

        elif filename.endswith(('.png', '.jpg', '.jpeg', '.gif')):
            with open(static_file, 'rb') as f:
                source = f.read()
            content_type = "image/png" if filename.endswith('.png') else "image/jpeg" if filename.endswith(('.jpg', '.jpeg')) else "image/gif"
            response = (
                "HTTP/1.1 200 OK\r\n"
                "Content-Type: {}\r\n"
                "Access-Control-Allow-Origin: *\r\n"
                "\r\n".format(content_type)
            ).encode('utf-8') + source
            return response

    return (
        "HTTP/1.1 404 Not Found\r\n"
        "Content-Type: text/html\r\n"
        "Access-Control-Allow-Origin: *\r\n"
        "\r\n"
        "<h1>404 Not Found</h1>"
    )

@route('/call')
def call():
    return (
        "HTTP/1.1 200 OK\r\n"
        "Content-Type: text/plain\r\n"
        "Access-Control-Allow-Origin: *\r\n"
        "\r\n"
        "OK"
    )

def monitor():
    try:
        try:
            from kodi_six import xbmc
        except:
            import xbmc
        monitor = xbmc.Monitor()
        while not monitor.waitForAbort(3):
            pass
        url = 'http://127.0.0.1:59100/stop'
        try:
            r = requests.get(url,timeout=4)
        except:
            pass
        try:
            os._exit(1)
        except:
            pass
    except:
        pass

# Iniciar o servidor em uma nova thread
if __name__ == "__main__":
    proxy = hlsretry.XtreamProxy()
    proxy.start()
    server_thread = threading.Thread(target=start_server)
    server_thread.start()
    monitor_service = threading.Thread(target=monitor)
    monitor_service.start()
    logger.info("ONEPLAY TV SMART RODANDO")
    endereco = 'http://{0}:59100'.format(hlsretry.HOST_NAME)
    helper.dialog('ABRA O NAVEGADOR DA TV E ACESSE:\n%s'%endereco)

