__filename__ = "webapp_column_left.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
__version__ = "1.5.0"
__maintainer__ = "Bob Mottram"
__email__ = "bob@libreserver.org"
__status__ = "Production"
__module_group__ = "Web Interface Columns"

import os
from utils import get_config_param
from utils import get_nickname_from_actor
from utils import is_editor
from utils import is_artist
from utils import remove_domain_port
from utils import local_actor_url
from webapp_utils import shares_timeline_json
from webapp_utils import html_post_separator
from webapp_utils import get_left_image_file
from webapp_utils import header_buttons_front_screen
from webapp_utils import html_header_with_external_style
from webapp_utils import html_footer
from webapp_utils import get_banner_file
from webapp_utils import edit_text_field
from shares import share_category_icon


def _links_exist(base_dir: str) -> bool:
    """Returns true if links have been created
    """
    links_filename = base_dir + '/accounts/links.txt'
    return os.path.isfile(links_filename)


def _get_left_column_shares(base_dir: str,
                            http_prefix: str, domain: str, domain_full: str,
                            nickname: str,
                            max_shares_in_left_column: int,
                            translate: {},
                            shared_items_federated_domains: []) -> []:
    """get any shares and turn them into the left column links format
    """
    page_number = 1
    actor = local_actor_url(http_prefix, nickname, domain_full)
    # NOTE: this could potentially be slow if the number of federated
    # shared items is large
    shares_json, _ = \
        shares_timeline_json(actor, page_number, max_shares_in_left_column,
                             base_dir, domain, nickname,
                             max_shares_in_left_column,
                             shared_items_federated_domains, 'shares')
    if not shares_json:
        return []

    links_list = []
    ctr = 0
    for _, item in shares_json.items():
        sharedesc = item['displayName']
        if '<' in sharedesc or '?' in sharedesc:
            continue
        share_id = item['shareId']
        # selecting this link calls html_show_share
        share_link = actor + '?showshare=' + share_id
        if item.get('category'):
            share_link += '?category=' + item['category']
            share_category = share_category_icon(item['category'])

        links_list.append(share_category + sharedesc + ' ' + share_link)
        ctr += 1
        if ctr >= max_shares_in_left_column:
            break

    if links_list:
        links_list = ['* ' + translate['Shares']] + links_list
    return links_list


def _get_left_column_wanted(base_dir: str,
                            http_prefix: str, domain: str, domain_full: str,
                            nickname: str,
                            max_shares_in_left_column: int,
                            translate: {},
                            shared_items_federated_domains: []) -> []:
    """get any wanted items and turn them into the left column links format
    """
    page_number = 1
    actor = local_actor_url(http_prefix, nickname, domain_full)
    # NOTE: this could potentially be slow if the number of federated
    # wanted items is large
    shares_json, _ = \
        shares_timeline_json(actor, page_number, max_shares_in_left_column,
                             base_dir, domain, nickname,
                             max_shares_in_left_column,
                             shared_items_federated_domains, 'wanted')
    if not shares_json:
        return []

    links_list = []
    ctr = 0
    for _, item in shares_json.items():
        sharedesc = item['displayName']
        if '<' in sharedesc or ';' in sharedesc:
            continue
        share_id = item['shareId']
        # selecting this link calls html_show_share
        share_link = actor + '?showwanted=' + share_id
        links_list.append(sharedesc + ' ' + share_link)
        ctr += 1
        if ctr >= max_shares_in_left_column:
            break

    if links_list:
        links_list = ['* ' + translate['Wanted']] + links_list
    return links_list


def get_left_column_content(base_dir: str, nickname: str, domain_full: str,
                            http_prefix: str, translate: {},
                            editor: bool, artist: bool,
                            show_back_button: bool, timeline_path: str,
                            rss_icon_at_top: bool, show_header_image: bool,
                            front_page: bool, theme: str,
                            access_keys: {},
                            shared_items_federated_domains: []) -> str:
    """Returns html content for the left column
    """
    html_str = ''

    separator_str = html_post_separator(base_dir, 'left')
    domain = remove_domain_port(domain_full)

    edit_image_class = ''
    if show_header_image:
        left_image_file, left_column_image_filename = \
            get_left_image_file(base_dir, nickname, domain, theme)

        # show the image at the top of the column
        edit_image_class = 'leftColEdit'
        if os.path.isfile(left_column_image_filename):
            edit_image_class = 'leftColEditImage'
            html_str += \
                '\n      <center>\n        <img class="leftColImg" ' + \
                'alt="" loading="lazy" decoding="async" src="/users/' + \
                nickname + '/' + left_image_file + '" />\n' + \
                '      </center>\n'

    if show_back_button:
        html_str += \
            '      <div>      <a href="' + timeline_path + '">' + \
            '<button class="cancelbtn">' + \
            translate['Go Back'] + '</button></a>\n'

    if (editor or rss_icon_at_top) and not show_header_image:
        html_str += '<div class="columnIcons">'

    if edit_image_class == 'leftColEdit':
        html_str += '\n      <center>\n'

    html_str += '      <div class="leftColIcons">\n'

    if editor:
        # show the edit icon
        html_str += \
            '      <a href="/users/' + nickname + '/editlinks" ' + \
            'accesskey="' + access_keys['menuEdit'] + '" tabindex="5" ' + \
            'class="imageAnchor">' + \
            '<img class="' + edit_image_class + \
            '" loading="lazy" decoding="async" alt="' + \
            translate['Edit Links'] + ' | " title="' + \
            translate['Edit Links'] + '" src="/icons/edit.png" /></a>\n'

    if artist:
        # show the theme designer icon
        html_str += \
            '      <a href="/users/' + nickname + '/themedesigner" ' + \
            'accesskey="' + access_keys['menuThemeDesigner'] + \
            '" tabindex="5" class="imageAnchor">' + \
            '<img class="' + edit_image_class + \
            '" loading="lazy" decoding="async" alt="' + \
            translate['Theme Designer'] + ' | " title="' + \
            translate['Theme Designer'] + '" src="/icons/theme.png" /></a>\n'

    # RSS icon
    if nickname != 'news':
        # rss feed for this account
        rss_url = http_prefix + '://' + domain_full + \
            '/blog/' + nickname + '/rss.xml'
    else:
        # rss feed for all accounts on the instance
        rss_url = http_prefix + '://' + domain_full + '/blog/rss.xml'
    if not front_page:
        rss_title = translate['RSS feed for your blog']
    else:
        rss_title = translate['RSS feed for this site']
    rss_icon_str = \
        '      <a href="' + rss_url + '" tabindex="5" class="imageAnchor">' + \
        '<img class="' + edit_image_class + \
        '" loading="lazy" decoding="async" alt="' + \
        rss_title + '" title="' + rss_title + \
        '" src="/icons/logorss.png" /></a>\n'
    if rss_icon_at_top:
        html_str += rss_icon_str
    html_str += '      </div>\n'

    if edit_image_class == 'leftColEdit':
        html_str += '      </center>\n'

    if (editor or rss_icon_at_top) and not show_header_image:
        html_str += '</div><br>'

    # if show_header_image:
    #     html_str += '<br>'

    # flag used not to show the first separator
    first_separator_added = False

    links_filename = base_dir + '/accounts/links.txt'
    links_file_contains_entries = False
    links_list = None
    if os.path.isfile(links_filename):
        with open(links_filename, 'r', encoding='utf-8') as fp_links:
            links_list = fp_links.readlines()

    if not front_page:
        # show a number of shares
        max_shares_in_left_column = 3
        shares_list = \
            _get_left_column_shares(base_dir,
                                    http_prefix, domain, domain_full, nickname,
                                    max_shares_in_left_column, translate,
                                    shared_items_federated_domains)
        if links_list and shares_list:
            links_list = shares_list + links_list

        wanted_list = \
            _get_left_column_wanted(base_dir,
                                    http_prefix, domain, domain_full, nickname,
                                    max_shares_in_left_column, translate,
                                    shared_items_federated_domains)
        if links_list and wanted_list:
            links_list = wanted_list + links_list

    new_tab_str = ' target="_blank" rel="nofollow noopener noreferrer"'
    if links_list:
        html_str += '<nav itemscope itemtype="http://schema.org/Collection">\n'
        for line_str in links_list:
            if ' ' not in line_str:
                if '#' not in line_str:
                    if '*' not in line_str:
                        if not line_str.startswith('['):
                            if not line_str.startswith('=> '):
                                continue
            line_str = line_str.strip()
            link_str = None
            if not line_str.startswith('['):
                words = line_str.split(' ')
                # get the link
                for word in words:
                    if word == '#':
                        continue
                    if word == '*':
                        continue
                    if word == '=>':
                        continue
                    if '://' in word:
                        link_str = word
                        break
            else:
                # markdown link
                if ']' not in line_str:
                    continue
                if '(' not in line_str:
                    continue
                if ')' not in line_str:
                    continue
                link_str = line_str.split('(')[1]
                if ')' not in link_str:
                    continue
                link_str = link_str.split(')')[0]
                if '://' not in link_str:
                    continue
                line_str = line_str.split('[')[1]
                if ']' not in line_str:
                    continue
                line_str = line_str.split(']')[0]
            if link_str:
                line_str = line_str.replace(link_str, '').strip()
                # avoid any dubious scripts being added
                if '<' not in line_str:
                    # remove trailing comma if present
                    if line_str.endswith(','):
                        line_str = line_str[:len(line_str)-1]
                    # add link to the returned html
                    if '?showshare=' not in link_str and \
                       '?showwarning=' not in link_str:
                        html_str += \
                            '      <p><a href="' + link_str + \
                            '"' + new_tab_str + '>' + \
                            line_str + '</a></p>\n'
                    else:
                        html_str += \
                            '      <p><a href="' + link_str + \
                            '">' + line_str + '</a></p>\n'
                    links_file_contains_entries = True
                elif line_str.startswith('=> '):
                    # gemini style link
                    line_str = line_str.replace('=> ', '')
                    line_str = line_str.replace(link_str, '')
                    # add link to the returned html
                    if '?showshare=' not in link_str and \
                       '?showwarning=' not in link_str:
                        html_str += \
                            '      <p><a href="' + link_str + \
                            '"' + new_tab_str + '>' + \
                            line_str.strip() + '</a></p>\n'
                    else:
                        html_str += \
                            '      <p><a href="' + link_str + \
                            '">' + line_str.strip() + '</a></p>\n'
                    links_file_contains_entries = True
            else:
                if line_str.startswith('#') or line_str.startswith('*'):
                    line_str = line_str[1:].strip()
                    if first_separator_added:
                        html_str += separator_str
                    first_separator_added = True
                    html_str += \
                        '      <h3 class="linksHeader">' + \
                        line_str + '</h3>\n'
                else:
                    html_str += \
                        '      <p>' + line_str + '</p>\n'
                links_file_contains_entries = True
        html_str += '</nav>\n'

    if first_separator_added:
        html_str += separator_str
    html_str += \
        '<p class="login-text"><a href="/users/' + nickname + \
        '/catalog.csv">' + translate['Shares Catalog'] + '</a></p>'
    html_str += \
        '<p class="login-text"><a href="/users/' + \
        nickname + '/accesskeys" accesskey="' + \
        access_keys['menuKeys'] + '">' + \
        translate['Key Shortcuts'] + '</a></p>'
    html_str += \
        '<p class="login-text"><a href="/about">' + \
        translate['About this Instance'] + '</a></p>'
    html_str += \
        '<p class="login-text"><a href="/manual">' + \
        translate['User Manual'] + '</a></p>'
    html_str += \
        '<p class="login-text"><a href="/activitypub">' + \
        translate['ActivityPub Specification'] + '</a></p>'
    html_str += \
        '<p class="login-text"><a href="/terms">' + \
        translate['Terms of Service'] + '</a></p>'

    if links_file_contains_entries and not rss_icon_at_top:
        html_str += '<br><div class="columnIcons">' + rss_icon_str + '</div>'

    return html_str


def html_links_mobile(base_dir: str,
                      nickname: str, domain_full: str,
                      http_prefix: str, translate,
                      timeline_path: str, authorized: bool,
                      rss_icon_at_top: bool,
                      icons_as_buttons: bool,
                      default_timeline: str,
                      theme: str, access_keys: {},
                      shared_items_federated_domains: []) -> str:
    """Show the left column links within mobile view
    """
    html_str = ''

    # the css filename
    css_filename = base_dir + '/epicyon-profile.css'
    if os.path.isfile(base_dir + '/epicyon.css'):
        css_filename = base_dir + '/epicyon.css'

    # is the user a site editor?
    if nickname == 'news':
        editor = False
        artist = False
    else:
        editor = is_editor(base_dir, nickname)
        artist = is_artist(base_dir, nickname)

    domain = remove_domain_port(domain_full)

    instance_title = \
        get_config_param(base_dir, 'instanceTitle')
    html_str = \
        html_header_with_external_style(css_filename, instance_title, None)
    banner_file, _ = \
        get_banner_file(base_dir, nickname, domain, theme)
    html_str += \
        '<a href="/users/' + nickname + '/' + default_timeline + '" ' + \
        'accesskey="' + access_keys['menuTimeline'] + '">' + \
        '<img loading="lazy" decoding="async" class="timeline-banner" ' + \
        'alt="' + translate['Switch to timeline view'] + '" ' + \
        'src="/users/' + nickname + '/' + banner_file + '" /></a>\n'

    html_str += '<div class="col-left-mobile">\n'
    html_str += '<center>' + \
        header_buttons_front_screen(translate, nickname,
                                    'links', authorized,
                                    icons_as_buttons) + '</center>'
    html_str += \
        get_left_column_content(base_dir, nickname, domain_full,
                                http_prefix, translate,
                                editor, artist,
                                False, timeline_path,
                                rss_icon_at_top, False, False,
                                theme, access_keys,
                                shared_items_federated_domains)
    if editor and not _links_exist(base_dir):
        html_str += '<br><br><br>\n<center>\n  '
        html_str += translate['Select the edit icon to add web links']
        html_str += '\n</center>\n'

    # end of col-left-mobile
    html_str += '</div>\n'

    html_str += '</div>\n' + html_footer()
    return html_str


def html_edit_links(translate: {}, base_dir: str, path: str,
                    domain: str,
                    default_timeline: str, theme: str,
                    access_keys: {}) -> str:
    """Shows the edit links screen
    """
    if '/users/' not in path:
        return ''
    path = path.replace('/inbox', '').replace('/outbox', '')
    path = path.replace('/shares', '').replace('/wanted', '')

    nickname = get_nickname_from_actor(path)
    if not nickname:
        return ''

    # is the user a moderator?
    if not is_editor(base_dir, nickname):
        return ''

    css_filename = base_dir + '/epicyon-links.css'
    if os.path.isfile(base_dir + '/links.css'):
        css_filename = base_dir + '/links.css'

    # filename of the banner shown at the top
    banner_file, _ = \
        get_banner_file(base_dir, nickname, domain, theme)

    instance_title = \
        get_config_param(base_dir, 'instanceTitle')
    edit_links_form = \
        html_header_with_external_style(css_filename, instance_title, None)

    # top banner
    edit_links_form += \
        '<header>\n' + \
        '<a href="/users/' + nickname + '/' + default_timeline + \
        '" title="' + \
        translate['Switch to timeline view'] + '" alt="' + \
        translate['Switch to timeline view'] + '" ' + \
        'accesskey="' + access_keys['menuTimeline'] + '">\n'
    edit_links_form += \
        '<img loading="lazy" decoding="async" class="timeline-banner" ' + \
        'alt = "" src="' + \
        '/users/' + nickname + '/' + banner_file + '" /></a>\n' + \
        '</header>\n'

    edit_links_form += \
        '<form enctype="multipart/form-data" method="POST" ' + \
        'accept-charset="UTF-8" action="' + path + '/linksdata">\n'
    edit_links_form += \
        '  <div class="vertical-center">\n'
    edit_links_form += \
        '    <div class="containerSubmitNewPost">\n'
    edit_links_form += \
        '      <h1>' + translate['Edit Links'] + '</h1>'
    edit_links_form += \
        '      <input type="submit" name="submitLinks" value="' + \
        translate['Publish'] + '" ' + \
        'accesskey="' + access_keys['submitButton'] + '">\n'
    edit_links_form += \
        '    </div>\n'

    links_filename = base_dir + '/accounts/links.txt'
    links_str = ''
    if os.path.isfile(links_filename):
        with open(links_filename, 'r', encoding='utf-8') as fp_links:
            links_str = fp_links.read()

    edit_links_form += \
        '<div class="container">'
    edit_links_form += \
        '  ' + \
        translate['One link per line. Description followed by the link.'] + \
        '<br>'
    new_col_link_str = translate['New link title and URL']
    edit_links_form += \
        edit_text_field(None, 'newColLink', '', new_col_link_str)
    edit_links_form += \
        '  <textarea id="message" name="editedLinks" ' + \
        'style="height:80vh" spellcheck="false">' + links_str + '</textarea>'
    edit_links_form += \
        '</div>'

    # the admin can edit terms of service, about and specification text
    admin_nickname = get_config_param(base_dir, 'admin')
    if admin_nickname:
        if nickname == admin_nickname:
            about_filename = base_dir + '/accounts/about.md'
            about_str = ''
            if os.path.isfile(about_filename):
                with open(about_filename, 'r', encoding='utf-8') as fp_about:
                    about_str = fp_about.read()

            edit_links_form += \
                '<div class="container">'
            edit_links_form += \
                '  ' + \
                translate['About this Instance'] + \
                '<br>'
            edit_links_form += \
                '  <textarea id="message" name="editedAbout" ' + \
                'style="height:100vh" spellcheck="true" autocomplete="on">' + \
                about_str + '</textarea>'
            edit_links_form += \
                '</div>'

            tos_filename = base_dir + '/accounts/tos.md'
            tos_str = ''
            if os.path.isfile(tos_filename):
                with open(tos_filename, 'r', encoding='utf-8') as fp_tos:
                    tos_str = fp_tos.read()

            edit_links_form += \
                '<div class="container">'
            edit_links_form += \
                '  ' + \
                translate['Terms of Service'] + \
                '<br>'
            edit_links_form += \
                '  <textarea id="message" name="editedTOS" ' + \
                'style="height:100vh" spellcheck="true" autocomplete="on">' + \
                tos_str + '</textarea>'
            edit_links_form += \
                '</div>'

            specification_filename = base_dir + '/accounts/activitypub.md'
            specification_str = ''
            if os.path.isfile(specification_filename):
                with open(specification_filename, 'r',
                          encoding='utf-8') as fp_specification:
                    specification_str = fp_specification.read()

            edit_links_form += \
                '<div class="container">'
            edit_links_form += \
                '  ' + \
                translate['ActivityPub Specification'] + \
                '<br>'
            edit_links_form += \
                '  <textarea id="message" name="editedSpecification" ' + \
                'style="height:1000vh" spellcheck="true" ' + \
                'autocomplete="on">' + specification_str + '</textarea>'
            edit_links_form += \
                '</div>'

    edit_links_form += html_footer()
    return edit_links_form