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

from elementmaker import E
from gettext import gettext as _

from ajax import ajax_send
from book_list.cover_grid import BORDER_RADIUS
from book_list.globals import get_db
from book_list.library_data import last_virtual_library_for, sync_library_books, all_libraries
from book_list.router import open_book, update_window_title
from book_list.top_bar import add_button, create_top_bar
from book_list.ui import set_default_panel_handler, show_panel
from dom import add_extra_css, build_rule, clear, ensure_id, set_css, unique_id
from modals import create_custom_dialog
from session import get_device_uuid, get_interface_data
from utils import conditional_timeout, safe_set_inner_html, username_key
from widgets import create_button

CLASS_NAME = 'home-page'

add_extra_css(def():
    ans = ''
    sel = f'.{CLASS_NAME} '
    ans += build_rule(f'{sel} h2', padding='1rem', font_size='1.5em')
    sel += '.recently-read img'
    ans += build_rule(sel, max_width='25vw', max_height='40vh', height='auto', border_radius=f'{BORDER_RADIUS}px')
    ans += build_rule(f'{sel}:hover', transform='scale(1.2)')
    ans += build_rule(f'{sel}:active', transform='scale(2)')
    return ans
)


def show_cover(blob, name, mt, book):
    img = document.getElementById(this)
    if not img:
        return
    img.onload = def():
        window.URL.revokeObjectURL(this.src)
    img.src = window.URL.createObjectURL(blob)


def read_book(library_id, book_id, fmt):
    open_book(book_id, fmt, library_id)


def get_last_read_position(last_read_positions, prev_last_read):
    prev_epoch = prev_last_read.getTime()
    dev = get_device_uuid()
    newest_epoch = ans = None
    for data in last_read_positions:
        if data.device is not dev and data.epoch > prev_epoch:
            if ans is None or data.epoch > newest_epoch:
                newest_epoch = data.epoch
                ans = data
    return ans


def sync_data_received(library_id, lrmap, load_type, xhr, ev):
    if load_type is not 'load':
        print('Failed to get book sync data')
        return
    data = JSON.parse(xhr.responseText)

    db = get_db()
    for key in data:
        new_vals = data[key]
        entry = {'last_read': None, 'last_read_position': None, 'annotations_map': None}
        prev_last_read = lrmap[key]
        if prev_last_read:
            last_read_positions = new_vals.last_read_positions
            new_last_read = get_last_read_position(last_read_positions, prev_last_read)
            if new_last_read:
                last_read = new Date(new_last_read.epoch * 1000)
                cfi = new_last_read.cfi
                if cfi:
                    entry.last_read = last_read
                    entry.last_read_position = cfi
        new_amap = new_vals.annotations_map or {}
        is_empty = True
        v'for(var ikey in new_amap) { is_empty = false; break; }'
        if !is_empty:
            entry.annotations_map = new_amap
        if entry.last_read_position or entry.annotations_map:
            book_id, fmt = key.partition(':')[::2]
            db.update_annotations_data_from_key(library_id, int(book_id), fmt, entry)


def start_sync(to_sync):
    libraries = {}
    for key, last_read in to_sync:
        library_id = key[0]
        if not libraries[library_id]:
            libraries[library_id] = v'[]'
        libraries[library_id].push(v'[key, last_read]')
    for lid in libraries:
        sync_library_books(lid, libraries[lid], sync_data_received)


def show_recent_stage2(books):
    container = document.getElementById(this)
    if not container or not books.length:
        return
    container.style.display = 'block'
    container.style.borderBottom = 'solid 1px currentColor'
    container.style.paddingBottom = '1em'
    container.appendChild(E.h2(_(
        'Continue reading…')))
    container.appendChild(E.div(style='display:flex'))
    images = container.lastChild
    db = get_db()
    to_sync = v'[]'
    username = get_interface_data().username
    for book in books:
        if to_sync.length < 10:
            lr = book.last_read[username_key(username)] or new Date(0)  # noqa: unused-local
            to_sync.push(v'[book.key, lr]')
        authors = book.metadata.authors.join(' & ') if book.metadata.authors else _('Unknown')
        img = E.img(
            alt=_('{} by {}').format(book.metadata.title, authors)
        )
        img_id = ensure_id(img)
        images.appendChild(E.div(style='margin: 0 1em',
            E.a(img, href='javascript: void(0)', title=img.alt,
                onclick=read_book.bind(None, book.key[0], book.key[1], book.key[2])
            ),
        ))
        if book.cover_name:
            db.get_file(book, book.cover_name, show_cover.bind(img_id))
    start_sync(to_sync)
    container.appendChild(E.div(style='margin: 1rem 1rem',
        create_button(
            _('Browse all downloaded books…'),
            action=def():
                show_panel('local_books')
    )))


def show_recent():
    container = this
    db = get_db()
    if not db.initialized:
        conditional_timeout(container.id, 5, show_recent)
        return
    if db.is_ok:
        db.get_recently_read_books(show_recent_stage2.bind(container.id))
    else:
        print(db.initialize_error_msg)

# User account {{{

def change_password():
    interface_data = get_interface_data()
    create_custom_dialog(_('Change password for: {}').format(interface_data.username), def(parent, close_modal):
        ids = unique_id(), unique_id(), unique_id()
        parent.appendChild(E.table(
            E.tr(
                E.td(E.label(_('Current password:') + '\xa0', for_=ids[0])), set_css(E.td(E.input(type='password'), id=ids[0]), padding_bottom='1.5ex')
            ),
            E.tr(
                E.td(E.label(_('New password:') + '\xa0', for_=ids[1])), set_css(E.td(E.input(type='password'), id=ids[1]), padding_bottom='1.5ex')
            ),
            E.tr(
                E.td(E.label(_('New password again:') + '\xa0', for_=ids[2])), set_css(E.td(E.input(type='password'), id=ids[2]), padding_bottom='1.5ex')
            )
        ))
        parent.appendChild(E.div())

        def show_msg(html, is_info):
            msg = parent.firstChild.nextSibling
            safe_set_inner_html(msg, html)
            msg.style.color = 'red' if not is_info else 'currentColor'

        def on_complete(end_type, xhr, ev):
            if end_type is 'load':
                clear(parent)
                parent.appendChild(E.div(_(
                    'Password successfully changed, you will be asked for the new password'
                    ' the next time the browser has to contact the calibre server.')))
                parent.appendChild(
                    E.div(class_='button-box',
                        create_button(_('OK'), None, close_modal),
                ))
                return
            show_msg(_('Failed to change password, with error: {}').format(xhr.error_html))


        def ok():
            pws = parent.firstChild.getElementsByTagName('input')
            oldpw, pw1, pw2 = pws[0].value, pws[1].value, pws[2].value
            if pw1 is not pw2:
                show_msg(_('The two new passwords do not match'))
                return
            if not pw1 or not oldpw:
                show_msg(_('Empty passwords are not allowed'))
                return
            ajax_send('users/change-pw', {'oldpw': oldpw, 'newpw': pw1}, on_complete)
            show_msg(_('Contacting server, please wait...'), True)
            parent.lastChild.display = 'none'

        parent.appendChild(
            E.div(class_='button-box',
                create_button(_('OK'), None, ok), '\xa0',
                create_button(_('Cancel'), None, close_modal),
            )
        )
    )

def show_user_details():
    interface_data = get_interface_data()
    create_custom_dialog(_('Logged in as {}').format(interface_data.username), def(parent, close_modal):
            msg = E.div()
            safe_set_inner_html(msg, _(
                'You are logged in as the user <b>{}</b>. To log in '
                'as a different user, you will have to restart the browser.').format(interface_data.username))
            parent.appendChild(msg)
            parent.appendChild(
                E.div(class_='button-box',
                    create_button(_('Change password'), None, def():
                        setTimeout(change_password, 0)
                        close_modal()
                    ), '\xa0',
                    create_button(_('Close'), None, close_modal),
                )
            )
    )
# }}}



def init(container_id):
    update_window_title()
    container = document.getElementById(container_id)
    container.classList.add(CLASS_NAME)
    create_top_bar(container, run_animation=True)
    interface_data = get_interface_data()
    if interface_data.username:
        add_button(container, 'user', show_user_details, _('Logged in as {}').format(interface_data.username))

    # Recent books
    recent = E.div(style='display:none', class_='recently-read')
    recent_container_id = ensure_id(recent)
    container.appendChild(recent)
    conditional_timeout(recent_container_id, 5, show_recent)

    # Choose library
    container.appendChild(E.h2(_('Choose the calibre library to browse…')))
    container.appendChild(E.div(style='display: flex; flex-wrap: wrap'))
    cl = container.lastChild
    for library_id, library_name in all_libraries():
        library_name = interface_data.library_map[library_id]
        if library_name:
            cl.appendChild(
                create_button(library_name, icon='library', action=def(ev):
                    lib_id = ev.currentTarget.dataset.lid
                    q = {'library_id': lib_id}
                    vlid = last_virtual_library_for(lib_id)
                    if vlid:
                        q.vl = vlid
                    show_panel('book_list', q)
            ))
            cl.lastChild.style.margin = '1ex 1rem'
            cl.lastChild.dataset.lid = library_id

set_default_panel_handler(init)
