"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { useRouter } from "next/navigation";
import useEntries from "@/hooks/use-entries";
import { useGroupsContext } from "@/hooks/groups-context";
import NewEntryModal from "@/components/new-entry-modal";
import EntryDetailsModal from "@/components/entry-details-modal";
import { useNotificationsContext } from "@/hooks/notifications-context";
import useTags from "@/hooks/use-tags";
import ConfirmSlideModal from "@/components/confirm-slide-modal";
import useGroupSettings from "@/hooks/use-group-settings";
import TagInput from "@/components/tag-input";
import { emitEntryMutated } from "@/lib/client/entry-mutation-events";

export default function EntriesPanel() {
    const today = new Date().toISOString().slice(0, 10);
    const { groups, activeGroupId } = useGroupsContext();
    const router = useRouter();
    const { entries, loading, error, createEntry, updateEntry, deleteEntry } = useEntries(activeGroupId);
    const { notify } = useNotificationsContext();
    const { tags: tagSuggestions } = useTags(activeGroupId);
    const { settings } = useGroupSettings(activeGroupId);
    const activeGroup = groups.find(group => group.id === activeGroupId) || null;
    const canManageTags = Boolean(activeGroup && (activeGroup.role !== "MEMBER" || settings.allowMemberTagManage));
    const emptyTagActionLabel = canManageTags
        ? "No Tags Assigned Yet - Click To Assign Tags"
        : "No Tags Assigned Yet - Contact Your Group Admin";
    const [form, setForm] = useState({
        amountDollars: "",
        occurredAt: today,
        necessity: "NECESSARY",
        notes: "",
        tags: [] as string[],
        entryType: "SPENDING" as "SPENDING" | "INCOME",
        isRecurring: false,
        frequency: "MONTHLY" as "DAILY" | "WEEKLY" | "BIWEEKLY" | "MONTHLY" | "QUARTERLY" | "YEARLY",
        intervalCount: 1,
        endCondition: "NEVER" as "NEVER" | "AFTER_COUNT" | "BY_DATE",
        endCount: "",
        endDate: ""
    });
    const [isModalOpen, setIsModalOpen] = useState(false);
    const [detailsOpen, setDetailsOpen] = useState(false);
    const [selectedId, setSelectedId] = useState<number | null>(null);
    const [selectedIndex, setSelectedIndex] = useState<number | null>(null);
    const [detailsForm, setDetailsForm] = useState({
        amountDollars: "",
        occurredAt: today,
        necessity: "NECESSARY",
        notes: "",
        tags: [] as string[],
        entryType: "SPENDING" as "SPENDING" | "INCOME",
        isRecurring: false,
        frequency: "MONTHLY" as "DAILY" | "WEEKLY" | "BIWEEKLY" | "MONTHLY" | "QUARTERLY" | "YEARLY",
        intervalCount: 1,
        endCondition: "NEVER" as "NEVER" | "AFTER_COUNT" | "BY_DATE",
        endCount: "",
        endDate: ""
    });
    const [detailsOriginal, setDetailsOriginal] = useState<typeof detailsForm | null>(null);
    const [removedTags, setRemovedTags] = useState<string[]>([]);
    const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);
    const [discardOpen, setDiscardOpen] = useState(false);
    const [filterOpen, setFilterOpen] = useState(false);
    const [entryTab, setEntryTab] = useState<"SINGLE" | "RECURRING">("SINGLE");
    const emptyFilters = {
        amountMin: "",
        amountMax: "",
        dateFrom: "",
        dateTo: "",
        necessity: "ANY",
        notesQuery: "",
        tags: [] as string[],
        tagsMode: "ANY" as "ANY" | "ALL"
    };
    const [filters, setFilters] = useState(emptyFilters);
    const amountInputRef = useRef<HTMLInputElement>(null);
    const tagsInputRef = useRef<HTMLInputElement>(null);
    const pendingDiscardRef = useRef<
        | { type: "close" }
        | { type: "prev" }
        | { type: "next" }
        | { type: "open"; entry: typeof entries[number]; index: number }
        | null
    >(null);
    const filteredEntries = useMemo(() => {
        if (!entries.length) return entries;
        const min = filters.amountMin ? Number(filters.amountMin) : null;
        const max = filters.amountMax ? Number(filters.amountMax) : null;
        const from = filters.dateFrom ? new Date(filters.dateFrom).getTime() : null;
        const to = filters.dateTo ? new Date(filters.dateTo).getTime() : null;
        const query = filters.notesQuery.trim().toLowerCase();
        const tagsFilter = filters.tags.map(tag => tag.toLowerCase());
        return entries.filter(entry => {
            if (min != null && entry.amountDollars < min) return false;
            if (max != null && entry.amountDollars > max) return false;
            if (from != null) {
                const time = new Date(entry.occurredAt).getTime();
                if (!Number.isNaN(from) && time < from) return false;
            }
            if (to != null) {
                const time = new Date(entry.occurredAt).getTime();
                if (!Number.isNaN(to) && time > to + 24 * 60 * 60 * 1000 - 1) return false;
            }
            if (filters.necessity !== "ANY" && entry.necessity !== filters.necessity) return false;
            if (query) {
                const notes = (entry.notes || "").toLowerCase();
                if (!notes.includes(query)) return false;
            }
            if (tagsFilter.length) {
                const entryTags = (entry.tags || []).map(tag => tag.toLowerCase());
                if (filters.tagsMode === "ALL") {
                    if (!tagsFilter.every(tag => entryTags.includes(tag))) return false;
                } else if (!tagsFilter.some(tag => entryTags.includes(tag))) return false;
            }
            return true;
        });
    }, [entries, filters]);
    const visibleEntries = useMemo(() => filteredEntries.filter(entry => entry.isRecurring === (entryTab === "RECURRING")), [filteredEntries, entryTab]);
    const totalEntries = visibleEntries.length;
    const activeFilterCount = useMemo(() => {
        let count = 0;
        if (filters.amountMin) count += 1;
        if (filters.amountMax) count += 1;
        if (filters.dateFrom) count += 1;
        if (filters.dateTo) count += 1;
        if (filters.necessity !== "ANY") count += 1;
        if (filters.notesQuery.trim()) count += 1;
        if (filters.tags.length) count += 1;
        return count;
    }, [filters]);

    function handleEmptyTagAction() {
        if (!activeGroupId || !canManageTags) return;
        router.push("/groups/settings");
    }

    useEffect(() => {
        if (tagsInputRef.current)
            tagsInputRef.current.setCustomValidity(form.tags.length ? "" : "Please fill out this field");
    }, [form.tags.length]);

    useEffect(() => {
        if (!filterOpen && !discardOpen) return;
        function handleKeyDown(event: KeyboardEvent) {
            if (event.key === "Escape") {
                if (discardOpen) handleCancelDiscard();
                if (filterOpen) setFilterOpen(false);
            }
        }
        window.addEventListener("keydown", handleKeyDown);
        return () => window.removeEventListener("keydown", handleKeyDown);
    }, [discardOpen, filterOpen]);

    async function handleCreate(e: React.FormEvent<HTMLFormElement>) {
        e.preventDefault();
        if (tagsInputRef.current)
            tagsInputRef.current.setCustomValidity(form.tags.length ? "" : "Please fill out this field");
        if (!e.currentTarget.reportValidity()) {
            if (!form.amountDollars) amountInputRef.current?.focus();
            else if (!form.tags.length) tagsInputRef.current?.focus();
            return;
        }
        const amountDollars = Number(form.amountDollars || 0);
        if (!Number.isFinite(amountDollars) || amountDollars <= 0) {
            return;
        }
        if (!form.occurredAt) {
            return;
        }
        if (!form.tags.length) {
            return;
        }

        const purchaseType = form.tags.join(", ") || "General";

        const nextRunAt = form.isRecurring ? form.occurredAt : null;
        const createdEntry = await createEntry({
            entryType: form.entryType,
            amountDollars,
            occurredAt: form.occurredAt,
            necessity: form.necessity as "NECESSARY" | "BOTH" | "UNNECESSARY",
            purchaseType,
            notes: form.notes.trim() || undefined,
            tags: form.tags,
            isRecurring: form.isRecurring,
            frequency: form.isRecurring ? form.frequency : null,
            intervalCount: form.intervalCount,
            endCondition: form.isRecurring ? form.endCondition : null,
            endCount: form.endCondition === "AFTER_COUNT" ? Number(form.endCount || 0) || null : null,
            endDate: form.endCondition === "BY_DATE" ? form.endDate || null : null,
            nextRunAt
        });
        if (createdEntry) {
            setForm({
                amountDollars: "",
                occurredAt: today,
                necessity: "NECESSARY",
                notes: "",
                tags: [],
                entryType: "SPENDING",
                isRecurring: false,
                frequency: "MONTHLY",
                intervalCount: 1,
                endCondition: "NEVER",
                endCount: "",
                endDate: ""
            });
            setIsModalOpen(false);
            notify({
                title: "Entry added",
                message: `${form.tags.join(", ")} · $${amountDollars.toFixed(2)}`,
                tone: "success"
            });
            emitEntryMutated({ before: null, after: createdEntry });
        }
    }

    function setDetailsFromEntry(entry: typeof entries[number], index: number) {
        const nextId = Number(entry.id);
        if (!Number.isFinite(nextId) || nextId <= 0) {
            alert("Invalid entry id");
            return;
        }
        const nextForm = {
            amountDollars: String(entry.amountDollars),
            occurredAt: new Date(entry.occurredAt).toISOString().slice(0, 10),
            necessity: entry.necessity,
            notes: entry.notes || "",
            tags: entry.tags || [],
            entryType: entry.entryType,
            isRecurring: entry.isRecurring,
            frequency: entry.frequency || "MONTHLY",
            intervalCount: entry.intervalCount || 1,
            endCondition: entry.endCondition || "NEVER",
            endCount: entry.endCount ? String(entry.endCount) : "",
            endDate: entry.endDate || ""
        };
        setSelectedId(nextId);
        setSelectedIndex(index);
        setRemovedTags([]);
        setDetailsForm(nextForm);
        setDetailsOriginal(nextForm);
        setDetailsOpen(true);
    }

    function handleOpenDetails(entry: typeof entries[number], index: number) {
        requestDiscard({ type: "open", entry, index });
    }

    function normalizeTags(tags: string[]) {
        return tags.map(tag => tag.toLowerCase()).sort();
    }

    function handleFilterAddTag(tag: string) {
        setFilters(prev => (prev.tags.includes(tag) ? prev : { ...prev, tags: [...prev.tags, tag] }));
    }

    function handleFilterToggleTag(tag: string) {
        setFilters(prev => ({ ...prev, tags: prev.tags.filter(item => item !== tag) }));
    }

    function handleClearFilters() {
        setFilters(emptyFilters);
    }
    function hasDetailsChanges() {
        if (!detailsOriginal) return false;
        const currentTags = detailsForm.tags.filter(tag => !removedTags.includes(tag));
        const currentTagsKey = normalizeTags(currentTags).join("|");
        const originalTagsKey = normalizeTags(detailsOriginal.tags).join("|");
        return (
            detailsForm.amountDollars !== detailsOriginal.amountDollars ||
            detailsForm.occurredAt !== detailsOriginal.occurredAt ||
            detailsForm.necessity !== detailsOriginal.necessity ||
            detailsForm.notes !== detailsOriginal.notes ||
            detailsForm.entryType !== detailsOriginal.entryType ||
            detailsForm.isRecurring !== detailsOriginal.isRecurring ||
            detailsForm.frequency !== detailsOriginal.frequency ||
            detailsForm.intervalCount !== detailsOriginal.intervalCount ||
            detailsForm.endCondition !== detailsOriginal.endCondition ||
            detailsForm.endCount !== detailsOriginal.endCount ||
            detailsForm.endDate !== detailsOriginal.endDate ||
            currentTagsKey !== originalTagsKey
        );
    }

    function requestDiscard(action: NonNullable<typeof pendingDiscardRef.current>) {
        if (!detailsOpen || !hasDetailsChanges()) {
            runDiscardAction(action);
            return;
        }
        pendingDiscardRef.current = action;
        setDiscardOpen(true);
    }

    function runDiscardAction(action: NonNullable<typeof pendingDiscardRef.current>) {
        if (action.type === "close") {
            setDetailsOpen(false);
            setDetailsOriginal(null);
            setRemovedTags([]);
            return;
        }
        if (action.type === "open") {
            setDetailsFromEntry(action.entry, action.index);
            return;
        }
        if (!totalEntries) return;
        const current = selectedIndex ?? 0;
        if (action.type === "prev") {
            const nextIndex = current === 0 ? totalEntries - 1 : current - 1;
            setDetailsFromEntry(visibleEntries[nextIndex], nextIndex);
        }
        if (action.type === "next") {
            const nextIndex = current === totalEntries - 1 ? 0 : current + 1;
            setDetailsFromEntry(visibleEntries[nextIndex], nextIndex);
        }
    }

    async function handleUpdate(e: React.FormEvent<HTMLFormElement>) {
        e.preventDefault();
        if (!selectedId) return;
        if (!hasDetailsChanges()) return;

        const amountDollars = Number(detailsForm.amountDollars || 0);
        if (!Number.isFinite(amountDollars) || amountDollars <= 0) {
            alert("Enter a valid amount");
            return;
        }
        if (!detailsForm.occurredAt) {
            alert("Select a date");
            return;
        }
        const nextTags = detailsForm.tags.filter(tag => !removedTags.includes(tag));
        if (!nextTags.length) {
            alert("Add at least one tag");
            return;
        }

        const purchaseType = nextTags.join(", ") || "General";

        const nextRunAt = detailsForm.isRecurring ? detailsForm.occurredAt : null;
        const beforeEntry = entries.find(entry => Number(entry.id) === Number(selectedId)) || null;
        const updatedEntry = await updateEntry({
            id: selectedId,
            entryType: detailsForm.entryType,
            amountDollars,
            occurredAt: detailsForm.occurredAt,
            necessity: detailsForm.necessity as "NECESSARY" | "BOTH" | "UNNECESSARY",
            purchaseType,
            notes: detailsForm.notes.trim() || undefined,
            tags: nextTags,
            isRecurring: detailsForm.isRecurring,
            frequency: detailsForm.isRecurring ? detailsForm.frequency : null,
            intervalCount: detailsForm.intervalCount,
            endCondition: detailsForm.isRecurring ? detailsForm.endCondition : null,
            endCount: detailsForm.endCondition === "AFTER_COUNT" ? Number(detailsForm.endCount || 0) || null : null,
            endDate: detailsForm.endCondition === "BY_DATE" ? detailsForm.endDate || null : null,
            nextRunAt
        });
        if (updatedEntry) {
            setDetailsOpen(false);
            setDetailsOriginal(null);
            setRemovedTags([]);
            notify({
                title: "Entry updated",
                message: `${nextTags.join(", ")} · $${amountDollars.toFixed(2)}`
            });
            emitEntryMutated({ before: beforeEntry, after: updatedEntry });
        }
    }

    async function handleDelete() {
        if (!selectedId || !Number.isFinite(selectedId)) return;
        const beforeEntry = entries.find(entry => Number(entry.id) === Number(selectedId)) || null;
        const deletedEntry = await deleteEntry(selectedId);
        if (deletedEntry || beforeEntry) {
            setDetailsOpen(false);
            setDetailsOriginal(null);
            setRemovedTags([]);
            notify({
                title: "Entry deleted",
                message: detailsForm.tags.join(", ") || "Entry removed",
                tone: "danger"
            });
            emitEntryMutated({ before: deletedEntry || beforeEntry, after: null });
        }
    }

    function handleToggleTag(tag: string) {
        setRemovedTags(prev => prev.includes(tag) ? prev.filter(item => item !== tag) : [...prev, tag]);
    }

    function handleAddTag(tag: string) {
        setDetailsForm(prev => ({ ...prev, tags: prev.tags.includes(tag) ? prev.tags : [...prev.tags, tag] }));
        setRemovedTags(prev => prev.filter(item => item !== tag));
    }

    function handlePrev() {
        if (!totalEntries) return;
        requestDiscard({ type: "prev" });
    }

    function handleNext() {
        if (!totalEntries) return;
        requestDiscard({ type: "next" });
    }

    function handleCloseDetails() {
        requestDiscard({ type: "close" });
    }

    function handleConfirmDiscard() {
        const action = pendingDiscardRef.current;
        pendingDiscardRef.current = null;
        setDiscardOpen(false);
        if (action) runDiscardAction(action);
    }

    function handleCancelDiscard() {
        pendingDiscardRef.current = null;
        setDiscardOpen(false);
    }

    function handleRevertDetails() {
        if (!detailsOriginal) return;
        setDetailsForm(detailsOriginal);
        setRemovedTags([]);
    }

    return (
        <>
            <div className="space-y-4">
                <div className="panel panel-accent p-4">
                    <div className="card-header">
                        <div className="flex flex-wrap items-center gap-3">
                            <h2 className="card-title text-lg">Entries</h2>
                            <div className="flex items-center gap-0 rounded-full border border-accent-weak bg-panel">
                                <button
                                    type="button"
                                    className={`mr-[-10px] w-20 rounded-full px-3 py-2 text-xs font-semibold ${entryTab === "SINGLE" ? "btn-accent" : "text-muted"}`}
                                    onClick={() => setEntryTab(prev => prev === "SINGLE" ? "RECURRING" : "SINGLE")}
                                >
                                    Existing
                                </button>
                                <button
                                    type="button"
                                    className={`rounded-full w-20 px-3 py-2 text-xs font-semibold ${entryTab === "RECURRING" ? "btn-accent" : "text-muted"}`}
                                    onClick={() => setEntryTab(prev => prev === "RECURRING" ? "SINGLE" : "RECURRING")}
                                >
                                    Scheduled
                                </button>
                            </div>
                        </div>
                        <div className="flex items-center gap-2">
                            <button
                                type="button"
                                onClick={() => setFilterOpen(true)}
                                className="rounded-lg btn-outline-accent px-3 py-1 text-xs font-semibold disabled:opacity-50"
                                disabled={!activeGroupId}
                            >
                                Filters{activeFilterCount ? ` (${activeFilterCount})` : ""}
                            </button>
                            <button
                                type="button"
                                onClick={() => setIsModalOpen(true)}
                                className="flex h-8 w-8 -translate-y-0.5 items-center justify-center rounded-full border border-accent bg-panel text-lg font-semibold leading-none hover:border-accent-strong disabled:opacity-50"
                                disabled={!activeGroupId}
                                aria-label="Add entry"
                            >
                                +
                            </button>
                        </div>
                    </div>
                    <div className="mt-3 space-y-2">
                        {!activeGroupId ? (
                            <div className="text-sm text-muted">Select a group to view entries.</div>
                        ) : loading ? (
                            <div className="space-y-2">
                                {[0, 1, 2].map(row => (
                                    <div key={row} className="rounded-lg border border-accent-weak bg-panel px-3 py-3">
                                        <div className="animate-pulse space-y-2">
                                            <div className="h-4 w-28 rounded bg-surface" />
                                            <div className="h-3 w-40 rounded bg-surface" />
                                            <div className="flex flex-wrap gap-2">
                                                <div className="h-5 w-14 rounded-full bg-surface" />
                                                <div className="h-5 w-12 rounded-full bg-surface" />
                                                <div className="h-5 w-16 rounded-full bg-surface" />
                                            </div>
                                        </div>
                                    </div>
                                ))}
                            </div>
                        ) : entries.length ? (
                            visibleEntries.length ? (
                                visibleEntries.map((entry, index) => {
                                    const tags = entry.tags ?? [];
                                    const mobileTagLimit = 2;
                                    const mobileTags = tags.slice(0, mobileTagLimit);
                                    const extraTagCount = Math.max(tags.length - mobileTagLimit, 0);

                                    return (
                                        <div
                                            key={entry.id}
                                            className="flex items-center justify-between rounded-lg border border-accent-weak bg-panel px-3 py-2 text-sm transition hover:border-accent hover:bg-accent-soft"
                                            onClick={() => handleOpenDetails(entry, index)}
                                        >
                                            <div className="flex flex-col gap-1">
                                                <div className="text-base font-semibold">${entry.amountDollars.toFixed(2)}</div>
                                                <div className="text-xs text-muted">
                                                    {new Date(entry.occurredAt).toISOString().slice(0, 10)} · {entry.necessity}
                                                </div>
                                            </div>
                                            {tags.length ? (
                                                <>
                                                    <div className="flex flex-wrap justify-end gap-2 md:hidden">
                                                        {mobileTags.map(tag => (
                                                            <span key={tag} className="rounded-full border border-accent-weak bg-accent-soft px-2 py-0.5 text-xs">
                                                                #{tag}
                                                            </span>
                                                        ))}
                                                        {extraTagCount ? (
                                                            <span className="rounded-full border border-accent-weak bg-panel px-2 py-0.5 text-xs text-soft">
                                                                {extraTagCount} more...
                                                            </span>
                                                        ) : null}
                                                    </div>
                                                    <div className="hidden flex-wrap justify-end gap-2 md:flex">
                                                        {tags.map(tag => (
                                                            <span key={tag} className="rounded-full border border-accent-weak bg-accent-soft px-2 py-0.5 text-xs">
                                                                #{tag}
                                                            </span>
                                                        ))}
                                                    </div>
                                                </>
                                            ) : (
                                                <span className="rounded-full border border-accent-weak px-2 py-0.5 text-xs text-soft">No tags</span>
                                            )}
                                        </div>
                                    );
                                })
                            ) : (
                                <div className="space-y-2 text-sm text-muted">
                                    <div>No matching entries.</div>
                                    {activeFilterCount ? (
                                        <button type="button" className="rounded-lg btn-outline-accent px-3 py-1 text-xs" onClick={handleClearFilters}>
                                            Clear filters
                                        </button>
                                    ) : null}
                                </div>
                            )
                        ) : (
                            <div className="text-sm text-muted">No entries yet.</div>
                        )}
                    </div>
                </div>
            </div>
            <NewEntryModal
                isOpen={isModalOpen && Boolean(activeGroupId)}
                form={form}
                error={error}
                onClose={() => setIsModalOpen(false)}
                onSubmit={handleCreate}
                onChange={next => setForm(prev => ({ ...prev, ...next }))}
                tagSuggestions={tagSuggestions}
                emptyTagActionLabel={emptyTagActionLabel}
                emptyTagActionDisabled={!canManageTags}
                onEmptyTagAction={handleEmptyTagAction}
                amountInputRef={amountInputRef}
                tagsInputRef={tagsInputRef}
            />
            <EntryDetailsModal
                isOpen={detailsOpen}
                form={detailsForm}
                originalForm={detailsOriginal}
                isDirty={hasDetailsChanges()}
                error={error}
                onClose={handleCloseDetails}
                onSubmit={handleUpdate}
                onRequestDelete={() => setConfirmDeleteOpen(true)}
                onRevert={handleRevertDetails}
                onChange={next => setDetailsForm(prev => ({ ...prev, ...next }))}
                onAddTag={handleAddTag}
                onToggleTag={handleToggleTag}
                removedTags={removedTags}
                tagSuggestions={tagSuggestions}
                emptyTagActionLabel={emptyTagActionLabel}
                emptyTagActionDisabled={!canManageTags}
                onEmptyTagAction={handleEmptyTagAction}
                onPrev={handlePrev}
                onNext={handleNext}
                loopHintPrev={selectedIndex === 0 && totalEntries > 1 ? "Loop" : ""}
                loopHintNext={selectedIndex === totalEntries - 1 && totalEntries > 1 ? "Loop" : ""}
                canNavigate={totalEntries > 1}
            />
            {filterOpen ? (
                <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4 !mt-0" onClick={() => setFilterOpen(false)}>
                    <div
                        className="w-full max-w-xl rounded-xl border border-accent-weak bg-panel p-4"
                        onClick={event => event.stopPropagation()}
                        onKeyDown={event => {
                            if (event.key === "Escape") setFilterOpen(false);
                        }}
                        role="dialog"
                        tabIndex={-1}
                    >
                        <div className="flex items-center justify-between">
                            <h2 className="text-lg font-semibold">Filter Entries</h2>
                            <div className="flex items-center gap-2">
                                <button
                                    type="button"
                                    onClick={() => setFilterOpen(false)}
                                    className="rounded-lg btn-outline-accent px-2 py-1 text-sm"
                                    aria-label="Close"
                                >
                                    ✕
                                </button>
                            </div>
                        </div>
                        <div className="mt-3 grid gap-3 md:grid-cols-2">
                            <label className="text-sm text-muted md:col-span-2">
                                Amount Range
                                <div className="mt-1 flex items-center gap-2">
                                    <input
                                        type="number"
                                        min={0}
                                        step="0.01"
                                        className="w-full input-base px-3 py-2 text-sm"
                                        value={filters.amountMin}
                                        placeholder="none"
                                        onChange={e => setFilters(prev => ({ ...prev, amountMin: e.target.value }))}
                                    />
                                    <span className="text-xs text-soft">-</span>
                                    <input
                                        type="number"
                                        min={0}
                                        step="0.01"
                                        className="w-full input-base px-3 py-2 text-sm"
                                        value={filters.amountMax}
                                        placeholder="none"
                                        onChange={e => setFilters(prev => ({ ...prev, amountMax: e.target.value }))}
                                    />
                                </div>
                            </label>
                            <label className="text-sm text-muted md:col-span-2">
                                Date Range
                                <div className="mt-1 flex items-center gap-2">
                                    <input
                                        type="date"
                                        className="no-date-icon w-full input-base px-3 py-2 text-sm"
                                        value={filters.dateFrom}
                                        placeholder="none"
                                        onChange={e => setFilters(prev => ({ ...prev, dateFrom: e.target.value }))}
                                    />
                                    <span className="text-xs text-soft">-</span>
                                    <input
                                        type="date"
                                        className="no-date-icon w-full input-base px-3 py-2 text-sm"
                                        value={filters.dateTo}
                                        placeholder="none"
                                        onChange={e => setFilters(prev => ({ ...prev, dateTo: e.target.value }))}
                                    />
                                </div>
                            </label>
                            <div className="text-sm text-muted">
                                <div className="mt-1 flex items-center gap-2 rounded-full border border-accent-weak bg-panel" role="group" aria-label="Necessity">
                                    {([
                                        { value: "ANY", label: "Any" },
                                        { value: "NECESSARY", label: "Necessary" },
                                        { value: "BOTH", label: "Both" },
                                        { value: "UNNECESSARY", label: "Unnecessary" }
                                    ] as const).map(option => (
                                        <button
                                            key={option.value}
                                            type="button"
                                            className={`rounded-full px-3 py-2 text-xs font-semibold ${filters.necessity === option.value ? "btn-accent" : "text-muted"}`}
                                            onClick={() => setFilters(prev => ({ ...prev, necessity: prev.necessity === option.value ? "ANY" : option.value }))}
                                        >
                                            {option.label}
                                        </button>
                                    ))}
                                </div>
                            </div>
                            <label className="text-sm text-muted">
                                Notes contains
                                <input
                                    type="text"
                                    className="mt-1 w-full input-base px-3 py-2 text-sm"
                                    value={filters.notesQuery}
                                    onChange={e => setFilters(prev => ({ ...prev, notesQuery: e.target.value }))}
                                />
                            </label>
                        </div>
                        <div className="mt-3 space-y-3">
                            <TagInput
                                label="Tags"
                                labelAction={
                                    <div className="flex items-center gap-1 rounded-full border border-accent-weak bg-panel">
                                        <button
                                            type="button"
                                            className={`rounded-full px-3 py-2 text-xs font-semibold ${filters.tagsMode === "ANY" ? "btn-accent" : "text-muted"}`}
                                            onClick={() => setFilters(prev => ({ ...prev, tagsMode: prev.tagsMode === "ANY" ? "ALL" : "ANY" }))}
                                        >
                                            Any
                                        </button>
                                        <button
                                            type="button"
                                            className={`rounded-full px-3 py-2 text-xs font-semibold ${filters.tagsMode === "ALL" ? "btn-accent" : "text-muted"}`}
                                            onClick={() => setFilters(prev => ({ ...prev, tagsMode: prev.tagsMode === "ALL" ? "ANY" : "ALL" }))}
                                        >
                                            All
                                        </button>
                                    </div>
                                }
                                tags={filters.tags}
                                suggestions={tagSuggestions}
                                allowCustom={false}
                                onToggleTag={handleFilterToggleTag}
                                onAddTag={handleFilterAddTag}
                                emptySuggestionLabel={emptyTagActionLabel}
                                emptySuggestionDisabled={!canManageTags}
                                onEmptySuggestionClick={handleEmptyTagAction}
                            />
                        </div>
                        <div className="mt-4 flex items-center justify-between">
                            <div className="text-xs text-soft">
                                {activeFilterCount ? `${activeFilterCount} filter${activeFilterCount === 1 ? "" : "s"} applied` : "No filters applied"}
                            </div>
                            <div className="flex items-center gap-2">
                                <button type="button" className="rounded-lg btn-outline-accent px-3 py-2 text-xs" onClick={handleClearFilters}>
                                    Clear Filters
                                </button>
                                <button type="button" className="rounded-lg btn-accent px-3 py-2 text-xs" onClick={() => setFilterOpen(false)}>
                                    Apply
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
            ) : null}
            {discardOpen ? (
                <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4">
                    <div
                        className="w-full max-w-sm rounded-2xl border border-accent-weak bg-panel p-5 shadow-xl"
                        onKeyDown={event => {
                            if (event.key === "Escape") handleCancelDiscard();
                        }}
                        role="dialog"
                        tabIndex={-1}
                    >
                        <div className="text-lg font-semibold">Discard changes?</div>
                        <p className="mt-2 text-sm text-muted">You have unsaved changes. Do you want to discard them?</p>
                        <div className="mt-4 flex items-center gap-2">
                            <button
                                type="button"
                                className="flex-1 rounded-lg btn-outline-accent px-3 py-2 text-sm font-semibold"
                                onClick={handleCancelDiscard}
                            >
                                Keep editing
                            </button>
                            <button
                                type="button"
                                className="flex-1 rounded-lg border border-red-400/60 bg-red-500/10 px-3 py-2 text-sm font-semibold text-red-200"
                                onClick={handleConfirmDiscard}
                            >
                                Discard
                            </button>
                        </div>
                    </div>
                </div>
            ) : null}
            <ConfirmSlideModal
                isOpen={confirmDeleteOpen}
                title="Delete entry"
                description="This will permanently remove the entry and its tags."
                confirmLabel="Delete entry"
                onClose={() => setConfirmDeleteOpen(false)}
                onConfirm={() => {
                    setConfirmDeleteOpen(false);
                    handleDelete();
                }}
            />
        </>
    );
}
