
import os
import xml.etree.ElementTree as ET
import xml.dom.minidom as minidom

import xbmc
import xbmcgui
import xbmcplugin
import xbmcvfs

from urllib.parse import quote_plus


ADS_FILE = xbmcvfs.translatePath("special://userdata/advancedsettings.xml")

CACHE_DEFAULTS = {
    'buffermode': '0',
    'memorysize': '20971520',   # 20 MB
    'readfactor': '4',
}

CACHE_LABELS = {
    'buffermode': 'Tryb buforowania',
    'memorysize': 'Rozmiar bufora',
    'readfactor': 'Readfactor',
    'curlclienttimeout': 'Timeout połączenia CURL (sek.)',
    'curllowspeedtime': 'CURL czas niskiej prędkości (sek.)',
    'curlretries': 'CURL liczba powtórzeń',
    'cachemembuffersize': 'Bufor pamięci cache',
}

BUFFERMODE_LABELS = [
    '0 - Buforuj internet (domyślnie)',
    '1 - Buforuj wszystkie systemy plików',
    '2 - Buforuj tylko prawdziwy internet',
    '3 - Bez buforowania',
    '4 - Buforuj wszystko',
]

MEMORYSIZE_OPTIONS = [
    (20971520,   '20 MB (domyślne Kodi)'),
    (52428800,   '50 MB'),
    (104857600,  '100 MB'),
    (157286400,  '150 MB'),
    (209715200,  '200 MB'),
    (268435456,  '256 MB'),
    (524288000,  '500 MB'),
]

READFACTOR_OPTIONS = [
    ('1',  '1x'),
    ('2',  '2x'),
    ('4',  '4x (domyślne)'),
    ('6',  '6x'),
    ('8',  '8x'),
    ('10', '10x'),
    ('15', '15x'),
    ('20', '20x'),
]

NETWORK_DEFAULTS = {
    'disablehttp2': 'true',
}

NETWORK_LABELS = {
    'disablehttp2': 'Wyłącz HTTP/2',
    'curlclienttimeout': 'Timeout połączenia CURL (sek.)',
    'curllowspeedtime': 'CURL czas niskiej prędkości (sek.)',
    'curlretries': 'CURL liczba powtórzeń',
    'curlproxytunnel': 'Tunel proxy CURL',
}

BOOLEAN_LABELS = [
    'true - Tak',
    'false - Nie',
]

SECTION_DEFAULTS = {
    'cache': CACHE_DEFAULTS,
    'network': NETWORK_DEFAULTS,
}

SECTION_SETTING_LABELS = {
    'cache': CACHE_LABELS,
    'network': NETWORK_LABELS,
}

SECTION_LABELS = {
    'cache': 'Cache / Buforowanie',
    'gui': 'Interfejs (GUI)',
    'network': 'Sieć (Network)',
    'video': 'Wideo',
    'audio': 'Audio',
    'services': 'Usługi (Services)',
    'pvr': 'PVR / TV',
}


def log(msg):
    xbmc.log('[kodisettings] ' + str(msg), level=xbmc.LOGINFO)

def _load_ads():
    """Wczytuje advancedsettings.xml. Zwraca root Element lub None."""
    if xbmcvfs.exists(ADS_FILE):
        try:
            tree = ET.parse(ADS_FILE)
            return tree.getroot()
        except ET.ParseError:
            return None
    return None

def _read_value(section, tag, default):
    """Odczytuje wartość tagu z sekcji XML."""
    root = _load_ads()
    if root is None:
        return default
    sec = root.find(section)
    if sec is None:
        return default
    elem = sec.find(tag)
    if elem is None or elem.text is None:
        return default
    return elem.text

def _write_value(root, section, tag, value):
    """Zapisuje wartość do sekcji XML. Tworzy sekcję jeśli nie istnieje."""
    sec = root.find(section)
    if sec is None:
        sec = ET.SubElement(root, section)
    elem = sec.find(tag)
    if elem is None:
        elem = ET.SubElement(sec, tag)
    elem.text = str(value)

def _save_ads(root):
    """Robi backup .bak i zapisuje XML z ładnym formatowaniem."""
    if xbmcvfs.exists(ADS_FILE):
        bak = ADS_FILE + '.bak'
        if xbmcvfs.exists(bak):
            xbmcvfs.delete(bak)
        xbmcvfs.copy(ADS_FILE, bak)

    xml_string = minidom.parseString(ET.tostring(root)).toprettyxml()
    xml_string = os.linesep.join(s for s in xml_string.splitlines() if s.strip())
    with open(ADS_FILE, 'w') as f:
        f.write(xml_string)

def _get_or_create_root():
    """Zwraca istniejący root XML lub tworzy nowy."""
    root = _load_ads()
    if root is None:
        root = ET.fromstring('<advancedsettings version="1.0" />')
    return root

def _format_cache_value(tag, value):
    """Formatuje wartość cache do wyświetlenia."""
    if tag == 'buffermode':
        try:
            return BUFFERMODE_LABELS[int(value)]
        except (ValueError, IndexError):
            return value
    elif tag == 'memorysize':
        try:
            mb = int(value) // 1048576
            return '%d MB' % mb
        except ValueError:
            return value
    elif tag == 'readfactor':
        return '%sx' % value
    return value


def mainMenu(add_func, addon_handle, sysaddon):
    """Menu główne: dynamicznie wyświetla sekcje z advancedsettings.xml."""
    root = _load_ads()

    if root is not None:
        existing_sections = set()
        for section in root:
            section_name = section.tag
            existing_sections.add(section_name)
            label = SECTION_LABELS.get(section_name, section_name)
            child_count = len(section)
            label = '[%s]  (%d ustawień)' % (label, child_count)
            add_func(label, section_name, 'KodiSection', True)

        for sec_name in SECTION_DEFAULTS:
            if sec_name not in existing_sections:
                sec_label = SECTION_LABELS.get(sec_name, sec_name)
                add_func('+ Dodaj sekcję: %s' % sec_label, sec_name, 'KodiSectionAdd', False)
    else:
        add_func('Brak advancedsettings.xml', '0', '', False)
        for sec_name in SECTION_DEFAULTS:
            sec_label = SECTION_LABELS.get(sec_name, sec_name)
            add_func('+ Utwórz z domyślnymi: %s' % sec_label, sec_name, 'KodiSectionAdd', False)

    xbmcplugin.endOfDirectory(addon_handle)

def sectionMenu(add_func, addon_handle, sysaddon, section_name):
    """Wyświetla ustawienia wybranej sekcji."""
    root = _load_ads()
    if root is None:
        return

    section = root.find(section_name)
    if section is None:
        return

    labels = SECTION_SETTING_LABELS.get(section_name, {})
    existing_tags = set()
    for elem in section:
        tag = elem.tag
        existing_tags.add(tag)
        value = elem.text if elem.text else ''

        label = labels.get(tag, tag)
        if section_name == 'cache':
            display_value = _format_cache_value(tag, value)
        else:
            display_value = value

        item_url = '%s|%s' % (section_name, tag)
        add_func('%s:  [%s]' % (label, display_value), item_url, 'KodiSettingEdit', False)

    defaults = SECTION_DEFAULTS.get(section_name)
    if defaults:
        for tag in defaults:
            if tag not in existing_tags:
                label = labels.get(tag, tag)
                item_url = '%s|%s' % (section_name, tag)
                add_func('+ Dodaj: %s' % label, item_url, 'KodiSettingEdit', False)
        add_func('--- Resetuj sekcję ---', section_name, 'KodiSectionReset', False)
    else:
        add_func('+ Dodaj ustawienie...', section_name, 'KodiSettingAdd', False)

    xbmcplugin.endOfDirectory(addon_handle)

def editSetting(params):
    """Edycja ustawienia — rozpoznaje znane ustawienia cache i daje odpowiedni dialog."""
    parts = params.split('|')
    if len(parts) != 2:
        return
    section_name, tag = parts

    dlg = xbmcgui.Dialog()

    if section_name == 'cache' and tag == 'buffermode':
        _edit_buffermode(dlg)
        return
    if section_name == 'cache' and tag == 'memorysize':
        _edit_memorysize(dlg)
        return
    if section_name == 'cache' and tag == 'readfactor':
        _edit_readfactor(dlg)
        return

    if section_name == 'network' and tag == 'disablehttp2':
        _edit_boolean(dlg, 'network', 'disablehttp2', 'Wyłącz HTTP/2')
        return

    current = _read_value(section_name, tag, '')
    labels = SECTION_SETTING_LABELS.get(section_name, {})
    label = labels.get(tag, tag)
    input_type = xbmcgui.INPUT_NUMERIC if current.isdigit() else xbmcgui.INPUT_ALPHANUM
    result = dlg.input('Edytuj: %s' % label, defaultt=current, type=input_type)
    if result is None or result == '':
        return

    root = _get_or_create_root()
    _write_value(root, section_name, tag, result)
    _save_ads(root)

    dlg.notification('Ustawienia Kodi', 'Zapisano. Zrestartuj Kodi.',
                     xbmcgui.NOTIFICATION_INFO, 3000)
    xbmc.executebuiltin('Container.Refresh')

def _edit_buffermode(dlg):
    """Dialog wyboru trybu buforowania."""
    current = _read_value('cache', 'buffermode', CACHE_DEFAULTS['buffermode'])
    try:
        preselect = int(current)
    except ValueError:
        preselect = 0
    choice = dlg.select('Tryb buforowania', BUFFERMODE_LABELS, preselect=preselect)
    if choice < 0:
        return
    root = _get_or_create_root()
    _write_value(root, 'cache', 'buffermode', str(choice))
    _save_ads(root)
    dlg.notification('Cache', 'Zapisano. Zrestartuj Kodi.', xbmcgui.NOTIFICATION_INFO, 3000)
    xbmc.executebuiltin('Container.Refresh')

def _edit_memorysize(dlg):
    """Dialog wyboru rozmiaru bufora z predefiniowanych wartości."""
    labels = [opt[1] for opt in MEMORYSIZE_OPTIONS]
    current = _read_value('cache', 'memorysize', CACHE_DEFAULTS['memorysize'])

    preselect = 0
    try:
        current_int = int(current)
        for i, opt in enumerate(MEMORYSIZE_OPTIONS):
            if opt[0] == current_int:
                preselect = i
                break
    except ValueError:
        pass

    choice = dlg.select('Rozmiar bufora', labels, preselect=preselect)
    if choice < 0:
        return
    value = str(MEMORYSIZE_OPTIONS[choice][0])
    root = _get_or_create_root()
    _write_value(root, 'cache', 'memorysize', value)
    _save_ads(root)
    dlg.notification('Cache', 'Zapisano. Zrestartuj Kodi.', xbmcgui.NOTIFICATION_INFO, 3000)
    xbmc.executebuiltin('Container.Refresh')

def _edit_readfactor(dlg):
    """Dialog wyboru readfactor z predefiniowanych wartości."""
    labels = [opt[1] for opt in READFACTOR_OPTIONS]
    current = _read_value('cache', 'readfactor', CACHE_DEFAULTS['readfactor'])

    preselect = 0
    for i, opt in enumerate(READFACTOR_OPTIONS):
        if opt[0] == current:
            preselect = i
            break

    choice = dlg.select('Readfactor', labels, preselect=preselect)
    if choice < 0:
        return
    value = READFACTOR_OPTIONS[choice][0]
    root = _get_or_create_root()
    _write_value(root, 'cache', 'readfactor', value)
    _save_ads(root)
    dlg.notification('Cache', 'Zapisano. Zrestartuj Kodi.', xbmcgui.NOTIFICATION_INFO, 3000)
    xbmc.executebuiltin('Container.Refresh')

def _edit_boolean(dlg, section_name, tag, label):
    """Dialog wyboru true/false."""
    current = _read_value(section_name, tag, 'false')
    preselect = 0 if current == 'true' else 1
    choice = dlg.select(label, BOOLEAN_LABELS, preselect=preselect)
    if choice < 0:
        return
    value = 'true' if choice == 0 else 'false'
    root = _get_or_create_root()
    _write_value(root, section_name, tag, value)
    _save_ads(root)
    dlg.notification('Ustawienia Kodi', 'Zapisano. Zrestartuj Kodi.', xbmcgui.NOTIFICATION_INFO, 3000)
    xbmc.executebuiltin('Container.Refresh')

def addSetting(section_name):
    """Dodaje nowe ustawienie do sekcji — pyta o nazwę i wartość."""
    dlg = xbmcgui.Dialog()
    tag = dlg.input('Nazwa ustawienia (tag XML)')
    if not tag:
        return
    value = dlg.input('Wartość dla: %s' % tag)
    if value is None:
        return

    root = _get_or_create_root()
    _write_value(root, section_name, tag, value)
    _save_ads(root)

    dlg.notification('Ustawienia Kodi', 'Dodano %s. Zrestartuj Kodi.' % tag,
                     xbmcgui.NOTIFICATION_INFO, 3000)
    xbmc.executebuiltin('Container.Refresh')

def addSectionDefaults(section_name):
    """Tworzy sekcję z domyślnymi wartościami."""
    defaults = SECTION_DEFAULTS.get(section_name)
    if not defaults:
        return

    dlg = xbmcgui.Dialog()
    sec_label = SECTION_LABELS.get(section_name, section_name)
    if not dlg.yesno(sec_label, 'Dodać sekcję %s z domyślnymi ustawieniami?' % sec_label):
        return

    root = _get_or_create_root()
    for tag, value in defaults.items():
        _write_value(root, section_name, tag, value)
    _save_ads(root)

    dlg.notification(sec_label, 'Dodano domyślne ustawienia. Zrestartuj Kodi.',
                     xbmcgui.NOTIFICATION_INFO, 3000)
    xbmc.executebuiltin('Container.Refresh')

def resetSection(section_name):
    """Usuwa sekcję z advancedsettings.xml po potwierdzeniu."""
    dlg = xbmcgui.Dialog()
    sec_label = SECTION_LABELS.get(section_name, section_name)
    if not dlg.yesno('Resetuj', 'Usunąć sekcję %s i przywrócić domyślne Kodi?' % sec_label):
        return

    root = _load_ads()
    if root is None:
        dlg.notification(sec_label, 'Brak pliku advancedsettings.xml', xbmcgui.NOTIFICATION_INFO)
        return

    sec = root.find(section_name)
    if sec is not None:
        root.remove(sec)
        _save_ads(root)
        dlg.notification(sec_label, 'Zresetowano. Zrestartuj Kodi.', xbmcgui.NOTIFICATION_INFO, 3000)
    else:
        dlg.notification(sec_label, 'Sekcja nie istnieje', xbmcgui.NOTIFICATION_INFO)

    xbmc.executebuiltin('Container.Refresh')
