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

import os
from utils import getConfigParam
from utils import getNicknameFromActor
from utils import isEditor
from utils import isArtist
from utils import removeDomainPort
from utils import localActorUrl
from webapp_utils import sharesTimelineJson
from webapp_utils import htmlPostSeparator
from webapp_utils import getLeftImageFile
from webapp_utils import headerButtonsFrontScreen
from webapp_utils import htmlHeaderWithExternalStyle
from webapp_utils import htmlFooter
from webapp_utils import getBannerFile
from webapp_utils import editTextField
from shares import shareCategoryIcon


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


def _getLeftColumnShares(baseDir: str,
                         httpPrefix: str, domain: str, domainFull: str,
                         nickname: str,
                         maxSharesInLeftColumn: int,
                         translate: {},
                         sharedItemsFederatedDomains: []) -> []:
    """get any shares and turn them into the left column links format
    """
    pageNumber = 1
    actor = localActorUrl(httpPrefix, nickname, domainFull)
    # NOTE: this could potentially be slow if the number of federated
    # shared items is large
    sharesJson, lastPage = \
        sharesTimelineJson(actor, pageNumber, maxSharesInLeftColumn,
                           baseDir, domain, nickname, maxSharesInLeftColumn,
                           sharedItemsFederatedDomains, 'shares')
    if not sharesJson:
        return []

    linksList = []
    ctr = 0
    for published, item in sharesJson.items():
        sharedesc = item['displayName']
        if '<' in sharedesc or '?' in sharedesc:
            continue
        shareId = item['shareId']
        # selecting this link calls htmlShowShare
        shareLink = actor + '?showshare=' + shareId
        if item.get('category'):
            shareLink += '?category=' + item['category']
            shareCategory = shareCategoryIcon(item['category'])

        linksList.append(shareCategory + sharedesc + ' ' + shareLink)
        ctr += 1
        if ctr >= maxSharesInLeftColumn:
            break

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


def _getLeftColumnWanted(baseDir: str,
                         httpPrefix: str, domain: str, domainFull: str,
                         nickname: str,
                         maxSharesInLeftColumn: int,
                         translate: {},
                         sharedItemsFederatedDomains: []) -> []:
    """get any wanted items and turn them into the left column links format
    """
    pageNumber = 1
    actor = localActorUrl(httpPrefix, nickname, domainFull)
    # NOTE: this could potentially be slow if the number of federated
    # wanted items is large
    sharesJson, lastPage = \
        sharesTimelineJson(actor, pageNumber, maxSharesInLeftColumn,
                           baseDir, domain, nickname, maxSharesInLeftColumn,
                           sharedItemsFederatedDomains, 'wanted')
    if not sharesJson:
        return []

    linksList = []
    ctr = 0
    for published, item in sharesJson.items():
        sharedesc = item['displayName']
        if '<' in sharedesc or ';' in sharedesc:
            continue
        shareId = item['shareId']
        # selecting this link calls htmlShowShare
        shareLink = actor + '?showwanted=' + shareId
        linksList.append(sharedesc + ' ' + shareLink)
        ctr += 1
        if ctr >= maxSharesInLeftColumn:
            break

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


def getLeftColumnContent(baseDir: str, nickname: str, domainFull: str,
                         httpPrefix: str, translate: {},
                         editor: bool, artist: bool,
                         showBackButton: bool, timelinePath: str,
                         rssIconAtTop: bool, showHeaderImage: bool,
                         frontPage: bool, theme: str,
                         accessKeys: {},
                         sharedItemsFederatedDomains: []) -> str:
    """Returns html content for the left column
    """
    htmlStr = ''

    separatorStr = htmlPostSeparator(baseDir, 'left')
    domain = removeDomainPort(domainFull)

    editImageClass = ''
    if showHeaderImage:
        leftImageFile, leftColumnImageFilename = \
            getLeftImageFile(baseDir, nickname, domain, theme)

        # show the image at the top of the column
        editImageClass = 'leftColEdit'
        if os.path.isfile(leftColumnImageFilename):
            editImageClass = 'leftColEditImage'
            htmlStr += \
                '\n      <center>\n        <img class="leftColImg" ' + \
                'alt="" loading="lazy" src="/users/' + \
                nickname + '/' + leftImageFile + '" />\n' + \
                '      </center>\n'

    if showBackButton:
        htmlStr += \
            '      <div>      <a href="' + timelinePath + '">' + \
            '<button class="cancelbtn">' + \
            translate['Go Back'] + '</button></a>\n'

    if (editor or rssIconAtTop) and not showHeaderImage:
        htmlStr += '<div class="columnIcons">'

    if editImageClass == 'leftColEdit':
        htmlStr += '\n      <center>\n'

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

    if editor:
        # show the edit icon
        htmlStr += \
            '      <a href="/users/' + nickname + '/editlinks" ' + \
            'accesskey="' + accessKeys['menuEdit'] + '">' + \
            '<img class="' + editImageClass + '" loading="lazy" alt="' + \
            translate['Edit Links'] + ' | " title="' + \
            translate['Edit Links'] + '" src="/icons/edit.png" /></a>\n'

    if artist:
        # show the theme designer icon
        htmlStr += \
            '      <a href="/users/' + nickname + '/themedesigner" ' + \
            'accesskey="' + accessKeys['menuThemeDesigner'] + '">' + \
            '<img class="' + editImageClass + '" loading="lazy" alt="' + \
            translate['Theme Designer'] + ' | " title="' + \
            translate['Theme Designer'] + '" src="/icons/theme.png" /></a>\n'

    # RSS icon
    if nickname != 'news':
        # rss feed for this account
        rssUrl = httpPrefix + '://' + domainFull + \
            '/blog/' + nickname + '/rss.xml'
    else:
        # rss feed for all accounts on the instance
        rssUrl = httpPrefix + '://' + domainFull + '/blog/rss.xml'
    if not frontPage:
        rssTitle = translate['RSS feed for your blog']
    else:
        rssTitle = translate['RSS feed for this site']
    rssIconStr = \
        '      <a href="' + rssUrl + '"><img class="' + editImageClass + \
        '" loading="lazy" alt="' + rssTitle + '" title="' + rssTitle + \
        '" src="/icons/logorss.png" /></a>\n'
    if rssIconAtTop:
        htmlStr += rssIconStr
    htmlStr += '      </div>\n'

    if editImageClass == 'leftColEdit':
        htmlStr += '      </center>\n'

    if (editor or rssIconAtTop) and not showHeaderImage:
        htmlStr += '</div><br>'

    # if showHeaderImage:
    #     htmlStr += '<br>'

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

    linksFilename = baseDir + '/accounts/links.txt'
    linksFileContainsEntries = False
    linksList = None
    if os.path.isfile(linksFilename):
        with open(linksFilename, 'r') as f:
            linksList = f.readlines()

    if not frontPage:
        # show a number of shares
        maxSharesInLeftColumn = 3
        sharesList = \
            _getLeftColumnShares(baseDir,
                                 httpPrefix, domain, domainFull, nickname,
                                 maxSharesInLeftColumn, translate,
                                 sharedItemsFederatedDomains)
        if linksList and sharesList:
            linksList = sharesList + linksList

        wantedList = \
            _getLeftColumnWanted(baseDir,
                                 httpPrefix, domain, domainFull, nickname,
                                 maxSharesInLeftColumn, translate,
                                 sharedItemsFederatedDomains)
        if linksList and wantedList:
            linksList = wantedList + linksList

    newTabStr = ' target="_blank" rel="nofollow noopener noreferrer"'
    if linksList:
        htmlStr += '<nav>\n'
        for lineStr in linksList:
            if ' ' not in lineStr:
                if '#' not in lineStr:
                    if '*' not in lineStr:
                        if not lineStr.startswith('['):
                            if not lineStr.startswith('=> '):
                                continue
            lineStr = lineStr.strip()
            linkStr = None
            if not lineStr.startswith('['):
                words = lineStr.split(' ')
                # get the link
                for word in words:
                    if word == '#':
                        continue
                    if word == '*':
                        continue
                    if word == '=>':
                        continue
                    if '://' in word:
                        linkStr = word
                        break
            else:
                # markdown link
                if ']' not in lineStr:
                    continue
                if '(' not in lineStr:
                    continue
                if ')' not in lineStr:
                    continue
                linkStr = lineStr.split('(')[1]
                if ')' not in linkStr:
                    continue
                linkStr = linkStr.split(')')[0]
                if '://' not in linkStr:
                    continue
                lineStr = lineStr.split('[')[1]
                if ']' not in lineStr:
                    continue
                lineStr = lineStr.split(']')[0]
            if linkStr:
                lineStr = lineStr.replace(linkStr, '').strip()
                # avoid any dubious scripts being added
                if '<' not in lineStr:
                    # remove trailing comma if present
                    if lineStr.endswith(','):
                        lineStr = lineStr[:len(lineStr)-1]
                    # add link to the returned html
                    if '?showshare=' not in linkStr and \
                       '?showwarning=' not in linkStr:
                        htmlStr += \
                            '      <p><a href="' + linkStr + \
                            '"' + newTabStr + '>' + \
                            lineStr + '</a></p>\n'
                    else:
                        htmlStr += \
                            '      <p><a href="' + linkStr + \
                            '">' + lineStr + '</a></p>\n'
                    linksFileContainsEntries = True
                elif lineStr.startswith('=> '):
                    # gemini style link
                    lineStr = lineStr.replace('=> ', '')
                    lineStr = lineStr.replace(linkStr, '')
                    # add link to the returned html
                    if '?showshare=' not in linkStr and \
                       '?showwarning=' not in linkStr:
                        htmlStr += \
                            '      <p><a href="' + linkStr + \
                            '"' + newTabStr + '>' + \
                            lineStr.strip() + '</a></p>\n'
                    else:
                        htmlStr += \
                            '      <p><a href="' + linkStr + \
                            '">' + lineStr.strip() + '</a></p>\n'
                    linksFileContainsEntries = True
            else:
                if lineStr.startswith('#') or lineStr.startswith('*'):
                    lineStr = lineStr[1:].strip()
                    if firstSeparatorAdded:
                        htmlStr += separatorStr
                    firstSeparatorAdded = True
                    htmlStr += \
                        '      <h3 class="linksHeader">' + \
                        lineStr + '</h3>\n'
                else:
                    htmlStr += \
                        '      <p>' + lineStr + '</p>\n'
                linksFileContainsEntries = True
        htmlStr += '</nav>\n'

    if firstSeparatorAdded:
        htmlStr += separatorStr
    htmlStr += \
        '<p class="login-text"><a href="/users/' + nickname + \
        '/catalog.csv">' + translate['Shares Catalog'] + '</a></p>'
    htmlStr += \
        '<p class="login-text"><a href="/users/' + \
        nickname + '/accesskeys" accesskey="' + \
        accessKeys['menuKeys'] + '">' + \
        translate['Key Shortcuts'] + '</a></p>'
    htmlStr += \
        '<p class="login-text"><a href="/about">' + \
        translate['About this Instance'] + '</a></p>'
    htmlStr += \
        '<p class="login-text"><a href="/terms">' + \
        translate['Terms of Service'] + '</a></p>'

    if linksFileContainsEntries and not rssIconAtTop:
        htmlStr += '<br><div class="columnIcons">' + rssIconStr + '</div>'

    return htmlStr


def htmlLinksMobile(cssCache: {}, baseDir: str,
                    nickname: str, domainFull: str,
                    httpPrefix: str, translate,
                    timelinePath: str, authorized: bool,
                    rssIconAtTop: bool,
                    iconsAsButtons: bool,
                    defaultTimeline: str,
                    theme: str, accessKeys: {},
                    sharedItemsFederatedDomains: []) -> str:
    """Show the left column links within mobile view
    """
    htmlStr = ''

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

    # is the user a site editor?
    if nickname == 'news':
        editor = False
        artist = False
    else:
        editor = isEditor(baseDir, nickname)
        artist = isArtist(baseDir, nickname)

    domain = removeDomainPort(domainFull)

    instanceTitle = \
        getConfigParam(baseDir, 'instanceTitle')
    htmlStr = htmlHeaderWithExternalStyle(cssFilename, instanceTitle, None)
    bannerFile, bannerFilename = \
        getBannerFile(baseDir, nickname, domain, theme)
    htmlStr += \
        '<a href="/users/' + nickname + '/' + defaultTimeline + '" ' + \
        'accesskey="' + accessKeys['menuTimeline'] + '">' + \
        '<img loading="lazy" class="timeline-banner" ' + \
        'alt="' + translate['Switch to timeline view'] + '" ' + \
        'src="/users/' + nickname + '/' + bannerFile + '" /></a>\n'

    htmlStr += '<div class="col-left-mobile">\n'
    htmlStr += '<center>' + \
        headerButtonsFrontScreen(translate, nickname,
                                 'links', authorized,
                                 iconsAsButtons) + '</center>'
    htmlStr += \
        getLeftColumnContent(baseDir, nickname, domainFull,
                             httpPrefix, translate,
                             editor, artist,
                             False, timelinePath,
                             rssIconAtTop, False, False,
                             theme, accessKeys,
                             sharedItemsFederatedDomains)
    if editor and not _linksExist(baseDir):
        htmlStr += '<br><br><br>\n<center>\n  '
        htmlStr += translate['Select the edit icon to add web links']
        htmlStr += '\n</center>\n'

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

    htmlStr += '</div>\n' + htmlFooter()
    return htmlStr


def htmlEditLinks(cssCache: {}, translate: {}, baseDir: str, path: str,
                  domain: str, port: int, httpPrefix: str,
                  defaultTimeline: str, theme: str,
                  accessKeys: {}) -> 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 = getNicknameFromActor(path)
    if not nickname:
        return ''

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

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

    # filename of the banner shown at the top
    bannerFile, bannerFilename = \
        getBannerFile(baseDir, nickname, domain, theme)

    instanceTitle = \
        getConfigParam(baseDir, 'instanceTitle')
    editLinksForm = \
        htmlHeaderWithExternalStyle(cssFilename, instanceTitle, None)

    # top banner
    editLinksForm += \
        '<header>\n' + \
        '<a href="/users/' + nickname + '/' + defaultTimeline + '" title="' + \
        translate['Switch to timeline view'] + '" alt="' + \
        translate['Switch to timeline view'] + '" ' + \
        'accesskey="' + accessKeys['menuTimeline'] + '">\n'
    editLinksForm += \
        '<img loading="lazy" class="timeline-banner" ' + \
        'alt = "" src="' + \
        '/users/' + nickname + '/' + bannerFile + '" /></a>\n' + \
        '</header>\n'

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

    linksFilename = baseDir + '/accounts/links.txt'
    linksStr = ''
    if os.path.isfile(linksFilename):
        with open(linksFilename, 'r') as fp:
            linksStr = fp.read()

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

    # the admin can edit terms of service and about text
    adminNickname = getConfigParam(baseDir, 'admin')
    if adminNickname:
        if nickname == adminNickname:
            aboutFilename = baseDir + '/accounts/about.md'
            aboutStr = ''
            if os.path.isfile(aboutFilename):
                with open(aboutFilename, 'r') as fp:
                    aboutStr = fp.read()

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

            TOSFilename = baseDir + '/accounts/tos.md'
            TOSStr = ''
            if os.path.isfile(TOSFilename):
                with open(TOSFilename, 'r') as fp:
                    TOSStr = fp.read()

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

    editLinksForm += htmlFooter()
    return editLinksForm