# -*- coding: utf-8 -*-
# Author: Parrot Developers
# License: MPL 2.0 https://www.mozilla.org/en-US/MPL/2.0/

import os
import sys
import shutil
import xbmc
import xbmcgui
import xbmcplugin
import xbmcaddon
import random
import json
import requests
import time
import datetime
import threading
import xbmcvfs
import xml.etree.ElementTree as ET
from kodiez import KodiEZ
from routing import Plugin
from imgs import getIMG
from resources.utils.channels import genList
from resources.utils.common import getEnabled, parsePlaylist
from resources.utils.epg import update_epg
from urllib.parse import urlencode, urlparse
from scraper import resolve, checkForGrabber
from scraper.utils.browser import Firefox

plugin = Plugin()
_ADDON = xbmcaddon.Addon()
_ADDON_NAME = _ADDON.getAddonInfo('name')
_ADDON_ID = _ADDON.getAddonInfo('id')
_URL = "plugin://{}".format(_ADDON.getAddonInfo('id'))
_KODIEZ = KodiEZ(_ADDON, plugin.handle)
_ADDON_FOLDER = xbmcvfs.translatePath('special://home/addons/'+_ADDON_ID)
_USERDATA_FOLDER = xbmcvfs.translatePath('special://home/userdata/addon_data/'+_ADDON_ID)
_PLAYLIST_FILE = os.path.join(_USERDATA_FOLDER, "playlist.m3u")
_HISTORY_FILE = os.path.join(_USERDATA_FOLDER, "history.json")
_CHANNELS_FILE = os.path.join(_USERDATA_FOLDER, "channels.json")

# Create userdata folder
os.makedirs(_USERDATA_FOLDER, exist_ok=True)

colors = ["white", "black", "gradient"]
color = colors[int(_ADDON.getSetting("selectColor"))]

# Basic auth
if _ADDON.getAddonInfo('author') != "[COLOR cyan]Parrot[/COLOR] [COLOR yellow]Developers[/COLOR]": exit()
if _ADDON.getAddonInfo('id') != "plugin.video.parrottv": exit()



def addDir(name, icon, url, genre=''):
    list_item = xbmcgui.ListItem(label=name)
    list_item.setInfo('video', {'title': name, 'genre': genre, 'plot': name, 'mediatype': 'video'})
    list_item.setArt({'thumb': icon, 'icon': icon, 'fanart': 'https://cdn.wallpapersafari.com/14/97/Bir3IC.jpg'})
    xbmcplugin.addDirectoryItem(plugin.handle, url, list_item, True)


def addChannel(name, icon, url):
    headers = Firefox().headers
    icon += '|' + urlencode(headers)

    list_item = xbmcgui.ListItem(label=name)
    list_item.setInfo('video', {'title': name, 'genre': '', 'plot': name, 'mediatype': 'video'})
    list_item.setArt({'thumb': icon, 'icon': icon, 'fanart': 'https://cdn.wallpapersafari.com/14/97/Bir3IC.jpg'})
    
    if "/play/" in url:
        list_item.setProperty('IsPlayable', 'true')
    
    xbmcplugin.addDirectoryItem(plugin.handle, url, list_item, False)


def genPlaylist():
    allowed = getEnabled()
    headers = Firefox().headers
    fullList = genList(_ADDON_FOLDER)


    allowed_ = allowed.copy()
    if "CS" in allowed_:
        allowed_.remove("CS")

    m3u = [
        '#EXTM3U',
        f'#X-Falcon-Version: {_ADDON.getAddonInfo("version")}',
        f'#X-Falcon-ID: {_ADDON.getAddonInfo("id")}',
        f'#X-Falcon-Generated-Countries: {", ".join(allowed_)}',
        f'#X-Falcon-Generated-On: {str(int(time.time()))}',
    ]

    for ID, item in fullList.items():
        try:
            name = item["name"]
        except:
            xbmcgui.Dialog().ok(_ADDON_NAME, f"Error occurred when parsing channel: {ID}")
            exit()

        logo = item.get("logo", "https://cdn1.iconfinder.com/data/icons/special-characters/100/09-1024.png") 
        if logo: logo = logo + '|' + urlencode(headers)
        country = item["country"]
        category = item["category"]
        tvgid = item.get("epg", "0")

        # Check if user has allowed this country
        if country not in allowed: continue

        # Check if channel is disabled
        if item.get("disabled", False) == True:
            continue

        if 'sources' not in item: continue
        if len(item['sources']) == 0: continue

        # Check if there are live sources
        sources_count = sum((not source["disabled"] and checkForGrabber(source['module'])) for source in item['sources'])
        if sources_count == 0: continue

        m3u.append(f'#EXTINF:-1 tvg-logo="{logo}" group-title="{category}" tvg-id="{tvgid}" tvg-name="{name}", {name}')
        m3u.append(f"{_URL}/play/{ID}")

    open(_CHANNELS_FILE, 'w', encoding="utf-8").write(json.dumps(fullList))
    open(_PLAYLIST_FILE, 'w', encoding='utf-8').write("\n".join(m3u))
    


def _parse_xmltv_time(ts):
    if not ts:
        return None
    try:
        s = ts.strip()
        y = int(s[0:4])
        mth = int(s[4:6])
        d = int(s[6:8])
        h = int(s[8:10])
        mi = int(s[10:12])
        sec = int(s[12:14])
        dt = datetime.datetime(y, mth, d, h, mi, sec)
        rest = s[14:].strip()
        if not rest:
            return dt
        if rest.upper().endswith('Z'):
            rest = rest[:-1].strip()
        if rest.startswith('+') or rest.startswith('-'):
            tz_h = int(rest[:3])
            if ':' in rest:
                rest = rest.replace(':', '')
            tz_m = int(rest[3:5]) if len(rest) >= 5 else 0
            return dt - datetime.timedelta(hours=tz_h, minutes=tz_m)
        return dt
    except:
        try:
            xbmc.log("parrotTV EPG time parse failed: %s" % repr(ts), xbmc.LOGDEBUG)
        except:
            pass
        return None


def _load_epg_data():
    path = os.path.join(_USERDATA_FOLDER, "epg.xml")
    if not os.path.isfile(path):
        return None, None
    try:
        tree = ET.parse(path)
    except:
        return None, None
    root = tree.getroot()
    channels_epg = {}
    for ch in root.findall('channel'):
        cid = ch.get('id', '')
        name = ch.findtext('display-name', cid)
        channels_epg[cid] = name
    programmes = []
    for p in root.findall('programme'):
        start_s = p.get('start', '')
        stop_s = p.get('stop', '')
        programmes.append({
            'channel': p.get('channel', ''),
            'start': start_s,
            'stop': stop_s,
            'start_dt': _parse_xmltv_time(start_s),
            'stop_dt': _parse_xmltv_time(stop_s),
            'title': p.findtext('title', ''),
            'desc': p.findtext('desc', ''),
            'category': p.findtext('category', ''),
        })
    return channels_epg, programmes

def _get_channels_map(channels_data):
    return {ch_id: ch_data.get("epg", "") for ch_id, ch_data in channels_data.items()}

def _find_current(programmes):
    now = datetime.datetime.utcnow()
    return [p for p in programmes if p['start_dt'] and p['stop_dt'] and p['start_dt'] <= now < p['stop_dt']]


def _find_upcoming(programmes, limit=15):
    now = datetime.datetime.utcnow()
    future = [p for p in programmes if p['start_dt'] and p['start_dt'] > now]
    future.sort(key=lambda p: p['start_dt'])
    return future[:limit]


@plugin.route('/')
def root():
    xbmcplugin.setContent(plugin.handle, 'Home')
    xbmcplugin.setPluginCategory(plugin.handle, "Home")
    genPlaylist()

    addDir('[COLOR gold]Search[/COLOR]', getIMG('search', color), "{}/search".format(_URL))
    addDir('[COLOR gold]TV Channels[/COLOR]', getIMG('list', color), "{}/channels".format(_URL))
    addDir('[COLOR gold]TV Categories[/COLOR]', getIMG('grid', color), "{}/categories".format(_URL))
    addDir('[COLOR gold]EPG Guide[/COLOR]', getIMG('grid', color), "{}/epg".format(_URL))
    addDir('[COLOR gold]History[/COLOR]', getIMG('history', color), "{}/history".format(_URL))
    xbmcplugin.endOfDirectory(plugin.handle)


def _get_epg_source():
    val = _ADDON.getSetting("epgSource") or "0"
    idx = int(val) if val.isdigit() else 0
    if idx == 0:
        return "default", ""
    elif idx == 1:
        return "openepg", ""
    elif idx == 2:
        return "custom", _ADDON.getSetting("epgUrl") or ""
    return "default", ""

def _get_epg_source_tag():
    source, source_url = _get_epg_source()
    return "%s|%s" % (source, source_url)

def _ensure_epg():
    path = os.path.join(_USERDATA_FOLDER, "epg.xml")
    tag_path = os.path.join(_USERDATA_FOLDER, ".epg_source")
    source_tag = _get_epg_source_tag()
    if os.path.isfile(path):
        try:
            old_tag = open(tag_path, 'r', encoding='utf-8').read()
            if old_tag == source_tag:
                return True
            xbmc.log("parrotTV EPG source changed, regenerating", xbmc.LOGDEBUG)
        except:
            pass
    raw_path = os.path.join(_USERDATA_FOLDER, "epg_raw.xml")
    if os.path.isfile(raw_path):
        os.remove(raw_path)
    try:
        update_epg(_USERDATA_FOLDER, genList(_ADDON_FOLDER), source=source_tag.split("|")[0], source_url=source_tag.split("|")[1])
        open(tag_path, 'w', encoding='utf-8').write(source_tag)
        xbmcgui.Dialog().notification(_ADDON_NAME, "EPG generated", xbmcgui.NOTIFICATION_INFO, 3000)
        return os.path.isfile(path)
    except Exception as e:
        xbmcgui.Dialog().ok(_ADDON_NAME, "EPG generation failed:\n" + str(e))
        return False


@plugin.route('/epg')
def epg_menu():
    xbmcplugin.setContent(plugin.handle, 'EPG')
    xbmcplugin.setPluginCategory(plugin.handle, "EPG Guide")
    addDir('[COLOR gold]Currently Playing[/COLOR]', getIMG('list', color), "{}/epg/now".format(_URL))
    addDir('[COLOR gold]Browse by Channel[/COLOR]', getIMG('grid', color), "{}/epg/browse".format(_URL))
    addDir('[COLOR gold][DEBUG] EPG Status[/COLOR]', getIMG('grid', color), "{}/epg/debug".format(_URL))
    addDir('[COLOR gold]Force EPG Update[/COLOR]', getIMG('list', color), "{}/epg/force".format(_URL))
    xbmcplugin.endOfDirectory(plugin.handle)


@plugin.route('/epg/debug')
def epg_debug():
    path = os.path.join(_USERDATA_FOLDER, "epg.xml")
    lines = []
    lines.append("EPG file: " + path)
    lines.append("Exists: " + str(os.path.isfile(path)))
    if os.path.isfile(path):
        lines.append("Size: " + str(os.path.getsize(path)) + " bytes")
    channels_epg, progs = _load_epg_data()
    lines.append("Channels: " + str(len(channels_epg) if channels_epg else 0))
    lines.append("Programmes: " + str(len(progs) if progs else 0))

    cur = _find_current(progs) if progs else []
    lines.append("Current: " + str(len(cur)))

    try:
        chans = json.loads(open(_CHANNELS_FILE, 'r', encoding='utf-8').read())
        epg_to_ch = {v.get("epg", ""): k for k, v in chans.items() if v.get("epg")}
        matched = sum(1 for p in cur if p['channel'] in epg_to_ch)
        lines.append("Current matched (channels.json): " + str(matched))
        upc = _find_upcoming(progs, 60) if progs else []
        matched_up = sum(1 for p in upc if p['channel'] in epg_to_ch)
        lines.append("Upcoming 60 matched: " + str(matched_up))
        lines.append("epg_to_ch count: " + str(len(epg_to_ch)))
    except Exception as e:
        lines.append("Channels JSON error: " + str(e))
    lines.append("NOW UTC: " + str(datetime.datetime.utcnow()))
    lines.append("EPG file mtime: " + str(datetime.datetime.fromtimestamp(os.path.getmtime(path))))
    if progs:
        start_dt0 = progs[0]['start_dt']
        start_dt_last = progs[-1]['start_dt']
        lines.append("Prog[0].start_dt: " + str(start_dt0))
        lines.append("Prog[-1].start_dt: " + str(start_dt_last))
        nones = sum(1 for p in progs if p['start_dt'] is None)
        lines.append("start_dt is None: " + str(nones))
        valid_up = sum(1 for p in progs if p['start_dt'] and p['start_dt'] > datetime.datetime.utcnow())
        lines.append("Total upcoming (valid): " + str(valid_up))
        lines.append("Prog[0].raw_start: " + repr(progs[0]['start']))
        lines.append("Prog[1].raw_start: " + repr(progs[1]['start']))
        lines.append("Prog[10].raw_start: " + repr(progs[10]['start']))
        lines.append("Prog[-1].raw_start: " + repr(progs[-1]['start']))
        lines.append("EPG file size: " + str(os.path.getsize(path)) + " bytes")
        lines.append("EPG file mtime: " + str(datetime.datetime.fromtimestamp(os.path.getmtime(path))))
        raw_first = open(path, 'r', encoding='utf-8').read(200)
        lines.append("Raw first 200 chars: " + repr(raw_first))
    debug_path = os.path.join(_USERDATA_FOLDER, "epg_debug.txt")
    open(debug_path, 'w', encoding='utf-8').write("\n".join(lines))
    xbmcgui.Dialog().ok(_ADDON_NAME, "Debug info saved to:\n" + debug_path)
    exit()


@plugin.route('/epg/force')
def epg_force():
    path = os.path.join(_USERDATA_FOLDER, "epg.xml")
    raw_path = os.path.join(_USERDATA_FOLDER, "epg_raw.xml")
    tag_path = os.path.join(_USERDATA_FOLDER, ".epg_source")
    if os.path.isfile(path):
        os.remove(path)
    if os.path.isfile(raw_path):
        os.remove(raw_path)
    if os.path.isfile(tag_path):
        os.remove(tag_path)
    if _ensure_epg():
        xbmcgui.Dialog().notification(_ADDON_NAME, "EPG force updated", xbmcgui.NOTIFICATION_INFO, 3000)
    else:
        xbmcgui.Dialog().ok(_ADDON_NAME, "EPG force update failed")
    xbmc.executebuiltin('Container.Refresh')
    exit()


@plugin.route('/epg/now')
def epg_now():
    xbmcplugin.setContent(plugin.handle, 'EPG')
    xbmcplugin.setPluginCategory(plugin.handle, "Currently Playing")
    if not _ensure_epg():
        return
    channels_epg, programmes = _load_epg_data()
    if not programmes:
        xbmcgui.Dialog().ok(_ADDON_NAME, "No EPG data available.")
        exit()
    channels = {}
    try:
        channels = json.loads(open(_CHANNELS_FILE, 'r', encoding='utf-8').read())
    except:
        pass
    epg_to_ch = {v.get("epg", ""): k for k, v in channels.items() if v.get("epg")}

    now = datetime.datetime.utcnow()

    current = _find_current(programmes)
    items = current if current else _find_upcoming(programmes, 60)

    count = 0
    for prog in items:
        ch_id = epg_to_ch.get(prog['channel'])
        if not ch_id:
            continue
        ch_data = channels.get(ch_id, {})
        time_str = " [{}]".format(prog['start_dt'].strftime("%H:%M")) if prog['start_dt'] else ""
        is_current = prog['start_dt'] <= now < prog['stop_dt'] if prog['start_dt'] and prog['stop_dt'] else False
        prefix = "[COLOR yellow]>> [/COLOR]" if is_current else "[UP] "
        label = "{}{}{} - {}".format(prefix, ch_data.get("name", prog['channel']), time_str, prog['title'])
        li = xbmcgui.ListItem(label=label)
        li.setInfo('video', {'title': prog['title'], 'plot': prog['desc'], 'genre': prog['category']})
        li.setArt({'thumb': ch_data.get("logo", "")})
        li.setProperty('IsPlayable', 'true')
        play_url = "{}/play/{}".format(_URL, ch_id)
        xbmcplugin.addDirectoryItem(plugin.handle, play_url, li, False)
        count += 1

    if count == 0 and channels_epg and len(items) > 0:
        for prog in items[:10]:
            ch_name = channels_epg.get(prog['channel'], prog['channel'])
            time_str = " [{}]".format(prog['start_dt'].strftime("%H:%M")) if prog['start_dt'] else ""
            label = "[COLOR red]?[/COLOR] {} {} - {}".format(ch_name, time_str, prog['title'])
            li = xbmcgui.ListItem(label=label)
            li.setInfo('video', {'title': prog['title'], 'plot': prog['desc'], 'genre': prog['category']})
            li.setProperty('IsPlayable', 'true')
            xbmcplugin.addDirectoryItem(plugin.handle, "", li, False)
            count += 1

    xbmcplugin.endOfDirectory(plugin.handle)
    if count == 0:
        xbmcgui.Dialog().ok(_ADDON_NAME, "No upcoming programmes found.")


@plugin.route('/epg/browse')
def epg_browse():
    xbmcplugin.setContent(plugin.handle, 'EPG')
    xbmcplugin.setPluginCategory(plugin.handle, "EPG by Channel")
    if not _ensure_epg():
        return
    channels = {}
    try:
        channels = json.loads(open(_CHANNELS_FILE, 'r', encoding='utf-8').read())
    except:
        pass
    channels_epg, _ = _load_epg_data()
    for ch_id, ch_data in channels.items():
        epg_id = ch_data.get("epg", "")
        if not epg_id:
            continue
        if channels_epg and epg_id not in channels_epg:
            continue
        if ch_data.get("disabled", False):
            continue
        addDir("[COLOR gold]{}[/COLOR]".format(ch_data['name']), ch_data.get("logo", ""), "{}/epg/channel/{}".format(_URL, ch_id))
    xbmcplugin.endOfDirectory(plugin.handle)


@plugin.route('/epg/channel/<ch_id>')
def epg_channel(ch_id):
    xbmcplugin.setContent(plugin.handle, 'EPG')
    if not _ensure_epg():
        return
    channels = {}
    try:
        channels = json.loads(open(_CHANNELS_FILE, 'r', encoding='utf-8').read())
    except:
        pass
    ch_data = channels.get(ch_id, {})
    epg_id = ch_data.get("epg", "")
    if not epg_id:
        xbmcgui.Dialog().ok(_ADDON_NAME, "No EPG ID for this channel.")
        exit()
    xbmcplugin.setPluginCategory(plugin.handle, "EPG - {}".format(ch_data.get("name", ch_id)))

    _, programmes = _load_epg_data()
    if not programmes:
        xbmcgui.Dialog().ok(_ADDON_NAME, "No EPG data available.")
        exit()

    ch_progs = [p for p in programmes if p['channel'] == epg_id]
    ch_progs.sort(key=lambda p: p['start_dt'] or datetime.datetime.min)
    now = datetime.datetime.utcnow()

    for prog in ch_progs:
        start_dt = prog['start_dt']
        stop_dt = prog['stop_dt']
        if not start_dt:
            continue
        time_str = start_dt.strftime("%H:%M")
        if stop_dt:
            time_str += " - " + stop_dt.strftime("%H:%M")
        is_now = start_dt <= now < stop_dt if stop_dt else False
        prefix = "[COLOR yellow]>> [/COLOR]" if is_now else ""
        label = "{}{}  {}".format(prefix, time_str, prog['title'])
        li = xbmcgui.ListItem(label=label)
        plot = prog['desc'] if prog['desc'] else prog['title']
        li.setInfo('video', {'title': prog['title'], 'plot': plot, 'genre': prog['category']})
        li.setArt({'thumb': ch_data.get("logo", "")})
        li.setProperty('IsPlayable', 'true')
        play_url = "{}/play/{}".format(_URL, ch_id)
        xbmcplugin.addDirectoryItem(plugin.handle, play_url, li, False)
    xbmcplugin.endOfDirectory(plugin.handle)



@plugin.route('/search')
def search():
    xbmcplugin.setContent(plugin.handle, 'Search')
    xbmcplugin.setPluginCategory(plugin.handle, "Search")
    query = _KODIEZ.inpt("Enter search query:", False)
    if query:
        for channel in parsePlaylist(_PLAYLIST_FILE):
            if query.lower() not in channel['name'].lower():
                continue

            addChannel(f"[COLOR gold][B]{channel['name']}[/B][/COLOR]", channel['logo'], channel['url'])

        xbmcplugin.endOfDirectory(plugin.handle)
    else:
        xbmcgui.Dialog().ok(_ADDON_NAME, 'No search query entered.')
        exit()


@plugin.route('/channels')
def channels():
    xbmcplugin.setContent(plugin.handle, 'Channels')
    xbmcplugin.setPluginCategory(plugin.handle, "Channels")

    _ensure_epg()
    _, programmes = _load_epg_data()
    channels_data = {}
    try:
        channels_data = json.loads(open(_CHANNELS_FILE, 'r', encoding='utf-8').read())
    except:
        pass
    epg_to_channel = {v.get("epg", ""): k for k, v in channels_data.items() if v.get("epg")}
    current = {}
    if programmes:
        for p in _find_current(programmes):
            ch_id = epg_to_channel.get(p['channel'])
            if ch_id:
                current[ch_id] = p

    name_to_id = {cdata.get("name", "").strip(): cid for cid, cdata in channels_data.items()}

    for channel in parsePlaylist(_PLAYLIST_FILE):
        ch_id = name_to_id.get(channel['name'].strip())
        prog = current.get(ch_id)
        if prog:
            time_str = ""
            if prog['start_dt'] and prog['stop_dt']:
                time_str = "{} - {} ".format(prog['start_dt'].strftime("%H:%M"), prog['stop_dt'].strftime("%H:%M"))
            label = "[COLOR gold][B]{}[/B][/COLOR]\n       [COLOR silver]{}{}[/COLOR]".format(channel['name'], time_str, prog['title'])
        else:
            label = "[COLOR gold][B]{}[/B][/COLOR]\n       ".format(channel['name'])

        headers = Firefox().headers
        icon = channel['logo'] + '|' + urlencode(headers)
        list_item = xbmcgui.ListItem(label=label)
        if prog:
            info_title = "{} - {}".format(channel['name'], prog['title'])
            info_plot = "[B]{}[/B]\n{}".format(prog['title'], prog['desc']) if prog['desc'] else "[B]{}[/B]".format(prog['title'])
            info_genre = prog['category'] or ""
        else:
            info_title = channel['name']
            info_plot = channel['name']
            info_genre = ""
        list_item.setInfo('video', {'title': info_title, 'genre': info_genre, 'plot': info_plot, 'mediatype': 'video'})
        list_item.setArt({'thumb': icon, 'icon': icon, 'fanart': 'https://cdn.wallpapersafari.com/14/97/Bir3IC.jpg'})
        if "/play/" in channel['url']:
            list_item.setProperty('IsPlayable', 'true')
        xbmcplugin.addDirectoryItem(plugin.handle, channel['url'], list_item, False)

    xbmcplugin.endOfDirectory(plugin.handle)


@plugin.route('/history')
def history():
    xbmcplugin.setContent(plugin.handle, 'History')
    xbmcplugin.setPluginCategory(plugin.handle, "History")
    
    channels = json.loads(open(_CHANNELS_FILE, 'r', encoding='utf-8').read())
    
    if not os.path.exists(_HISTORY_FILE):
        open(_HISTORY_FILE, 'w', encoding='utf-8').write('[]')
    
    try:
        historyList = json.loads(open(_HISTORY_FILE, 'r', encoding='utf-8').read())
    except:
        historyList = []
        open(_HISTORY_FILE, 'w', encoding='utf-8').write('[]')
    
    if historyList == []:
        xbmcgui.Dialog().ok(_ADDON_NAME, "History is empty")
        exit()

    for historyItem in historyList:
        channel = channels.get(historyItem, {
            "name": f"Removed channel: {historyItem}",
        })
        addChannel(f'[COLOR gold][B]{channel["name"]}[/B][/COLOR]', channel.get("logo", ""), f"{_URL}/play/{historyItem}")
    xbmcplugin.endOfDirectory(plugin.handle)


@plugin.route('/categories/')
def categories():
    xbmcplugin.setContent(plugin.handle, 'Categories')
    xbmcplugin.setPluginCategory(plugin.handle, "Categories")

    groups = list(set([channel['group'] for channel in parsePlaylist(_PLAYLIST_FILE)]))

    if "CZ" in groups and "SK" in groups:
        groups.remove("CZ")
        groups.remove("SK")
        groups.append("CS")
        groups.append("EN")
        groups.append("DE")
        groups.append("FR")

    for group in groups:
        addDir('[COLOR gold]{}[/COLOR]'.format(group), getIMG('grid', color), "{}/category/{}".format(_URL, group), True)
    
    xbmcplugin.endOfDirectory(plugin.handle)


@plugin.route('/category/<category>')
def category(category):
    xbmcplugin.setContent(plugin.handle, 'Categories')
    xbmcplugin.setPluginCategory(plugin.handle, "Categories")
    
    categories = [category]
    if category == "CS":
        categories.append("CZ")
        categories.append("SK")

    for channel in parsePlaylist(_PLAYLIST_FILE):
        if channel['group'] not in categories:
            continue

        addChannel(f"[COLOR gold][B]{channel['name']}[/B][/COLOR]", channel['logo'], channel['url'])
    xbmcplugin.endOfDirectory(plugin.handle)



@plugin.route('/play/<id>')
def play(id):
    # List sources
    channels = json.loads(open(_CHANNELS_FILE, 'r', encoding='utf-8').read())
    names = []
    modules, chs = [], []
    checkedSources = {}
    for value in channels[id]["sources"]:
        if not value["disabled"]:
            # Check if grabber is installed for specific module
            installed = checkedSources.get(value["module"], checkForGrabber(value["module"]))
            checkedSources[value["module"]] = installed

            if not installed:
                continue

            names.append(value["source_name"])
            modules.append(value["module"])
            chs.append(value["channel"])
    

    select = 0
    if len(names) == 0:
        xbmcgui.Dialog().ok("Error", "No available sources")
        return

    if len(names) > 1:
        if _ADDON.getSetting("autoselectSource") == "false":
            select = xbmcgui.Dialog().select("Select source", names)
        else:
            select = random.randint(0, len(names)-1)
        if select == -1: exit()
    
    module, stream = modules[select], chs[select]

    def addToHistory(channel):
        history_content = json.loads(open(_HISTORY_FILE, 'r', encoding='utf-8').read())
        history_content.append(channel)
        open(_HISTORY_FILE, 'w', encoding='utf-8').write(json.dumps(history_content))


    # Add to History
    threading.Thread(target=addToHistory, args=(id, )).start()
    
    # Play selected
    hlsurl, headers = "", {}

    os.makedirs(os.path.join(_USERDATA_FOLDER, "ResolveURL_data"), exist_ok=True)

    rmf = resolve(
        module=module,
        channel=stream,
        data_folder=os.path.join(_USERDATA_FOLDER, "ResolveURL_data"),
        data_file=os.path.join(_USERDATA_FOLDER, "ResolveURL_data.json"),
        server_port=23569, # NOTE: Server is disabled, this is redundant
        progress_dialog=xbmcgui.DialogProgress,
    )

    if rmf.self_player:
        rmf.play(plugin.handle)
        
    else:
        hlsurl, headers = rmf.url, rmf.headers

        li = xbmcgui.ListItem(path=hlsurl+'|'+urlencode(headers))
        li.setContentLookup(False)
        if _ADDON.getSetting("useinputstreamadaptive") == "true":
            li.setProperty('inputstream','inputstream.adaptive')
            li.setProperty('inputstream.adaptive.manifest_type','hls')

        ch_data = channels.get(id, {})
        ch_epg_id = ch_data.get("epg", "")
        title = ch_data.get("name", id)
        plot = ""
        genre = ""
        if ch_epg_id:
            _, progs = _load_epg_data()
            if progs:
                for p in _find_current(progs):
                    if p['channel'] == ch_epg_id:
                        time_str = ""
                        if p['start_dt'] and p['stop_dt']:
                            time_str = "{} - {}".format(p['start_dt'].strftime("%H:%M"), p['stop_dt'].strftime("%H:%M"))
                        title_line = "[B]{}[/B]".format(p['title'])
                        if time_str:
                            title_line += " " + time_str
                        if p['desc']:
                            plot = "{}\n{}".format(title_line, p['desc'])
                        else:
                            plot = title_line
                        genre = p['category'] or ""
                        break
        li.setInfo('video', {'title': title, 'plot': plot, 'genre': genre, 'mediatype': 'video'})
        xbmcplugin.setResolvedUrl(plugin.handle, True, li)



def _set_pvr_instance_setting(setting_id, value):
    pvr_dir = os.path.join(xbmcvfs.translatePath('special://userdata'), 'addon_data', 'pvr.iptvsimple')
    if not os.path.isdir(pvr_dir):
        return
    target = None
    for f in sorted(os.listdir(pvr_dir)):
        if f.startswith('instance-settings-') and f.endswith('.xml'):
            path = os.path.join(pvr_dir, f)
            tree = ET.parse(path)
            root = tree.getroot()
            enabled = root.find("setting[@id='kodi_addon_instance_enabled']")
            if enabled is None or enabled.text == 'true':
                target = (path, tree, root)
                break
    if target is None:
        path = os.path.join(pvr_dir, 'settings.xml')
        if not os.path.isfile(path):
            return
        tree = ET.parse(path)
        root = tree.getroot()
        target = (path, tree, root)
    path, tree, root = target
    for setting in root.findall('setting'):
        if setting.get('id') == setting_id:
            setting.text = value
            if setting.get('default') is not None:
                del setting.attrib['default']
            break
    tree.write(path, encoding='utf-8', xml_declaration=True)


@plugin.route('/ISS')
def iptvsimpleSetup():
    try:
        pisc = xbmcaddon.Addon('pvr.iptvsimple')
    except:
        xbmcgui.Dialog().notification(_ADDON_NAME, "IPTV Simple not found", xbmcgui.NOTIFICATION_INFO, 5000)
        return
    
    genPlaylist()
    
    _set_pvr_instance_setting('m3uPathType', '0')
    _set_pvr_instance_setting('m3uPath', 'special://userdata/addon_data/' + _ADDON_ID + '/playlist.m3u')
    _set_pvr_instance_setting('m3uRefreshMode', '0')
    _set_pvr_instance_setting('startNum', '1')

    epg_set = False
    if _ADDON.getSetting("epgEnabled") == "true":
        try:
            source, source_url = _get_epg_source()
            update_epg(_USERDATA_FOLDER, genList(_ADDON_FOLDER), source=source, source_url=source_url)
            _set_pvr_instance_setting('epgPath', 'special://userdata/addon_data/' + _ADDON_ID + '/epg.xml')
            _set_pvr_instance_setting('epgPathType', '0')
            _set_pvr_instance_setting('epgCache', '1')
            _set_pvr_instance_setting('epgTimeShift', '0')
            _set_pvr_instance_setting('epgIgnoreCaseForChannelIds', 'true')
            epg_set = True
        except:
            pass

    if not epg_set:
        epgUrl = _ADDON.getSetting("epgUrl")
        if epgUrl:
            _set_pvr_instance_setting('epgPath', epgUrl)
            _set_pvr_instance_setting('epgPathType', '0')
            _set_pvr_instance_setting('epgCache', '1')
            _set_pvr_instance_setting('epgTimeShift', '0')

    xbmcgui.Dialog().notification(_ADDON_NAME, "IPTV Simple setup completed", xbmcgui.NOTIFICATION_INFO, 5000)


@plugin.route('/ResolveURL_DeleteData')
def ResolveURL_DeleteData():
    dataFile = os.path.join(_USERDATA_FOLDER, "ResolveURL_data.json")
    dataFolder = os.path.join(_USERDATA_FOLDER, "ResolveURL_data")

    if os.path.exists(dataFile):
        os.remove(dataFile)
    
    if os.path.exists(dataFolder):
        shutil.rmtree(dataFolder)
    xbmcgui.Dialog().notification(_ADDON_NAME, "Successfully deleted ResolveURL Data", xbmcgui.NOTIFICATION_INFO, 5000)



@plugin.route('/Credits')
def credits():
    list = requests.get("https://images-ddg.pages.dev/list.json").json()
    text = "Created by:\n   Parrot Developers\nImages by:\n"
    credits = []
    for item in list: 
        if not list[item]['credits'].split(" - ")[0] in credits:
            credits.append(list[item]['credits'].split(" - ")[0])
    for credit in credits:
        text += "   {}\n".format(credit)
    xbmcgui.Dialog().textviewer("Credits", text)


if __name__ == "__main__":
    path = urlparse(sys.argv[0]).path

    if path == "/regenM3U":
        xbmcgui.Dialog().notification(_ADDON_NAME, "Starting M3U Generator", xbmcgui.NOTIFICATION_INFO, 5000)
        genPlaylist()
        xbmcgui.Dialog().notification(_ADDON_NAME, "Playlist Updated", xbmcgui.NOTIFICATION_INFO, 5000)
        exit()

    plugin.run(sys.argv)
