import { usePage } from '@inertiajs/react';
import {
    Cell,
    ColumnDef,
    ColumnFiltersState,
    flexRender,
    getCoreRowModel,
    getFilteredRowModel,
    getSortedRowModel,
    Row,
    SortingState,
    useReactTable,
    VisibilityState,
} from '@tanstack/react-table';
import * as Icons from 'lucide-react';
import { MoreHorizontal } from 'lucide-react';
import { useMemo, useState } from 'react';

import { CreateAutomationRuleDialog } from '@/components/automation-rules/create-automation-rule-dialog';
import { DeleteAutomationRuleDialog } from '@/components/automation-rules/delete-automation-rule-dialog';
import { EditAutomationRuleDialog } from '@/components/automation-rules/edit-automation-rule-dialog';
import { LabelBadges } from '@/components/shared/label-combobox';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
    ContextMenu,
    ContextMenuContent,
    ContextMenuItem,
    ContextMenuLabel,
    ContextMenuTrigger,
} from '@/components/ui/context-menu';
import {
    Dialog,
    DialogContent,
    DialogDescription,
    DialogHeader,
    DialogTitle,
} from '@/components/ui/dialog';
import {
    DropdownMenu,
    DropdownMenuContent,
    DropdownMenuItem,
    DropdownMenuLabel,
    DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { Input } from '@/components/ui/input';
import {
    Table,
    TableBody,
    TableCell,
    TableHead,
    TableHeader,
    TableRow,
} from '@/components/ui/table';
import { useEncryptionKey } from '@/contexts/encryption-key-context';
import { type AutomationRule, getRuleActions } from '@/types/automation-rule';
import { type Category, getCategoryColorClasses } from '@/types/category';
import { type Label } from '@/types/label';

interface AutomationRulesDialogProps {
    open: boolean;
    onOpenChange: (open: boolean) => void;
}

function AutomationRuleActions({
    rule,
    categories,
    labels,
}: {
    rule: AutomationRule;
    categories: Category[];
    labels: Label[];
}) {
    const [editOpen, setEditOpen] = useState(false);
    const [deleteOpen, setDeleteOpen] = useState(false);

    return (
        <>
            <DropdownMenu>
                <DropdownMenuTrigger asChild>
                    <Button
                        variant="ghost"
                        className="h-8 w-8 p-0"
                        aria-label="Actions"
                    >
                        <span className="sr-only">Open menu</span>
                        <MoreHorizontal className="h-4 w-4" />
                    </Button>
                </DropdownMenuTrigger>
                <DropdownMenuContent align="end">
                    <DropdownMenuLabel>Actions</DropdownMenuLabel>
                    <DropdownMenuItem onClick={() => setEditOpen(true)}>
                        Edit
                    </DropdownMenuItem>
                    <DropdownMenuItem
                        onClick={() => setDeleteOpen(true)}
                        variant="destructive"
                    >
                        Delete
                    </DropdownMenuItem>
                </DropdownMenuContent>
            </DropdownMenu>

            <EditAutomationRuleDialog
                rule={rule}
                categories={categories}
                labels={labels}
                open={editOpen}
                onOpenChange={setEditOpen}
            />
            <DeleteAutomationRuleDialog
                rule={rule}
                open={deleteOpen}
                onOpenChange={setDeleteOpen}
            />
        </>
    );
}

function AutomationRuleRow({
    row,
    categories,
    labels,
}: {
    row: Row<AutomationRule>;
    categories: Category[];
    labels: Label[];
}) {
    const rule = row.original;
    const [editOpen, setEditOpen] = useState(false);
    const [deleteOpen, setDeleteOpen] = useState(false);
    const [contextMenuOpen, setContextMenuOpen] = useState(false);

    return (
        <>
            <ContextMenu onOpenChange={setContextMenuOpen}>
                <ContextMenuTrigger asChild>
                    <TableRow
                        data-state={
                            (row.getIsSelected() || contextMenuOpen) &&
                            'selected'
                        }
                    >
                        {row
                            .getVisibleCells()
                            .map((cell: Cell<AutomationRule, unknown>) => (
                                <TableCell key={cell.id}>
                                    {flexRender(
                                        cell.column.columnDef.cell,
                                        cell.getContext(),
                                    )}
                                </TableCell>
                            ))}
                    </TableRow>
                </ContextMenuTrigger>
                <ContextMenuContent>
                    <ContextMenuLabel>Actions</ContextMenuLabel>
                    <ContextMenuItem onClick={() => setEditOpen(true)}>
                        Edit
                    </ContextMenuItem>
                    <ContextMenuItem
                        onClick={() => setDeleteOpen(true)}
                        variant="destructive"
                    >
                        Delete
                    </ContextMenuItem>
                </ContextMenuContent>
            </ContextMenu>

            <EditAutomationRuleDialog
                rule={rule}
                categories={categories}
                labels={labels}
                open={editOpen}
                onOpenChange={setEditOpen}
            />
            <DeleteAutomationRuleDialog
                rule={rule}
                open={deleteOpen}
                onOpenChange={setDeleteOpen}
            />
        </>
    );
}

export function AutomationRulesDialog({
    open,
    onOpenChange,
}: AutomationRulesDialogProps) {
    const { isKeySet } = useEncryptionKey();
    const { automationRules: rawRules } = usePage<{
        automationRules: AutomationRule[];
    }>().props;

    // Get categories and labels from globally shared Inertia data
    const categories = usePage().props.categories as Category[];
    const labels = usePage().props.labels as Label[];
    const rules = useMemo(
        () =>
            rawRules.map((rule) => ({
                ...rule,
                rules_json:
                    typeof rule.rules_json === 'string'
                        ? JSON.parse(rule.rules_json)
                        : rule.rules_json,
            })),
        [rawRules],
    );
    const [sorting, setSorting] = useState<SortingState>([
        {
            id: 'priority',
            desc: false,
        },
    ]);
    const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
    const [columnVisibility, setColumnVisibility] = useState<VisibilityState>(
        {},
    );

    const columns: ColumnDef<AutomationRule>[] = [
        {
            accessorKey: 'priority',
            header: 'Priority',
            cell: ({ row }) => {
                return (
                    <div className="font-medium">
                        {row.getValue('priority')}
                    </div>
                );
            },
        },
        {
            accessorKey: 'title',
            header: 'Title',
            cell: ({ row }) => {
                return (
                    <div className="font-medium">{row.getValue('title')}</div>
                );
            },
        },
        {
            id: 'actions_display',
            header: 'Actions',
            cell: ({ row }) => {
                const rule = row.original;
                const actions = getRuleActions(rule);

                if (actions.type === 'multiple') {
                    return (
                        <div className="flex flex-wrap items-center gap-2">
                            {actions.category && (
                                <Badge
                                    className={`${getCategoryColorClasses(actions.category.color).bg} ${getCategoryColorClasses(actions.category.color).text} flex items-center gap-2`}
                                >
                                    {(() => {
                                        const IconComponent = Icons[
                                            actions.category
                                                .icon as keyof typeof Icons
                                        ] as Icons.LucideIcon;
                                        return IconComponent ? (
                                            <IconComponent className="h-3 w-3 opacity-80" />
                                        ) : null;
                                    })()}
                                    {actions.category.name}
                                </Badge>
                            )}
                            {actions.hasLabels && actions.labels && (
                                <LabelBadges labels={actions.labels} max={2} />
                            )}
                            {actions.hasNote && (
                                <span className="text-sm text-muted-foreground">
                                    + note
                                </span>
                            )}
                        </div>
                    );
                }

                if (actions.type === 'category' && actions.category) {
                    const colorClasses = getCategoryColorClasses(
                        actions.category.color,
                    );
                    const IconComponent = Icons[
                        actions.category.icon as keyof typeof Icons
                    ] as Icons.LucideIcon;
                    return (
                        <Badge
                            className={`${colorClasses.bg} ${colorClasses.text} flex items-center gap-2`}
                        >
                            <IconComponent className="h-3 w-3 opacity-80" />
                            {actions.category.name}
                        </Badge>
                    );
                }

                if (actions.type === 'labels' && actions.labels) {
                    return <LabelBadges labels={actions.labels} max={3} />;
                }

                return (
                    <span className="text-sm text-muted-foreground">
                        Add note
                    </span>
                );
            },
        },
        {
            id: 'actions',
            enableHiding: false,
            cell: ({ row }) => (
                <AutomationRuleActions
                    rule={row.original}
                    categories={categories}
                    labels={labels}
                />
            ),
        },
    ];

    const table = useReactTable({
        data: rules,
        columns,
        onSortingChange: setSorting,
        onColumnFiltersChange: setColumnFilters,
        getCoreRowModel: getCoreRowModel(),
        getSortedRowModel: getSortedRowModel(),
        getFilteredRowModel: getFilteredRowModel(),
        onColumnVisibilityChange: setColumnVisibility,
        state: {
            sorting,
            columnFilters,
            columnVisibility,
        },
    });

    return (
        <Dialog open={open} onOpenChange={onOpenChange}>
            <DialogContent className="sm:max-w-3xl">
                <DialogHeader>
                    <DialogTitle>Automation Rules</DialogTitle>
                    <DialogDescription>
                        Manage your transaction automation rules. Rules will be
                        applied to categorize transactions automatically.
                    </DialogDescription>
                </DialogHeader>

                <div className="space-y-4">
                    <div className="flex items-center justify-between">
                        <Input
                            placeholder="Filter rules...."
                            value={
                                (table
                                    .getColumn('title')
                                    ?.getFilterValue() as string) ?? ''
                            }
                            onChange={(event) =>
                                table
                                    .getColumn('title')
                                    ?.setFilterValue(event.target.value)
                            }
                            className="max-w-sm"
                        />
                        <CreateAutomationRuleDialog
                            categories={categories}
                            labels={labels}
                            disabled={!isKeySet}
                        />
                    </div>

                    <div className="max-h-[75vh] overflow-y-auto rounded-md border">
                        <Table>
                            <TableHeader>
                                {table.getHeaderGroups().map((headerGroup) => (
                                    <TableRow key={headerGroup.id}>
                                        {headerGroup.headers.map((header) => {
                                            return (
                                                <TableHead key={header.id}>
                                                    {header.isPlaceholder
                                                        ? null
                                                        : flexRender(
                                                              header.column
                                                                  .columnDef
                                                                  .header,
                                                              header.getContext(),
                                                          )}
                                                </TableHead>
                                            );
                                        })}
                                    </TableRow>
                                ))}
                            </TableHeader>
                            <TableBody>
                                {table.getRowModel().rows?.length ? (
                                    table
                                        .getRowModel()
                                        .rows.map((row) => (
                                            <AutomationRuleRow
                                                key={row.id}
                                                row={row}
                                                categories={categories}
                                                labels={labels}
                                            />
                                        ))
                                ) : (
                                    <TableRow>
                                        <TableCell
                                            colSpan={columns.length}
                                            className="h-24 text-center"
                                        >
                                            No automation rules found.
                                        </TableCell>
                                    </TableRow>
                                )}
                            </TableBody>
                        </Table>
                    </div>

                    <div className="flex items-center justify-end">
                        <div className="text-sm text-muted-foreground">
                            {table.getFilteredRowModel().rows.length} rule(s)
                            total.
                        </div>
                    </div>
                </div>
            </DialogContent>
        </Dialog>
    );
}
