# 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 ajax import ajax_send_file
from book_list.library_data import force_refresh_on_next_load, loaded_books_query
from book_list.router import back
from book_list.theme import get_color
from book_list.top_bar import create_top_bar
from book_list.ui import query_as_href, show_panel
from dom import add_extra_css, build_rule, clear, ensure_id
from file_uploads import (
    update_status_widget, upload_files_widget, upload_status_widget
)
from session import get_interface_data
from utils import safe_set_inner_html
from widgets import create_button, enable_escape_key

state = {
    'in_progress': False,
    'container_id': None,
    'counter': 0,
    'number': 0,
    'fake_send': False,
    'transfers': [],
}


add_extra_css(def ():
    panel = '.cs-add-books'
    sel = panel + ' '
    s = ''
    s += build_rule(panel,
        display='flex',
        flex_direction='column',
        min_height='0',
        flex='1 1 auto',
    )
    s += build_rule('.cs-upload-dropzone',
        box_sizing='border-box',
        min_height='10rem',
        padding='1.1rem 1rem',
        border='var(--calibre-border-style-subtle)',
        border_radius='14px',
        background_color='var(--calibre-color-primary-light)',
        color='inherit',
        transition='background-color 160ms ease, border-color 160ms ease, box-shadow 160ms ease',
    )
    s += build_rule(sel + '.cs-upload-dropzone',
        min_height='min(72vh, 520px)',
        padding='2rem 1.5rem',
        margin='0.75rem 1rem 0.5rem 1rem',
        border='2px dashed var(--calibre-color-border)',
        border_radius='18px',
        display='flex',
        flex_direction='column',
        align_items='center',
        justify_content='center',
        cursor='pointer',
        box_shadow='0 1px 2px rgba(0,0,0,0.04)',
    )
    s += build_rule(sel + '.cs-upload-dropzone:hover',
        background_color='var(--calibre-color-primary-light-2)',
        border_color='var(--calibre-color-primary)',
        box_shadow='0 4px 18px rgba(0,0,0,0.08)',
    )
    s += build_rule('.cs-upload-dropzone-msg',
        display='block',
        max_width='28rem',
        margin='0',
        text_align='center',
        font_size='1.02rem',
        line_height='1.55',
        opacity='0.92',
    )
    s += build_rule(sel + '.cs-upload-dropzone-msg',
        font_size='1.06rem',
        line_height='1.6',
    )
    s += build_rule('.cs-upload-dropzone-msg a.blue-link',
        font_weight='600',
        text_decoration='underline',
        text_underline_offset='3px',
    )
    s += build_rule('.cs-upload-job',
        margin='0 0 0.65rem 0',
        padding='1.1rem 1.2rem',
        box_sizing='border-box',
        border='var(--calibre-border-style-subtle)',
        border_radius='14px',
        background_color=get_color('window-background'),
        box_shadow='0 2px 8px rgba(0,0,0,0.06)',
    )
    s += build_rule(sel + '.cs-upload-job',
        margin_left='1rem',
        margin_right='1rem',
    )
    s += build_rule('.cs-upload-job-title',
        margin='0 0 0.75rem 0',
        font_size='1.02rem',
        font_weight='700',
        line_height='1.35',
        word_break='break-word',
    )
    s += build_rule('.cs-upload-progress',
        width='100%',
        height='0.5rem',
        border_radius='999px',
        overflow='hidden',
        border='none',
        background_color='rgba(0,0,0,0.08)',
        accent_color='var(--calibre-color-primary)',
    )
    s += build_rule('.cs-upload-progress-label',
        display='block',
        margin_top='0.55rem',
        font_size='0.88rem',
        opacity='0.8',
    )
    s += build_rule(sel + '.cs-add-books-done-msg',
        display='inline',
        margin_right='0.35rem',
        font_size='0.95rem',
        opacity='0.88',
    )
    s += build_rule(sel + '.cs-add-books-dup-list',
        margin_top='0.45rem',
    )
    s += build_rule(sel + '.cs-add-books-dup-hint',
        padding='0.35rem 0',
        line_height='1.5',
        opacity='0.9',
    )
    s += build_rule(sel + '.cs-add-books-dup-detail',
        margin_top='0.85rem',
        padding_top='0.85rem',
        border_top='var(--calibre-border-style-subtle)',
        font_size='0.95rem',
        line_height='1.5',
        opacity='0.88',
    )
    s += build_rule(sel + '.cs-add-books-dup-detail ol',
        margin='0.5rem 0 0 0',
        padding_left='1.25rem',
    )
    s += build_rule(sel + '.cs-add-books-error',
        padding='0.5rem 0 0 0',
        font_size='0.95rem',
        line_height='1.55',
        color='inherit',
    )
    s += r'''
@media (max-width: 520px) {
  .cs-add-books .cs-upload-dropzone { min-height: 56vh; padding: 1.35rem 1rem; margin-left: 0.65rem; margin-right: 0.65rem; }
  .cs-add-books .cs-upload-job { margin-left: 0.65rem; margin-right: 0.65rem; }
}
'''
    return s
)


def cancel_in_progress():
    for xhr in state.transfers:
        xhr.abort()
    state.transfers = []
    state.in_progress = False


def on_close():
    cancel_in_progress()
    back()


def get_job_container(container_id, job_id):
    container = document.getElementById(container_id)
    if not container:
        return
    return container.querySelector(f'[data-job="{job_id}"]')


def on_progress(container_id, job_id, loaded, total, xhr):
    container = get_job_container(container_id, job_id)
    if not container:
        return
    if total:
        update_status_widget(container, loaded, total)


def list_added_book(container, data):
    container.appendChild(E.h3(
        E.b(data.title),
        E.span(' ' + _('by') + ' '),
        E.i(' & '.join(data.authors)),
        class_='cs-upload-job-title',
    ))
    done_msg = _('Added successfully') + ' '
    container.appendChild(E.span(done_msg, class_='cs-add-books-done-msg'))
    q = {'book_id': data.book_id + ''}
    a = create_button(_('Open'), action=query_as_href(q, 'book_details'))
    if state.number > 1:
        a.setAttribute('target', '_blank')
    else:
        a.addEventListener('click', def (e):
            e.preventDefault()
            show_panel('book_details', {'book_id': data.book_id + ''}, True)
        )
    container.appendChild(a)


def list_duplicate_book(container, container_id, job_id, data, file):
    container.appendChild(E.div(
        _('A book with the title "{0}" already exists in the library.').format(data.title),
        class_='cs-add-books-dup-hint',
    ))
    b = create_button(_('Add anyway'), action=def ():
        c = get_job_container(container_id, job_id)
        clear(c)
        w = upload_status_widget(file.name, job_id)
        c.appendChild(w)
        send_file(file, container_id, job_id, True)
    )

    def list_duplicates():
        ans = E.ol(class_='cs-add-books-dup-ol')
        for item in data.duplicates:
            ans.appendChild(E.li(_('{0} by {1}').format(item.title, ' & '.join(item.authors))))
        return ans

    container.appendChild(b)
    container.appendChild(E.div(
        class_='cs-add-books-dup-detail',
        _('The book you are trying to add is:'),
        E.span(' ', E.b(data.title), ' ', _('by'), ' ', E.i(' & '.join(data.authors))),
        _('. Books already in the library with that title are:'),
        E.div(class_='cs-add-books-dup-list', list_duplicates())
    ))


def write_access_error(msg, xhr):
    html = msg + '<br>'
    if xhr.status is 403:
        un = get_interface_data().username
        if un:
            html += _('You are not allowed to make changes to the library') + '<hr>'
        else:
            html += _('You must be logged in to make changes to the library') + '<hr>'
    return html + '<br>' + xhr.error_html


def on_complete(container_id, job_id, end_type, xhr, ev):
    idx = state.transfers.indexOf(xhr)
    if idx > -1:
        state.transfers.splice(idx, 1)
    container = get_job_container(container_id, job_id)
    if not container:
        return
    clear(container)
    if end_type is 'load':
        data = JSON.parse(xhr.responseText)
        if data.book_id:
            list_added_book(container, data)
            force_refresh_on_next_load()
        else:
            list_duplicate_book(container, container_id, job_id, data, this)
    elif end_type is 'abort':
        return
    else:
        html = write_access_error(_('Failed to upload the file: {}').format(this.name), xhr)
        safe_set_inner_html(container, '<div class="cs-add-books-error">' + html + '</div>')


def fake_send(container_id, job_id):
    container = get_job_container(container_id, job_id)
    prev = parseInt(container.dataset.fake or '0')
    container.dataset.fake = prev + 10
    update_status_widget(container, container.dataset.fake, 100)
    if parseInt(container.dataset.fake or '0') < 100:
        setTimeout(fake_send.bind(None, container_id, job_id), 1000)


def send_file(file, container_id, job_id, add_duplicates):
    lid = loaded_books_query().library_id
    ad = 'y' if add_duplicates else 'n'
    xhr = ajax_send_file(
        f'cdb/add-book/{job_id}/{ad}/{encodeURIComponent(file.name)}/{lid}',
        file, on_complete.bind(file, container_id, job_id), on_progress.bind(None, container_id, job_id))
    state.transfers.push(xhr)
    return xhr


def files_chosen(container_id, files):
    container = document.getElementById(container_id)
    if not container:
        return
    state.number = 0
    for file in files:
        state.counter += 1
        state.number += 1
        job_id = state.counter
        w = upload_status_widget(file.name, job_id)
        container.appendChild(w)
        if state.fake_send:
            setTimeout(fake_send.bind(None, container_id, job_id), 100)
        else:
            send_file(file, container_id, job_id)


def add_books_panel(container_id):
    container = document.getElementById(container_id)
    container.classList.add('cs-add-books')
    create_top_bar(container, title=_('Add books'), action=on_close, icon='close')
    cancel_in_progress()
    state.in_progress = True
    state.container_id = container_id
    state.fake_send = False
    enable_escape_key(container, on_close)
    return upload_files_widget(container, files_chosen)


def develop(container):
    add_books_panel(ensure_id(container))
