__filename__ = "webapp_calendar.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
__version__ = "1.2.0"
__maintainer__ = "Bob Mottram"
__email__ = "bob@libreserver.org"
__status__ = "Production"
__module_group__ = "Calendar"

import os
from datetime import datetime
from datetime import date
from utils import get_display_name
from utils import get_config_param
from utils import get_nickname_from_actor
from utils import get_domain_from_actor
from utils import locate_post
from utils import load_json
from utils import week_day_of_month_start
from utils import get_alt_path
from utils import remove_domain_port
from utils import acct_dir
from utils import local_actor_url
from utils import replace_users_with_at
from happening import get_todays_events
from happening import get_calendar_events
from webapp_utils import set_custom_background
from webapp_utils import html_header_with_external_style
from webapp_utils import html_footer
from webapp_utils import html_hide_from_screen_reader
from webapp_utils import html_keyboard_navigation


def html_calendar_delete_confirm(css_cache: {}, translate: {}, base_dir: str,
                                 path: str, http_prefix: str,
                                 domain_full: str, post_id: str, postTime: str,
                                 year: int, monthNumber: int,
                                 dayNumber: int, calling_domain: str) -> str:
    """Shows a screen asking to confirm the deletion of a calendar event
    """
    nickname = get_nickname_from_actor(path)
    actor = local_actor_url(http_prefix, nickname, domain_full)
    domain, port = get_domain_from_actor(actor)
    messageId = actor + '/statuses/' + post_id

    post_filename = locate_post(base_dir, nickname, domain, messageId)
    if not post_filename:
        return None

    post_json_object = load_json(post_filename)
    if not post_json_object:
        return None

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

    instanceTitle = \
        get_config_param(base_dir, 'instanceTitle')
    delete_postStr = \
        html_header_with_external_style(css_filename, instanceTitle, None)
    delete_postStr += \
        '<center><h1>' + postTime + ' ' + str(year) + '/' + \
        str(monthNumber) + \
        '/' + str(dayNumber) + '</h1></center>'
    delete_postStr += '<center>'
    delete_postStr += '  <p class="followText">' + \
        translate['Delete this event'] + '</p>'

    postActor = get_alt_path(actor, domain_full, calling_domain)
    delete_postStr += \
        '  <form method="POST" action="' + postActor + '/rmpost">\n'
    delete_postStr += '    <input type="hidden" name="year" value="' + \
        str(year) + '">\n'
    delete_postStr += '    <input type="hidden" name="month" value="' + \
        str(monthNumber) + '">\n'
    delete_postStr += '    <input type="hidden" name="day" value="' + \
        str(dayNumber) + '">\n'
    delete_postStr += \
        '    <input type="hidden" name="pageNumber" value="1">\n'
    delete_postStr += \
        '    <input type="hidden" name="messageId" value="' + \
        messageId + '">\n'
    delete_postStr += \
        '    <button type="submit" class="button" name="submitYes">' + \
        translate['Yes'] + '</button>\n'
    delete_postStr += \
        '    <a href="' + actor + '/calendar?year=' + \
        str(year) + '?month=' + \
        str(monthNumber) + '"><button class="button">' + \
        translate['No'] + '</button></a>\n'
    delete_postStr += '  </form>\n'
    delete_postStr += '</center>\n'
    delete_postStr += html_footer()
    return delete_postStr


def _html_calendar_day(person_cache: {}, css_cache: {}, translate: {},
                       base_dir: str, path: str,
                       year: int, monthNumber: int, dayNumber: int,
                       nickname: str, domain: str, dayEvents: [],
                       monthName: str, actor: str) -> str:
    """Show a day within the calendar
    """
    accountDir = acct_dir(base_dir, nickname, domain)
    calendarFile = accountDir + '/.newCalendar'
    if os.path.isfile(calendarFile):
        try:
            os.remove(calendarFile)
        except OSError:
            print('EX: _html_calendar_day unable to delete ' + calendarFile)

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

    calActor = actor
    if '/users/' in actor:
        calActor = '/users/' + actor.split('/users/')[1]

    instanceTitle = get_config_param(base_dir, 'instanceTitle')
    calendarStr = \
        html_header_with_external_style(css_filename, instanceTitle, None)
    calendarStr += '<main><table class="calendar">\n'
    calendarStr += '<caption class="calendar__banner--month">\n'
    calendarStr += \
        '  <a href="' + calActor + '/calendar?year=' + str(year) + \
        '?month=' + str(monthNumber) + '">\n'
    calendarStr += \
        '  <h1>' + str(dayNumber) + ' ' + monthName + \
        '</h1></a><br><span class="year">' + str(year) + '</span>\n'
    calendarStr += '</caption>\n'
    calendarStr += '<tbody>\n'

    if dayEvents:
        for eventPost in dayEvents:
            eventTime = None
            eventDescription = None
            eventPlace = None
            post_id = None
            senderName = ''
            senderActor = None
            eventIsPublic = False
            # get the time place and description
            for ev in eventPost:
                if ev['type'] == 'Event':
                    if ev.get('post_id'):
                        post_id = ev['post_id']
                    if ev.get('startTime'):
                        eventDate = \
                            datetime.strptime(ev['startTime'],
                                              "%Y-%m-%dT%H:%M:%S%z")
                        eventTime = eventDate.strftime("%H:%M").strip()
                    if 'public' in ev:
                        if ev['public'] is True:
                            eventIsPublic = True
                    if ev.get('sender'):
                        # get display name from sending actor
                        if ev.get('sender'):
                            senderActor = ev['sender']
                            dispName = \
                                get_display_name(base_dir, senderActor,
                                                 person_cache)
                            if dispName:
                                senderName = \
                                    '<a href="' + senderActor + '">' + \
                                    dispName + '</a>: '
                    if ev.get('name'):
                        eventDescription = ev['name'].strip()
                elif ev['type'] == 'Place':
                    if ev.get('name'):
                        eventPlace = ev['name']

            # prepend a link to the sender of the calendar item
            if senderName and eventDescription:
                # if the sender is also mentioned within the event
                # description then this is a reminder
                senderActor2 = replace_users_with_at(senderActor)
                if senderActor not in eventDescription and \
                   senderActor2 not in eventDescription:
                    eventDescription = senderName + eventDescription
                else:
                    eventDescription = \
                        translate['Reminder'] + ': ' + eventDescription

            deleteButtonStr = ''
            if post_id:
                deleteButtonStr = \
                    '<td class="calendar__day__icons"><a href="' + calActor + \
                    '/eventdelete?eventid=' + post_id + \
                    '?year=' + str(year) + \
                    '?month=' + str(monthNumber) + \
                    '?day=' + str(dayNumber) + \
                    '?time=' + eventTime + \
                    '">\n<img class="calendardayicon" loading="lazy" alt="' + \
                    translate['Delete this event'] + ' |" title="' + \
                    translate['Delete this event'] + '" src="/' + \
                    'icons/delete.png" /></a></td>\n'

            eventClass = 'calendar__day__event'
            calItemClass = 'calItem'
            if eventIsPublic:
                eventClass = 'calendar__day__event__public'
                calItemClass = 'calItemPublic'
            if eventTime and eventDescription and eventPlace:
                calendarStr += \
                    '<tr class="' + calItemClass + '">' + \
                    '<td class="calendar__day__time"><b>' + eventTime + \
                    '</b></td><td class="' + eventClass + '">' + \
                    '<span class="place">' + \
                    eventPlace + '</span><br>' + eventDescription + \
                    '</td>' + deleteButtonStr + '</tr>\n'
            elif eventTime and eventDescription and not eventPlace:
                calendarStr += \
                    '<tr class="' + calItemClass + '">' + \
                    '<td class="calendar__day__time"><b>' + eventTime + \
                    '</b></td><td class="' + eventClass + '">' + \
                    eventDescription + '</td>' + deleteButtonStr + '</tr>\n'
            elif not eventTime and eventDescription and not eventPlace:
                calendarStr += \
                    '<tr class="' + calItemClass + '">' + \
                    '<td class="calendar__day__time">' + \
                    '</td><td class="' + eventClass + '">' + \
                    eventDescription + '</td>' + deleteButtonStr + '</tr>\n'
            elif not eventTime and eventDescription and eventPlace:
                calendarStr += \
                    '<tr class="' + calItemClass + '">' + \
                    '<td class="calendar__day__time"></td>' + \
                    '<td class="' + eventClass + '"><span class="place">' + \
                    eventPlace + '</span><br>' + eventDescription + \
                    '</td>' + deleteButtonStr + '</tr>\n'
            elif eventTime and not eventDescription and eventPlace:
                calendarStr += \
                    '<tr class="' + calItemClass + '">' + \
                    '<td class="calendar__day__time"><b>' + eventTime + \
                    '</b></td><td class="' + eventClass + '">' + \
                    '<span class="place">' + \
                    eventPlace + '</span></td>' + \
                    deleteButtonStr + '</tr>\n'

    calendarStr += '</tbody>\n'
    calendarStr += '</table></main>\n'
    calendarStr += html_footer()

    return calendarStr


def html_calendar(person_cache: {}, css_cache: {}, translate: {},
                  base_dir: str, path: str,
                  http_prefix: str, domain_full: str,
                  text_mode_banner: str, access_keys: {}) -> str:
    """Show the calendar for a person
    """
    domain = remove_domain_port(domain_full)

    monthNumber = 0
    dayNumber = None
    year = 1970
    actor = http_prefix + '://' + domain_full + path.replace('/calendar', '')
    if '?' in actor:
        first = True
        for p in actor.split('?'):
            if not first:
                if '=' in p:
                    if p.split('=')[0] == 'year':
                        numStr = p.split('=')[1]
                        if numStr.isdigit():
                            year = int(numStr)
                    elif p.split('=')[0] == 'month':
                        numStr = p.split('=')[1]
                        if numStr.isdigit():
                            monthNumber = int(numStr)
                    elif p.split('=')[0] == 'day':
                        numStr = p.split('=')[1]
                        if numStr.isdigit():
                            dayNumber = int(numStr)
            first = False
        actor = actor.split('?')[0]

    currDate = datetime.now()
    if year == 1970 and monthNumber == 0:
        year = currDate.year
        monthNumber = currDate.month

    nickname = get_nickname_from_actor(actor)

    set_custom_background(base_dir, 'calendar-background',
                          'calendar-background')

    months = (
        'January', 'February', 'March', 'April', 'May', 'June',
        'July', 'August', 'September', 'October', 'November', 'December'
    )
    monthName = translate[months[monthNumber - 1]]

    if dayNumber:
        dayEvents = None
        events = \
            get_todays_events(base_dir, nickname, domain,
                              year, monthNumber, dayNumber)
        if events:
            if events.get(str(dayNumber)):
                dayEvents = events[str(dayNumber)]
        return _html_calendar_day(person_cache, css_cache,
                                  translate, base_dir, path,
                                  year, monthNumber, dayNumber,
                                  nickname, domain, dayEvents,
                                  monthName, actor)

    events = \
        get_calendar_events(base_dir, nickname, domain, year, monthNumber)

    prevYear = year
    prevMonthNumber = monthNumber - 1
    if prevMonthNumber < 1:
        prevMonthNumber = 12
        prevYear = year - 1

    nextYear = year
    nextMonthNumber = monthNumber + 1
    if nextMonthNumber > 12:
        nextMonthNumber = 1
        nextYear = year + 1

    print('Calendar year=' + str(year) + ' month=' + str(monthNumber) +
          ' ' + str(week_day_of_month_start(monthNumber, year)))

    if monthNumber < 12:
        daysInMonth = \
            (date(year, monthNumber + 1, 1) - date(year, monthNumber, 1)).days
    else:
        daysInMonth = \
            (date(year + 1, 1, 1) - date(year, monthNumber, 1)).days
    # print('daysInMonth ' + str(monthNumber) + ': ' + str(daysInMonth))

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

    calActor = actor
    if '/users/' in actor:
        calActor = '/users/' + actor.split('/users/')[1]

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

    # the main graphical calendar as a table
    calendarStr = '<main><table class="calendar">\n'
    calendarStr += '<caption class="calendar__banner--month">\n'
    calendarStr += \
        '  <a href="' + calActor + '/calendar?year=' + str(prevYear) + \
        '?month=' + str(prevMonthNumber) + '" ' + \
        'accesskey="' + access_keys['Page up'] + '">'
    calendarStr += \
        '  <img loading="lazy" alt="' + translate['Previous month'] + \
        '" title="' + translate['Previous month'] + '" src="/icons' + \
        '/prev.png" class="buttonprev"/></a>\n'
    calendarStr += '  <a href="' + calActor + '/inbox" title="'
    calendarStr += translate['Switch to timeline view'] + '" ' + \
        'accesskey="' + access_keys['menuTimeline'] + '">'
    calendarStr += '  <h1>' + monthName + '</h1></a>\n'
    calendarStr += \
        '  <a href="' + calActor + '/calendar?year=' + str(nextYear) + \
        '?month=' + str(nextMonthNumber) + '" ' + \
        'accesskey="' + access_keys['Page down'] + '">'
    calendarStr += \
        '  <img loading="lazy" alt="' + translate['Next month'] + \
        '" title="' + translate['Next month'] + '" src="/icons' + \
        '/prev.png" class="buttonnext"/></a>\n'
    calendarStr += '</caption>\n'
    calendarStr += '<thead>\n'
    calendarStr += '<tr>\n'
    days = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat')
    for d in days:
        calendarStr += '  <th scope="col" class="calendar__day__header">' + \
            translate[d] + '</th>\n'
    calendarStr += '</tr>\n'
    calendarStr += '</thead>\n'
    calendarStr += '<tbody>\n'

    # beginning of the links used for accessibility
    nav_links = {}
    timelineLinkStr = html_hide_from_screen_reader('🏠') + ' ' + \
        translate['Switch to timeline view']
    nav_links[timelineLinkStr] = calActor + '/inbox'

    dayOfMonth = 0
    dow = week_day_of_month_start(monthNumber, year)
    for weekOfMonth in range(1, 7):
        if dayOfMonth == daysInMonth:
            continue
        calendarStr += '  <tr>\n'
        for dayNumber in range(1, 8):
            if (weekOfMonth > 1 and dayOfMonth < daysInMonth) or \
               (weekOfMonth == 1 and dayNumber >= dow):
                dayOfMonth += 1

                isToday = False
                if year == currDate.year:
                    if currDate.month == monthNumber:
                        if dayOfMonth == currDate.day:
                            isToday = True
                if events.get(str(dayOfMonth)):
                    url = calActor + '/calendar?year=' + \
                        str(year) + '?month=' + \
                        str(monthNumber) + '?day=' + str(dayOfMonth)
                    dayDescription = monthName + ' ' + str(dayOfMonth)
                    dayLink = '<a href="' + url + '" ' + \
                        'title="' + dayDescription + '">' + \
                        str(dayOfMonth) + '</a>'
                    # accessibility menu links
                    menuOptionStr = \
                        html_hide_from_screen_reader('📅') + ' ' + \
                        dayDescription
                    nav_links[menuOptionStr] = url
                    # there are events for this day
                    if not isToday:
                        calendarStr += \
                            '    <td class="calendar__day__cell" ' + \
                            'data-event="">' + \
                            dayLink + '</td>\n'
                    else:
                        calendarStr += \
                            '    <td class="calendar__day__cell" ' + \
                            'data-today-event="">' + \
                            dayLink + '</td>\n'
                else:
                    # No events today
                    if not isToday:
                        calendarStr += \
                            '    <td class="calendar__day__cell">' + \
                            str(dayOfMonth) + '</td>\n'
                    else:
                        calendarStr += \
                            '    <td class="calendar__day__cell" ' + \
                            'data-today="">' + str(dayOfMonth) + '</td>\n'
            else:
                calendarStr += '    <td class="calendar__day__cell"></td>\n'
        calendarStr += '  </tr>\n'

    calendarStr += '</tbody>\n'
    calendarStr += '</table></main>\n'

    # end of the links used for accessibility
    nextMonthStr = \
        html_hide_from_screen_reader('→') + ' ' + translate['Next month']
    nav_links[nextMonthStr] = calActor + '/calendar?year=' + str(nextYear) + \
        '?month=' + str(nextMonthNumber)
    prevMonthStr = \
        html_hide_from_screen_reader('←') + ' ' + translate['Previous month']
    nav_links[prevMonthStr] = calActor + '/calendar?year=' + str(prevYear) + \
        '?month=' + str(prevMonthNumber)
    nav_access_keys = {
    }
    screenReaderCal = \
        html_keyboard_navigation(text_mode_banner, nav_links, nav_access_keys,
                                 monthName)

    newEventStr = \
        '<br><center>\n<p>\n' + \
        '<a href="' + calActor + '/newreminder">➕ ' + \
        translate['Add to the calendar'] + '</a>\n</p>\n</center>\n'

    calStr = \
        headerStr + screenReaderCal + calendarStr + newEventStr + html_footer()

    return calStr