# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
from __python__ import hash_literals

from elementmaker import E
from gettext import gettext as _

from book_list.globals import get_session_data
from book_list.router import back
from book_list.top_bar import create_top_bar
from dom import clear, ensure_id, add_extra_css, build_rule
from widgets import create_button, create_select

pp_counter = 0
widget_counter = 0

CLASS_NAME = 'cs-prefs'

add_extra_css(def ():
    sel = '.' + CLASS_NAME + ' '
    style = ''
    # Match page gutter + readable width
    style += build_rule(sel,
        padding='0.75rem 1rem 1rem 1rem',
        max_width='980px',
        width='100%',
        box_sizing='border-box',
        min_width='0',
        margin_left='auto',
        margin_right='auto'
    )
    style += r'''
@media (max-width: 720px) {
  .cs-prefs { padding-left: 0.75rem; padding-right: 0.75rem; }
}
@media (max-width: 520px) {
  .cs-prefs .item-main {
    flex-direction: column;
    align-items: stretch;
  }
  .cs-prefs .control {
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
  }
  .cs-prefs .control .label {
    flex: 0 0 auto;
  }
}
'''
    style += build_rule(sel + '.list',
        display='flex', flex_direction='column', gap='0.65rem',
        min_width='0',
        width='100%',
        box_sizing='border-box',
    )
    style += build_rule(sel + '.item',
        padding='0.85rem 1rem',
        border_radius='16px',
        border='var(--calibre-border-style-subtle)',
        background='linear-gradient(135deg, var(--calibre-color-surface-1) 0%, var(--calibre-color-surface-2) 100%)',
        box_shadow='0 12px 32px rgba(0,0,0,0.08)',
        min_width='0',
        max_width='100%',
        box_sizing='border-box',
        # No frosted glass effects (restore original, flat styling)
    )
    style += build_rule(sel + '.item:hover',
        border='var(--calibre-border-style)',
        box_shadow='0 16px 44px rgba(0,0,0,0.10)'
    )
    style += build_rule(sel + '.item-main',
        display='flex',
        align_items='center',
        justify_content='space-between',
        gap='1rem',
        flex_wrap='wrap',
        min_width='0',
        width='100%',
        box_sizing='border-box',
    )
    style += build_rule(sel + '.control',
        display='flex',
        align_items='center',
        justify_content='space-between',
        gap='0.75rem',
        flex='1 1 auto',
        min_width='0',
        max_width='100%',
        box_sizing='border-box',
    )
    style += build_rule(sel + '.label',
        font_weight='800',
        white_space='normal',
        opacity='0.92',
        flex='1 1 auto',
        min_width='0',
        max_width='100%',
        overflow_wrap='anywhere',
        word_break='break-word',
    )
    style += build_rule(sel + '.control input[type="text"],' + sel + '.control input[type="number"]',
        min_width='0',
        max_width='100%',
        width='100%',
        flex='1 1 auto',
    )
    style += build_rule(sel + '.help',
        margin_top='0.65rem',
        padding_top='0.65rem',
        border_top='var(--calibre-border-style-subtle)',
        font_size='0.85rem',
        font_weight='700',
        opacity='0.75',
        display='none',
        max_width='100%',
        overflow_wrap='anywhere',
        word_break='break-word',
    )
    style += build_rule(sel + '.footer',
        margin_top='1rem',
        display='flex',
        justify_content='flex-end'
    )
    return style
)


class ConfigItem:
    def __init__(self, item_data):
        nonlocal widget_counter
        widget_counter += 1
        self.widget_id = 'pref-widget-' + widget_counter
        self.item_data = item_data
        self.ignore_ui_value_changed = False

    def initialize(self):
        self.ignore_ui_value_changed = True
        try:
            self.to_ui(self.from_storage())
        finally:
            self.ignore_ui_value_changed = False
        return self

    @property
    def container(self):
        return document.getElementById(self.widget_id)

    @property
    def control(self):
        return self.container.lastChild

    def from_storage(self):
        val = get_session_data().get(self.item_data.name)
        if self.item_data.from_storage:
            val = self.item_data.from_storage(val)
        return val

    def to_storage(self, val):
        if self.item_data.to_storage:
            val = self.item_data.to_storage(val)
        get_session_data().set(self.item_data.name, val)

    def defval(self):
        val = get_session_data().defval(self.item_data.name)
        if self.item_data.from_storage:
            val = self.item_data.from_storage(val)
        return val

    def ui_value_changed(self):
        if self.ignore_ui_value_changed:
            return
        val = self.from_ui()
        self.to_storage(val)
        if self.item_data.onchange:
            self.item_data.onchange(val)

    def reset_to_default(self):
        self.to_ui(self.defval())
        self.ui_value_changed()

    def to_ui(self, val):
        pass

    def from_ui(self):
        pass


class Choices(ConfigItem):
    def __init__(self, item_data, container, onfocus):
        ConfigItem.__init__(self, item_data)
        options = {}
        for choice, text in item_data.choices:
            options[choice] = text
        c, select = create_select(item_data.text, '', **options)
        div = E.div(
            id=self.widget_id,
            E.span(item_data.text, class_='label'),
            c
        )
        div.classList.add('control')
        container.appendChild(div)
        select.addEventListener('change', self.ui_value_changed.bind(self))
        select.addEventListener('focus', onfocus)
        div.addEventListener('click', onfocus)

    @property
    def control(self):
        return self.container.getElementsByTagName('select')[0]

    def to_ui(self, val):
        self.control.value = val

    def from_ui(self):
        return self.control.value


class CheckBox(ConfigItem):
    def __init__(self, item_data, container, onfocus):
        ConfigItem.__init__(self, item_data)
        div = E.div(
            id=self.widget_id,
            style='cursor: pointer',
            E.input(type='checkbox'),
            E.span(item_data.text, class_='label')
        )
        div.classList.add('control')
        container.appendChild(div)
        control = div.firstChild
        control.addEventListener('change', self.ui_value_changed.bind(self))
        control.addEventListener('focus', onfocus)
        div.addEventListener('click', onfocus)
        div.lastChild.addEventListener('click', self.toggle.bind(self))

    @property
    def control(self):
        return self.container.firstChild

    def to_ui(self, val):
        self.control.checked = bool(val)

    def from_ui(self):
        return bool(self.control.checked)

    def toggle(self):
        self.to_ui(not self.from_ui())
        self.ui_value_changed()


class SpinBox(ConfigItem):
    def __init__(self, item_data, container, onfocus):
        ConfigItem.__init__(self, item_data)
        div = E.div(
            id=self.widget_id,
            E.span(item_data.text, class_='label'),
            E.input(type='number', step='any', min='1', max='100')
        )
        div.classList.add('control')
        container.appendChild(div)
        control = div.lastChild
        for attr in 'min max step'.split(' '):
            val = item_data[attr]
            if val is not undefined and val is not None:
                control.setAttribute(attr, '' + val)
        control.addEventListener('change', self.ui_value_changed.bind(self))
        control.addEventListener('focus', onfocus)
        div.addEventListener('click', onfocus)

    def to_ui(self, val):
        self.control.value = val

    def from_ui(self):
        return self.control.value


class LineEdit(ConfigItem):
    def __init__(self, item_data, container, onfocus):
        ConfigItem.__init__(self, item_data)
        div = E.div(
            id=self.widget_id,
            E.span(item_data.text, class_='label'),
            E.input(type='text')
        )
        div.classList.add('control')
        container.appendChild(div)
        control = div.lastChild
        control.addEventListener('change', self.ui_value_changed.bind(self))
        control.addEventListener('focus', onfocus)
        div.addEventListener('click', onfocus)

    def to_ui(self, val):
        self.control.value = val or ''

    def from_ui(self):
        return self.control.value or ''


class ColorEdit(ConfigItem):
    def __init__(self, item_data, container, onfocus):
        ConfigItem.__init__(self, item_data)
        div = E.div(
            id=self.widget_id,
            E.span(item_data.text, class_='label'),
            E.input(type='color')
        )
        div.classList.add('control')
        container.appendChild(div)
        control = div.lastChild
        control.addEventListener('change', self.ui_value_changed.bind(self))
        control.addEventListener('input', self.ui_value_changed.bind(self))
        control.addEventListener('focus', onfocus)
        div.addEventListener('click', onfocus)

    def to_ui(self, val):
        self.control.value = val or ''

    def from_ui(self):
        return self.control.value or ''


def onfocus(state, name):
    return def (ev):
        c = document.getElementById(state.container_id)
        div = c.querySelector('div[data-name="{}"]'.format(name))
        if div?.lastChild:
            div.lastChild.style.display = 'block'


def create_prefs_widget(container, prefs_data):
    state = {}
    state.container_id = ensure_id(container)
    state.widgets = []
    clear(container)
    try:
        container.classList.add(CLASS_NAME)
    except Exception:
        pass

    outer = E.div(class_='list')
    container.appendChild(outer)

    for item in prefs_data:
        div = E.div(
            title=item.tooltip,
            data_name=item.name,
            class_='item',
            E.div(class_='item-main'),
            E.div(item.tooltip or '', class_='help')
        )
        outer.appendChild(div)
        val = get_session_data().get(item.name)
        if item.from_storage:
            val = item.from_storage(val)
        if item.choices:
            cls = Choices
        elif item.type is 'color':
            cls = ColorEdit
        elif val is True or val is False:
            cls = CheckBox
        elif jstype(val) is 'number':
            cls = SpinBox
        else:
            cls = LineEdit
        state.widgets.push((new cls(item, div.firstChild, onfocus(state, item.name))).initialize())
    if state.widgets.length:
        container.appendChild(E.div(class_='footer',
            create_button(_('Restore default settings'), 'refresh', reset_to_defaults.bind(None, state))
        ))


def reset_to_defaults(state):
    for w in state.widgets:
        w.reset_to_default()


def prefs_panel_handler(title_func, get_prefs_data, on_close=None, icon='close'):
    def onkeydown(container_id, close_action, ev):
        if ev.key is 'Escape':
            ev.preventDefault(), ev.stopPropagation()
            close_action()

    def close_action():
        if on_close is not None:
            on_close()
        back()

    def init_prefs_panel(container_id):
        container = document.getElementById(container_id)
        container.addEventListener('keydown', onkeydown.bind(None, container_id, close_action), {'passive': False, 'capture': True})
        container.setAttribute('tabindex', '0')
        create_top_bar(container, title=title_func(), action=close_action, icon=icon)
        container.appendChild(E.div())
        create_prefs_widget(container.lastChild, get_prefs_data())
        container.focus()

    return init_prefs_panel
