import { For, Show, createEffect, createMemo, createSignal } from "solid-js";
import { Person } from "../../types/Person";
import { Register } from "../../types/Register";
import { courseMap } from "../../utils/allCourses";
import { certGenerator } from "../../certGenerator";
import { CaretRight } from "../../icons/CaretRight";
import { RegisterSidebar } from "./RegisterSidebar";
import { customLabelsMap } from "../../utils/allCustomLabels";
import { DownloadSimpleIcon } from "../../icons/DownloadSimpleIcon";
import { backend, wait } from "../../utils/functions";
import { JsonResult } from "../../types/JsonResult";
import { LoadingIcon } from "../../icons/LoadingIcon";

export function Registers(props: {person: Person | null, count: number}) {
    const [registers, setRegisters] = createSignal<Array<Register>>([]);
    const [showHidden, setShowHidden] = createSignal(false);
    const [sidebarRegister, setSidebarRegister] = createSignal<Register | null>(null);
    const [loading, setLoading] = createSignal(false);
    const [error, setError] = createSignal("");

    const loadRegisters = async() => {
        setLoading(true);
        setError("");

        const person = props.person!;
        setRegisters([]);

        if (import.meta.env.DEV) await wait(1500);

        backend.get<JsonResult<Array<Register>>>(`/api/register/${person.person_dni}`)
            .then((response) => {
                if (response.status === 200) {
                    setRegisters(response.data.Ok);
                } else {
                    console.error(response.data.Err);
                    setError(response.data.Err.reason);
                }
            })
            .catch((err) => {
                console.error(err);
                setError(`Error fatal: ${err.message}`);
            })
            .finally(() => setLoading(false));
    };

    createEffect(async() => {
        // eslint-disable-next-line @typescript-eslint/no-unused-vars
        const _count = props.count;

        if (props.person === null) {
            setRegisters([]);
            return;
        }

        loadRegisters();
    });

    // All registers sorted by year, and an indicator of whether there's register older
    // than last year
    const registerSortedList = createMemo<[Array<Array<Register>>, boolean]>(() => {
        const allRegisters = registers();

        const registerByYear: {[y: string]: Array<Register>} = {};

        let olderThanLastYear = false;
        allRegisters.forEach((register) => {
            const year = new Date(register.register_display_date).getFullYear();
            const currentYear = new Date().getFullYear();

            // Don't show registers from before last year
            if (year < (currentYear - 1)) {
                olderThanLastYear = true;
                if (!showHidden()) {
                    return;
                }
            }

            if (registerByYear[year] === undefined) {
                registerByYear[year] = [];
            }

            registerByYear[year].push(register);
        });

        // Create a new array with each year's registers
        // Sort the object keys (years) in descending order
        const sortedYears = Object.keys(registerByYear).sort((y1, y2) => (y1 < y2 ? 1 : -1));

        // Create the final array
        const result = sortedYears.map((year) => registerByYear[year].sort((r1, r2) => (r1.register_display_date < r2.register_display_date ? 1 : -1)));

        return [result, olderThanLastYear];
    });

    const inputCheck = () => setShowHidden((x) => !x);

    const todayRegisters = createMemo(() => {
        const today = new Date().toISOString()
            .split("T")[0];
        return registerSortedList()[0][0]
            ?.filter((r) => r.register_creation_date === today) ?? [];
    });

    const downloadTodayCerts = () => {
        if (props.person === null) return;

        todayRegisters().forEach((register) => {
            generateCert(props.person!, register);
        });
    };

    return (
        <div class="m-4 p-4 rounded-md relative">
            <h3 class="text-xl font-medium">
                <button
                    class="bg-c-primary text-c-on-primary inline-block mr-2 rounded-full
                        disabled:opacity-25 disabled:cursor-not-allowed px-2"
                    disabled={todayRegisters().length === 0}
                    title="Descargar todos los cert. creados hoy"
                    onclick={downloadTodayCerts}
                >
                    <DownloadSimpleIcon fill="var(--c-on-primary)" size={24} />
                    <span class="text-sm">
                        &nbsp;hoy
                    </span>
                </button>
                {props.person?.person_names}&nbsp;
                {props.person?.person_paternal_surname}&nbsp;
                {props.person?.person_maternal_surname}

                <Show when={registerSortedList()[1]}>
                    &nbsp;&nbsp;&nbsp;|
                    <input id={`person_${props.person?.person_id ?? "_"}`} type="checkbox" class="ml-4 mr-2" checked oninput={inputCheck} />
                    <label for={`person_${props.person?.person_id ?? "_"}`} class="text-sm">
                        Ocultar cert. anteriores a {new Date().getFullYear() - 1}
                    </label>
                </Show>
            </h3>

            <For each={registerSortedList()[0]}>
                {(year) => (
                    <div class="flex flex-wrap justify-start gap-2 my-6">
                        <For each={year}>
                            {(register) => (
                                <RegisterEl
                                    register={register}
                                    person={props.person!}
                                    onClick={() => setSidebarRegister(register)}
                                />
                            )}
                        </For>
                    </div>
                )}
            </For>

            <Show when={loading()}>
                <div class="text-center">
                    <LoadingIcon class="animate-spin" fill="var(--c-on-surface)" />
                </div>
            </Show>

            <Show when={error() !== ""}>
                <p>Error: {error()}</p>
            </Show>

            <Show when={sidebarRegister() !== null}>
                <RegisterSidebar
                    register={sidebarRegister()!}
                    close={() => setSidebarRegister(null)}
                    onDelete={loadRegisters}
                />
            </Show>
        </div>
    );
}

function RegisterEl(props: {register: Register, person: Person, onClick: () => void}) {

    const dateComponents = () => {
        const [, year, month, day] = /(\d{4})-(\d{2})-(\d{2})/.exec(props.register.register_display_date) ?? [];
        return {year, month, day};
    };

    const displayDate = () => {
        const {year, month, day} = dateComponents();
        return `${day}/${month}/${year}`;
    };

    const courseName = () => {
        const course = courseMap()[props.register.register_course_id];
        return course?.course_name ?? "Curso no encontrado";
    };

    const customLabel = () => {
        const labelId = props.register.register_custom_label;
        if (labelId === 1) return "";
        return customLabelsMap()[labelId]?.custom_label_value ?? "";
    };

    const genCert = () => {
        const person = props.person;
        const register = props.register;

        generateCert(person, register);
    };

    const generateable = () => {
        const courseN = courseName();
        return certGenerator[courseN] !== undefined;
    };

    const createdTodayClasses = () => {
        // current dat in YYYY-MM-DD format
        const today = new Date().toISOString()
            .split("T")[0];
        const createdToday = props.register.register_creation_date === today;

        return createdToday ? "bg-c-surface-variant" : "";
    };

    return (
        <div class="grid grid-cols-[11rem_1.5rem_1.25rem] border border-c-outline rounded-md overflow-hidden">
            <div class="border-r border-c-outline-50 align-middle">
                <p
                    class="font-bold overflow-hidden whitespace-nowrap pt-1 px-1"
                    title={`${courseName()} ${customLabel()}`}
                >
                    {courseName()}
                </p>
                <p class="font-mono text-sm px-1">
                    <span class="underline">
                        {customLabel()}
                    </span>
                    &nbsp;
                </p>
                <p class={`text-sm px-1 pb-1 ${createdTodayClasses()}`}>
                    <span class="font-mono">
                        {displayDate()}
                    </span>

                    <Show when={props.register.register_is_preview}>
                        <span class="text-c-error font-bold select-none">
                            &nbsp;sin firmas
                        </span>
                    </Show>
                    <Show when={!props.register.register_is_preview}>
                        <span class="font-mono">
                            &nbsp;- {props.register.register_code}
                        </span>
                    </Show>
                </p>
            </div>
            <button
                class="hover:bg-c-primary-container rounded-md transition-colors
                        disabled:opacity-0 disabled:cursor-default
                        disabled:hover:bg-c-transparent"
                title="Descargar DOCX"
                onclick={genCert}
                disabled={!generateable()}
            >
                <DownloadSimpleIcon fill="var(--c-on-primary-container)" size={20} />
            </button>
            <button
                class="hover:bg-c-surface-variant rounded-md transition-colors"
                title="Más opciones"
                onclick={props.onClick}
            >
                <CaretRight fill="var(--c-primary)" size={20} />
            </button>
        </div>
    );
}

function generateCert(person: Person, register: Register) {
    const courseN = courseMap()[register.register_course_id]?.course_name ?? "Curso no encontrado";

    const generator = certGenerator[courseN];
    if (generator === undefined) {
        alert(`Generator function with key \`${courseN}\` not found`);
        return;
    }

    const [, year, month, day] = /(\d{4})-(\d{2})-(\d{2})/.exec(register.register_display_date) ?? [];
    const personFullName = `${person.person_names} ${person.person_paternal_surname} ${person.person_maternal_surname}`;

    // Manage custom label
    const certCustomLabel = register.register_custom_label === 1
        ? ""
        : customLabelsMap()[register.register_custom_label]?.custom_label_value ?? "";

    const certCode = register.register_is_preview ? "0000" : register.register_code.toString().padStart(4, "0");

    generator(`${courseN} - ${personFullName}.docx`, {
        matpel: null,
        personFullName,
        personDni: person.person_dni.toString(),
        certCode,
        certYear: year,
        certMonth: month,
        certDay: day,
        certIId: register.register_code,
        certCustomLabel,
    });
}
