<script setup lang="ts">
import gm from 'avris-generator';
import { DateTime } from 'luxon';
import { useNuxtApp } from 'nuxt/app';

import useDialogue from '~/composables/useDialogue.ts';
import useSimpleHead from '~/composables/useSimpleHead.ts';
import {
    min,
    max,
    closed,
    MONTHS as months,
    AREAS as areas,
    TRANSFER_METHODS as transferMethods,
    type TimesheetData, type Timesheet,
} from '~/src/timesheets.ts';

const { $translator: translator } = useNuxtApp();
const dialogue = useDialogue();
useSimpleHead({
    title: `${translator.translate('admin.header')} • Volunteering timesheets`,
}, translator);

const persistentAsyncData = useFetch<TimesheetData>('/api/admin/timesheet');
const moderationAsyncData = useFetch('/api/admin/moderation', { pick: ['timesheets'] });
await Promise.all([persistentAsyncData, moderationAsyncData]);
const persistent = persistentAsyncData.data;
const moderation = moderationAsyncData.data;

const years: number[] = [];
for (let y = min.year; y <= max.year; y++) {
    years.push(y);
}

const year = ref(max.year);

const cells = ref<Map<string, HTMLElement>>(new Map());
watch(year, () => {
    cells.value.get('1-0')?.focus();
});

const buildTimesheet = (persistent: TimesheetData | null): Timesheet => {
    const timesheet: Timesheet = {};
    for (let y = min.year; y <= max.year; y++) {
        timesheet[y] = {};
        for (const m of Object.keys(months)) {
            timesheet[y][m] = {};
            for (const area of areas) {
                timesheet[y][m][area] = persistent?.timesheet?.[y]?.[m]?.[area] || 0;
            }
        }
    }
    return timesheet;
};

const timesheet = ref(buildTimesheet(persistent.value));
const transferMethod = ref<TimesheetData['transfer']>(persistent.value?.transfer || '');
const transferDetails = ref<TimesheetData['details']>({
    bank_name: persistent.value?.details?.bank_name || '',
    bank_iban: persistent.value?.details?.bank_iban || '',
    bank_bic: persistent.value?.details?.bank_bic || '',
    paypal_email: persistent.value?.details?.paypal_email || '',
    charity_name: persistent.value?.details?.charity_name || '',
    charity_url: persistent.value?.details?.charity_url || '',
    notes: persistent.value?.details?.notes || '',
});

const focusMonth = ref<keyof typeof months | null>(null);
const focusArea = ref<number | null>(null);

const dt = (year: number, month: number) => {
    return DateTime.local(year, month, 1);
};

const validateIBAN = (iban: string): string => {
    if (!iban.trim()) {
        return '';
    }
    try {
        gm.validate('_', 'iban', iban);
        return 'is-valid';
    } catch (e) {
        return 'is-invalid';
    }
};
const validateBIC = (bic: string): string => {
    if (!bic.trim()) {
        return '';
    }
    return bic.replace(/ /g, '').match(/^[A-Z0-9]{8,11}$/)
        ? 'is-valid'
        : 'is-invalid';
};

const save = async () => {
    await dialogue.postWithAlertOnError('/api/admin/timesheet', {
        timesheets: {
            timesheet: timesheet.value,
            transfer: transferMethod.value,
            details: transferDetails.value,
        },
    });
    await dialogue.alert('Saved successfully', 'success');
};

const cellKeydown = (e: KeyboardEvent) => {
    let newFocusMonth = focusMonth.value ?? 1;
    let newFocusArea = focusArea.value ?? 0;

    switch (e.key) {
        case 'ArrowLeft':
            newFocusMonth--;
            break;
        case 'ArrowRight':
            newFocusMonth++;
            break;
        case 'ArrowUp':
            newFocusArea--;
            break;
        case 'ArrowDown':
            newFocusArea++;
            break;
        default:
            return;
    }
    e.preventDefault();
    e.stopPropagation();

    const cell = cells.value.get(`${newFocusMonth}-${newFocusArea}`);
    if (!cell || cell.getAttribute('disabled')) {
        return;
    }
    cell.focus();
};

const sumCells = (area: typeof areas[number] | undefined, month: keyof typeof months | undefined) => {
    let sum = 0;
    for (const m of Object.keys(timesheet.value[year.value])) {
        if (month !== undefined && parseInt(m) !== parseInt(month as any as string)) {
            continue;
        }
        for (const a in timesheet.value[year.value][m]) {
            if (area !== undefined && a !== area) {
                continue;
            }
            sum += timesheet.value[year.value][m][a] || 0;
        }
    }
    return sum;
};
</script>

<template>
    <Page wide>
        <NotFound v-if="!$isGranted('panel')" />
        <div v-else>
            <p class="d-flex justify-content-between">
                <nuxt-link to="/admin">
                    <Icon v="user-cog" />
                    <T>admin.header</T>
                </nuxt-link>
                <span>
                    <nuxt-link to="/admin/timesheets/overview">
                        <Icon v="file-spreadsheet" />
                        Overview
                    </nuxt-link>
                    <nuxt-link to="/admin/timesheets/expenses">
                        <Icon v="file-spreadsheet" />
                        Declare expenses
                    </nuxt-link>
                </span>
            </p>
            <div v-html="moderation?.timesheets"></div>

            <hr>

            <h3>
                Year:
                <button
                    v-for="y in years"
                    :key="y"
                    :class="['btn', y === year ? 'btn-primary' : 'btn-outline-primary', 'mx-2']"
                    @click="year = y"
                >
                    {{ y }}
                </button>
            </h3>

            <div class="table-responsive">
                <table class="table table-striped">
                    <thead>
                        <tr>
                            <th>Area</th>
                            <th v-for="month in months">
                                {{ month }}
                            </th>
                            <th>Sum</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr v-for="area in areas">
                            <th>{{ area }}</th>
                            <td v-for="(month, m) in months">
                                <input
                                    :ref="(el) => cells.set(`${m}-${areas.indexOf(area)}`, el as HTMLInputElement)"
                                    v-model.number="timesheet[year][m][area]"
                                    type="number"
                                    min="0"
                                    max="160"
                                    step="0.5"
                                    class="form-control form-control-sm"
                                    style="min-width: 3rem"
                                    :disabled="dt(year, m) < closed || dt(year, m) > max"
                                    @focus="focusMonth = m;focusArea = areas.indexOf(area)"
                                    @keydown="cellKeydown"
                                >
                            </td>
                            <td>
                                <strong>
                                    {{ sumCells(area, undefined) }}
                                </strong>
                            </td>
                        </tr>
                        <tr>
                            <th>Sum</th>
                            <td v-for="(month, m) in months">
                                <strong>
                                    {{ sumCells(undefined, m) }}
                                </strong>
                            </td>
                            <td>
                                <strong>
                                    {{ sumCells(undefined, undefined) }}
                                </strong>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>

            <section>
                <p>
                    <strong>Transfer method:</strong>
                    <span v-for="(label, value) in transferMethods" class="form-check form-check-inline">
                        <input
                            :id="`method_${value}`"
                            v-model="transferMethod"
                            class="form-check-input"
                            type="radio"
                            name="inlineRadioOptions"
                            :value="value"
                        >
                        <label class="form-check-label" :for="`method_${value}`">{{ label }}</label>
                    </span>
                </p>
                <div v-if="transferMethod === 'bank'" class="mb-3">
                    <label for="bank_name" class="form-label">Owner name</label>
                    <input id="bank_name" v-model="transferDetails.bank_name" type="text" class="form-control" placeholder="Jay Doe">
                </div>
                <div v-if="transferMethod === 'bank'" class="mb-3">
                    <label for="bank_iban" class="form-label">IBAN</label>
                    <input id="bank_iban" v-model="transferDetails.bank_iban" type="text" :class="['form-control', validateIBAN(transferDetails.bank_iban)]" placeholder="NL12 ABCD 1234 5678 90">
                </div>
                <div v-if="transferMethod === 'bank'" class="mb-3">
                    <label for="bank_bic" class="form-label">BIC</label>
                    <input id="bank_bic" v-model="transferDetails.bank_bic" type="text" :class="['form-control', validateBIC(transferDetails.bank_bic)]" placeholder="BUNQNL2A">
                </div>
                <div v-if="transferMethod === 'paypal'" class="mb-3">
                    <label for="paypal_email" class="form-label">Email</label>
                    <input id="paypal_email" v-model="transferDetails.paypal_email" type="email" class="form-control" placeholder="paypal-user@email.com">
                </div>
                <div v-if="transferMethod !== 'skip' && transferMethod !== 'charity'" class="mb-3">
                    <p><em>There's a legal limit of how much we can send as volunteer allowance, so please also pick a charity in case it's exceeded.</em></p>
                </div>
                <div v-if="transferMethod !== 'skip'" class="mb-3">
                    <p><em>You can also leave the charity details empty – in that case we'll set aside that share and pick a charity together at the end of year, or whenever need arises.</em></p>
                </div>
                <div v-if="transferMethod !== 'skip'" class="mb-3">
                    <label for="charity_name" class="form-label">Charity name</label>
                    <input id="charity_name" v-model="transferDetails.charity_name" type="text" class="form-control" placeholder="Trevor Project">
                </div>
                <div v-if="transferMethod !== 'skip'" class="mb-3">
                    <label for="charity_url" class="form-label">Link</label>
                    <input id="charity_url" v-model="transferDetails.charity_url" type="email" class="form-control" placeholder="https://www.thetrevorproject.org/">
                </div>
                <div v-if="transferMethod" class="mb-3">
                    <label for="notes" class="form-label">Notes</label>
                    <input id="notes" v-model="transferDetails.notes" type="text" class="form-control" placeholder="">
                </div>
            </section>
            <button class="btn btn-primary" :disabled="!transferMethod" @click="save">
                <Icon v="save" />
                Save
            </button>
        </div>
    </Page>
</template>
