# 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 read_book.globals import dark_link_color, runtime
from session import session_defaults

opts = {}


def update_settings(settings):
    settings = Object.assign({}, session_defaults(), settings)
    opts.base_font_size = max(8, min(settings.base_font_size, 64))
    opts.color_scheme = settings.color_scheme
    opts.columns_per_screen = settings.columns_per_screen
    opts.cover_preserve_aspect_ratio = v'!!settings.cover_preserve_aspect_ratio'
    opts.hide_tooltips = settings.hide_tooltips
    opts.is_dark_theme = v'!!settings.is_dark_theme'
    opts.lines_per_sec_auto = settings.lines_per_sec_auto
    opts.lines_per_sec_smooth = settings.lines_per_sec_smooth
    opts.margin_left = max(0, settings.margin_left)
    opts.margin_right = max(0, settings.margin_right)
    opts.margin_top = max(0, settings.margin_top)
    opts.margin_bottom = max(0, settings.margin_bottom)
    opts.override_book_colors = settings.override_book_colors
    opts.paged_wheel_scrolls_by_screen = v'!!settings.paged_wheel_scrolls_by_screen'
    opts.paged_wheel_section_jumps = v'!!settings.paged_wheel_section_jumps'
    opts.paged_pixel_scroll_threshold = settings.paged_pixel_scroll_threshold
    opts.scroll_auto_boundary_delay = settings.scroll_auto_boundary_delay
    opts.scroll_mouse_boundary_delay = settings.scroll_mouse_boundary_delay
    opts.scroll_stop_boundaries = v'!!settings.scroll_stop_boundaries'
    opts.reverse_page_turn_zones = v'!!settings.reverse_page_turn_zones'
    opts.user_stylesheet = settings.user_stylesheet
    opts.gesture_overrides = settings.gesture_overrides

update_settings()


def apply_font_size():
    if not runtime.is_standalone_viewer:
        document.documentElement.style.fontSize = '{}px'.format(opts.base_font_size)


def default_selection_colors():
    if opts.is_dark_theme:
        return dark_link_color, '#111'
    return '#3297FD', '#fff'


def make_selection_background_opaque(selbg):
    # see https://stackoverflow.com/questions/7224445/css3-selection-behaves-differently-in-ff-chrome
    if selbg and selbg.startsWith('#') and len(selbg) is 7:
        selbg += 'fe'
    return selbg


styles_id = 'calibre-color-scheme-style-overrides'


def apply_colors(is_content_popup):
    des = document.documentElement.style
    des.setProperty('--calibre-viewer-background-color', opts.color_scheme.background)
    des.setProperty('--calibre-viewer-foreground-color', opts.color_scheme.foreground)
    des.colorScheme = 'dark' if opts.is_dark_theme else 'light'
    if opts.color_scheme.link:
        des.setProperty('--calibre-viewer-link-color', opts.color_scheme.link)
    for elem in (document.documentElement, document.body):
        elem.style.color = opts.color_scheme.foreground
        # set background color to transparent so that the users background
        # color which is set on the iframe is used instead
        elem.style.backgroundColor = 'transparent'
    des.backgroundColor = 'transparent'
    ss = document.getElementById('calibre-color-scheme-style-overrides')
    if not ss:
        ss = E.style(id=styles_id, type='text/css')
        document.documentElement.appendChild(ss)
    text = ''
    if runtime.is_standalone_viewer and 'macos' in window.navigator.userAgent:
        # Change the hyphenate character to a plain ASCII minus (U+002d) the default
        # is U+2010 but that does not render with the default Times font on macOS as of Monterey
        # and Qt 15.5 See https://bugs.launchpad.net/bugs/1951467 and can be easily reproduced
        # by converting a plain text file with the --pdf-hyphenate option
        # https://bugs.chromium.org/p/chromium/issues/detail?id=1267606 (fix released Feb 1 2022 v98)
        # See also pdf-preprint.js
        text += '\n* { -webkit-hyphenate-character: "-" !important }\n'
    if opts.override_book_colors is not 'never':
        text = 'body'
        if opts.override_book_colors is 'dark':
            text += '.calibre-viewer-dark-colors'
        text += f'''
        * {{
            color: {opts.color_scheme.foreground} !important; /**/
            background-color: {opts.color_scheme.background} !important; /**/
            border-color: {opts.color_scheme.foreground} !important; /**/
        }}'''
    if opts.color_scheme.link:
        c = opts.color_scheme.link
        # we use the html > body form so that these selectors have higher
        # priority than the override all selectors above
        text += f'\nhtml > body :link, html > body :link * {{ color: {c} !important }} html > body :visited, html > body :visited * {{ color: {c} !important }}'

    selbg, selfg = default_selection_colors()
    selbg = make_selection_background_opaque(selbg)
    text += f'\n::selection {{ background-color: {selbg}; color: {selfg} }}'
    text += f'\n::selection:window-inactive {{ background-color: {selbg}; color: {selfg} }}'
    if not is_content_popup:
        # In Chrome when content overflows in RTL and vertical layouts on the left side,
        # it is not displayed properly when scrolling unless overflow:visible is set,
        # but this causes scrollbars to appear.
        # Force disable scrollbars in Chrome, Safari, and Firefox to address this side effect.
        text += '\nhtml::-webkit-scrollbar, body::-webkit-scrollbar { display: none !important }'
        # for firefox: https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-width
        text += '\nhtml, body { scrollbar-width: none !important }'

        # show a dot after highlights that have notes
        text += '''\n\n
        .crw-has-dot::after {
            content: "";\
            vertical-align: text-top;\
            background-color: currentColor !important;\
            text-decoration: none !important;\
            display: inline-block;\
            height: 0.7ex;\
            width: 0.7ex;\
            border-radius: 50%;\
        }
        '''
    hints_box_css = f'''
            display: inline-block !important;\
            position: absolute !important;\
            text-indent: 0 !important;\
            text-decoration: none !important;\
            font-weight: bold !important;\
            color: {selfg} !important;\
            background: {selbg} !important;\
            cursor: default !important;\
            padding: 1px !important;\
            border: solid 1px {opts.color_scheme.foreground} !important;\
    '''

    # reference mode hint box
    text += f'''\n\n
        .calibre-reference-mode [data-calibre-ref-num]::before {{
            content: attr(data-calibre-ref-num) !important;\
            {hints_box_css}
        }}
    '''

    # follow links hint box
    text += f'''\n\n
        .calibre-hint-visible::before {{
            content: attr(data-calibre-hint-render) !important;\
            {hints_box_css}
        }}

        .calibre-hint-enter::before {{
            background: #FF5733 !important; \
        }}

        .calibre-animated-hint {{
            animation-name: calibre-animate-hint; \
            animation-duration: 0.3s; \
            animation-timing-function: ease-out; \
            display: inline-block !important; \
            text-indent: 0 !important; \
        }}
        @keyframes calibre-animate-hint {{
            from {{ transform: scale(1); }}
            to {{ transform: scale(2); }}
        }}
    '''
    ss.textContent = text


def set_selection_style(style):
    if not style:
        selbg, selfg = default_selection_colors()
        style = {'color': selfg, 'background-color': selbg}
    sheet = document.getElementById(styles_id)
    if not sheet:
        return
    css_text = ''
    if style.selbg:
        style.selbg = make_selection_background_opaque(style.selbg)
    for prop in Object.keys(style):
        css_text += f'{prop}: {style[prop]}; '
    for rule in sheet.sheet.cssRules:
        if rule.type is rule.STYLE_RULE and rule.selectorText.indexOf('selection') > -1:
            rule.style.cssText = css_text


def set_color_scheme_class():
    document.documentElement.classList.add('is-calibre-viewer')
    if opts.is_dark_theme:
        document.body.classList.add('calibre-viewer-dark-colors')
        document.body.classList.remove('calibre-viewer-light-colors')
    else:
        document.body.classList.add('calibre-viewer-light-colors')
        document.body.classList.remove('calibre-viewer-dark-colors')


def apply_stylesheet():
    sid = 'calibre-browser-viewer-user-stylesheet'
    style = document.getElementById(sid)
    if not style:
        if not opts.user_stylesheet:
            return
        style = E.style(type='text/css', id=sid)
        document.documentElement.appendChild(style)
    style.textContent = opts.user_stylesheet


def apply_settings(is_content_popup):
    apply_font_size()
    apply_colors(is_content_popup)
    apply_stylesheet()
