import { DataTable, type DataTableColumn } from '@admin/components/ui/data-table';
import { FormSelect } from '@admin/components/ui/forms/form-select';
import { Modal } from '@admin/components/ui/modal';
import { dashboardPersistentLayout } from '@admin/layouts/dashboard-page-layout';
import { Head } from '@inertiajs/react';
import { useMemo, useState } from 'react';

type AuditPresentedValue = {
    kind: 'text' | 'html' | 'empty';
    value: string;
};

type AuditChange = {
    key: string;
    field: string;
    type: string;
    old: AuditPresentedValue;
    new: AuditPresentedValue;
};

type AuditRow = {
    id: number;
    event: string;
    event_label: string;
    document_id: number;
    reference: string;
    user_name: string;
    summary: string;
    changes: AuditChange[];
    created_at: string | null;
};

type AuditTrailIndexProps = {
    audits: AuditRow[];
};

function isPresentedValue(value: unknown): value is AuditPresentedValue {
    return (
        typeof value === 'object' &&
        value !== null &&
        'kind' in value &&
        'value' in value &&
        typeof (value as { kind: unknown }).kind === 'string' &&
        typeof (value as { value: unknown }).value === 'string'
    );
}

function AuditValue({ value }: { value: unknown }) {
    if (!isPresentedValue(value)) {
        if (value === null || value === undefined || value === '') {
            return <span className="text-gray-400 dark:text-white/40">—</span>;
        }

        return <span className="audit-change-value">{String(value)}</span>;
    }

    if (value.kind === 'empty' || value.value === '') {
        return <span className="text-gray-400 dark:text-white/40">—</span>;
    }

    if (value.kind === 'html') {
        return (
            <div
                className="audit-change-value document-rich-text"
                dangerouslySetInnerHTML={{ __html: value.value }}
            />
        );
    }

    return <span className="audit-change-value">{value.value}</span>;
}

function formatAuditWhen(value: string | null): { date: string; time: string } {
    if (!value) {
        return { date: 'Unknown date', time: '' };
    }

    const occurred = new Date(value);

    if (Number.isNaN(occurred.getTime())) {
        return { date: value, time: '' };
    }

    return {
        date: occurred.toLocaleDateString(undefined, {
            month: 'short',
            day: 'numeric',
            year: 'numeric',
        }),
        time: occurred.toLocaleTimeString(undefined, {
            hour: 'numeric',
            minute: '2-digit',
            second: '2-digit',
        }),
    };
}

function AuditTrailIndex({ audits }: AuditTrailIndexProps) {
    const [eventFilter, setEventFilter] = useState('');
    const [selected, setSelected] = useState<AuditRow | null>(null);
    const selectedWhen = formatAuditWhen(selected?.created_at ?? null);

    const filteredAudits = useMemo(
        () => (eventFilter === '' ? audits : audits.filter((row) => row.event === eventFilter)),
        [audits, eventFilter],
    );

    const columns: DataTableColumn<AuditRow>[] = [
        {
            header: 'When',
            key: 'created_at',
            className: 'w-36',
            truncate: false,
            render: (row) => {
                const occurred = formatAuditWhen(row.created_at);

                return (
                    <span className="block leading-tight">
                        <span className="block whitespace-nowrap">{occurred.date}</span>
                        {occurred.time ? (
                            <span className="block whitespace-nowrap text-xs text-gray-500 dark:text-white/60">
                                {occurred.time}
                            </span>
                        ) : null}
                    </span>
                );
            },
        },
        { header: 'Action', key: 'event_label', className: 'w-32 whitespace-nowrap', truncate: false },
        { header: 'Document', key: 'reference', truncate: true, className: 'w-28 max-w-[7.5rem]' },
        {
            header: 'Who',
            key: 'user_name',
            truncate: false,
            className: 'min-w-[11rem] max-w-[16rem]',
            render: (row) => <span className="block whitespace-normal break-words leading-tight">{row.user_name}</span>,
        },
        { header: 'What changed', key: 'summary', truncate: true },
    ];

    return (
        <>
            <Head title="Audit trail" />

            <div className="grid grid-cols-12 gap-6">
                <div className="col-span-12">
                    <p className="mb-4 text-sm text-gray-500 dark:text-white/70">
                        Create, edit, and delete history for documentations. Older actions from before this log was
                        enabled are not included.
                    </p>
                    <div className="mb-4 grid grid-cols-12 gap-4">
                        <div className="col-span-12 sm:col-span-4 lg:col-span-3">
                            <FormSelect
                                label="Action"
                                value={eventFilter}
                                placeholder="All actions"
                                sortAlphabetically={false}
                                options={[
                                    { value: 'created', label: 'Created' },
                                    { value: 'updated', label: 'Edited' },
                                    { value: 'deleted', label: 'Deleted' },
                                ]}
                                onChange={setEventFilter}
                            />
                        </div>
                    </div>
                    <DataTable
                        data={filteredAudits}
                        columns={columns}
                        title="Documentation audit trail"
                        itemsPerPage={10}
                        onView={setSelected}
                        showView
                        showEdit={false}
                        noDataText="No documentation changes recorded yet"
                    />
                </div>
            </div>

            <Modal
                isOpen={selected !== null}
                onClose={() => setSelected(null)}
                title={selected ? `${selected.event_label}: ${selected.reference}` : 'Change details'}
                size="xl"
            >
                {selected && (
                    <div className="space-y-4">
                        <p className="mb-0 text-sm text-gray-500 dark:text-white/70">
                            {selected.user_name} · {selectedWhen.date}
                            {selectedWhen.time ? ` · ${selectedWhen.time}` : ''}
                        </p>
                        <div className="overflow-auto">
                            <table className="ti-custom-table audit-change-table w-full table-fixed">
                                <thead>
                                    <tr>
                                        <th className="w-[22%]">Field</th>
                                        {selected.event !== 'created' && <th>Before</th>}
                                        {selected.event !== 'deleted' && <th>After</th>}
                                    </tr>
                                </thead>
                                <tbody>
                                    {selected.changes.map((change) => (
                                        <tr key={change.key}>
                                            <td className="align-top font-medium break-words">{change.field}</td>
                                            {selected.event !== 'created' && (
                                                <td className="align-top">
                                                    <AuditValue value={change.old} />
                                                </td>
                                            )}
                                            {selected.event !== 'deleted' && (
                                                <td className="align-top">
                                                    <AuditValue value={change.new} />
                                                </td>
                                            )}
                                        </tr>
                                    ))}
                                </tbody>
                            </table>
                        </div>
                    </div>
                )}
            </Modal>
        </>
    );
}

export default Object.assign(AuditTrailIndex, {
    layout: dashboardPersistentLayout('Audit trail', 'Who created, edited, or deleted documentations'),
});
