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

from elementmaker import E
from gettext import gettext as _
from gettext import ngettext

from book_list.globals import get_session_data
from dom import clear, unique_id
from dom import svgicon
from read_book.globals import current_book
from read_book.prefs.utils import create_button_box
from session import get_interface_data, session_defaults
from utils import fmt_sidx
from viewer.constants import CHARS_PER_PAGE

CONTAINER = unique_id('reader-hf-prefs')


def create_item(region, label, style):
    def sep():
        return E.option('\xa0', disabled=True)

    def opt(label, name, selected):
        return E.option(label, id=name, value=name, selected=bool(selected))

    s = E.div(
        E.select(
            data_region=region,
            opt(_('Empty'), 'empty', True),
            sep(),
            opt(_('Book title'), 'title'),
            opt(_('Authors'), 'authors'),
            opt(_('Series'), 'series'),
            sep(),
            opt(_('Top level section'), 'top-section'),
            opt(_('Current section'), 'section'),
            opt(_('View mode'), 'view-mode'),
            opt(_('View mode as icon'), 'view-mode-icon'),
            sep(),
            opt(_('Clock'), 'clock'),
            opt(_('Controls button on hover'), 'menu-icon-on-hover'),
            sep(),
            opt(_('Progress'), 'progress'),
            opt(_('Time to read book'), 'time-book'),
            opt(_('Time to read chapter'), 'time-chapter'),
            opt(_('Time to read chapter and book'), 'time-chapter-book'),
            opt(_('Position in book'), 'pos-book'),
            opt(_('Position in chapter'), 'pos-chapter'),
            opt(_('Pages in chapter'), 'pages-progress'),
            opt(_('Pages from paper edition'), 'page-list'),
            opt(_('Pages from paper edition with total'), 'page-list-with-total'),
        ), E.span(svgicon('angle-down')),
        data_component='select',
    )

    return E.tr(
        style=style or '',
        E.td(label + ':', style='padding: 1ex 1rem'),
        E.td(s)
    )


def create_items(which):
    if which is 'header' or which is 'footer':
        ans = E.table(
            data_which=which,
            create_item('left', _('Left')),
            create_item('middle', _('Middle')),
            create_item('right', _('Right'))
        )
    elif which is 'controls_footer':
        ans = E.table(
            data_which=which,
        create_item('left', _('Left'), 'display: none'),
            create_item('middle', _('Middle')),
            create_item('right', _('Right'))
        )
    else:
        ans = E.table(
            data_which=which,
            create_item('left', _('Top')),
            create_item('middle', _('Middle')),
            create_item('right', _('Bottom'))
        )
    return ans


def apply_setting(table, val):
    for region in 'left middle right'.split(' '):
        sel = table.querySelector(f'select[data-region={region}]')
        for opt in sel.selectedOptions:
            opt.selected = False
        x = val[region] or 'empty'
        opt = sel.namedItem(x)
        if opt:
            opt.selected = True
        else:
            sel.selectedIndex = 0


def get_setting(table):
    ans = {}
    for region in 'left middle right'.split(' '):
        sel = table.querySelector(f'select[data-region={region}]')
        if sel.selectedIndex > -1:
            ans[region] = sel.options[sel.selectedIndex].value
    return ans


def groups():
    return {'header': _('Header'), 'footer': _('Footer'),
            'left-margin': _('Left margin'), 'right-margin': _('Right margin'),
            'controls_footer': _('Controls footer'),
    }


def restore_defaults():
    container = document.getElementById(CONTAINER)
    for which in Object.keys(groups()):
        table = container.querySelector(f'table[data-which={which}]')
        apply_setting(table, session_defaults()[which] or {})


def create_head_foot_panel(container, apply_func, cancel_func):
    gr = groups()
    container.appendChild(E.div(id=CONTAINER))
    container = container.lastChild

    for key in gr:
        s = 'margin: 1rem;'
        if container.childNodes.length > 0:
            s += 'margin-top: 0;'
        container.appendChild(E.h4(gr[key], style=s))
        container.appendChild(create_items(key))
        container.appendChild(E.hr(style='margin-top: 1ex; margin-bottom: 1ex'))
    container.removeChild(container.lastChild)

    sd = get_session_data()
    for which in Object.keys(gr):
        table = container.querySelector(f'table[data-which={which}]')
        apply_setting(table, sd.get(which) or {})
    container.appendChild(E.div(style='margin: 1rem', create_button_box(restore_defaults, apply_func, cancel_func)))


def commit_head_foot(onchange, container):
    sd = get_session_data()
    changed = False
    for which in Object.keys(groups()):
        prev = sd.get(which) or {}
        table = container.querySelector(f'table[data-which={which}]')
        current = get_setting(table)
        for region in 'left middle right'.split(' '):
            if prev[region] is not current[region]:
                changed = True
        sd.set(which, get_setting(table))

    if changed:
        onchange()


if window?.Intl?.DateTimeFormat:
    time_formatter = window.Intl.DateTimeFormat(undefined, {'hour': 'numeric', 'minute': 'numeric'})
else:
    time_formatter = {'format': def (date):
        return '{}:{}'.format(date.getHours(), date.getMinutes())
    }


def set_time_formatter(func):
    nonlocal time_formatter
    time_formatter = {'format': func}


def format_time_left(seconds):
    hours, minutes = divmod(int(seconds / 60), 60)
    if hours <= 0:
        if minutes < 1:
            return _('almost done')
        minutes = minutes
        return ngettext('{} min', '{} mins', minutes).format(minutes)
    if not minutes:
        return ngettext('{} hour', '{} hours', hours).format(hours)
    return _('{} h {} mins').format(hours, minutes)


def format_pos(progress_frac, length):
    if length < 1:
        return ''
    pages = Math.ceil(length / CHARS_PER_PAGE)
    pos = progress_frac * pages
    return f'{pos:.1f} / {pages}'


def render_head_foot(div, which, region, metadata, current_toc_node, current_toc_toplevel_node, page_list, book_time, chapter_time, pos, override, view_mode):
    template = get_session_data().get(which) or {}
    field = template[region] or 'empty'
    interface_data = get_interface_data()
    text = ''
    has_clock = False
    div.style.textOverflow = 'ellipsis'
    div.style.overflow = 'hidden'
    force_display_even_if_overflowed = False
    if override:
        text = override
    elif field is 'menu-icon-on-hover':
        clear(div)
        div.appendChild(E.div(class_='visible-on-hover', E.span(_('Show controls')), title=_('Show viewer controls'), style='cursor: pointer'))
        return has_clock
    elif field is 'progress':
        percent = min(100, max(Math.round(pos.progress_frac * 100), 0))
        text = percent + '%'
        force_display_even_if_overflowed = True
    elif field is 'title':
        text = metadata.title or _('Untitled')
    elif field is 'authors':
        text = ' & '.join(metadata.authors or [])
    elif field is 'series':
        if metadata.series:
            ival = fmt_sidx(metadata.series_index, use_roman=interface_data.use_roman_numerals_for_series_number)
            text = _('{0} of {1}').format(ival, metadata.series)
    elif field is 'clock':
        force_display_even_if_overflowed = True
        text = time_formatter.format(Date())
        has_clock = True
    elif field is 'section':
        text = current_toc_node.title if current_toc_node else ''
    elif field is 'top-section':
        text = current_toc_toplevel_node.title if current_toc_toplevel_node else ''
        if not text:
            text = current_toc_node.title if current_toc_node else ''
    elif field is 'view-mode':
        text = _('Paged') if view_mode is 'paged' else _('Flow')
    elif field is 'view-mode-icon':
        text = '📄' if view_mode is 'paged' else '📜'
    elif field.startswith('time-'):
        if book_time is None or chapter_time is None:
            text = _('Calculating...')
        else:
            if field is 'time-book':
                text = format_time_left(book_time)
            elif field is 'time-chapter':
                text = format_time_left(chapter_time)
            else:
                text = '{} ({})'.format(format_time_left(chapter_time), format_time_left(book_time))
    elif field.startswith('pos-'):
        if field is 'pos-book':
            text = format_pos(pos.progress_frac, pos.book_length)
        else:
            text = format_pos(pos.file_progress_frac, pos.chapter_length)
    elif field is 'pages-progress':
        if pos.page_counts:
            text = f'{pos.page_counts.current + 1} / {pos.page_counts.total}'
        else:
            text = _('Unknown')
    elif field is 'page-list':
        if page_list and page_list.length > 0:
            if page_list.length is 1:
                text = page_list[0].pagenum
            else:
                text = f'{page_list[0].pagenum} - {page_list[-1].pagenum}'
    elif field is 'page-list-with-total':
        if page_list and page_list.length > 0:
            if page_list.length is 1:
                text = page_list[0].pagenum
            else:
                text = f'{page_list[0].pagenum} - {page_list[-1].pagenum}'
            full_page_list = current_book().manifest.page_list
            if full_page_list:
                text = f'{text} / {full_page_list[-1].pagenum}'
    if not text:
        text = '\xa0'
    if text is not div.textContent:
        div.textContent = text
    if force_display_even_if_overflowed:
        div.style.textOverflow = 'clip'
        div.style.overflow = 'visible'
    return has_clock
