import { ChevronDown } from 'lucide-react';
import { useMemo, useState } from 'react';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import {
    Collapsible,
    CollapsibleContent,
    CollapsibleTrigger,
} from '@/components/ui/collapsible';
import { Label } from '@/components/ui/label';
import { cn } from '@/lib/utils';

export type PermissionOption = {
    name: string;
    label: string;
};

export type PermissionGroup = {
    key: string;
    label: string;
    permissions: PermissionOption[];
};

type Props = {
    groups: PermissionGroup[];
    selected: string[];
    onChange: (selected: string[]) => void;
    disabled?: boolean;
    name?: string;
};

export function PermissionGroupsPicker({
    groups,
    selected,
    onChange,
    disabled = false,
    name = 'permissions[]',
}: Props) {
    const [openGroups, setOpenGroups] = useState<Record<string, boolean>>(
        () =>
            Object.fromEntries(groups.map((group) => [group.key, true])),
    );

    const selectedSet = useMemo(() => new Set(selected), [selected]);
    const totalCount = groups.reduce(
        (sum, group) => sum + group.permissions.length,
        0,
    );

    function togglePermission(permission: string, checked: boolean) {
        if (disabled) {
            return;
        }

        onChange(
            checked
                ? [...selected, permission]
                : selected.filter((value) => value !== permission),
        );
    }

    function toggleGroup(group: PermissionGroup, checked: boolean) {
        if (disabled) {
            return;
        }

        const names = group.permissions.map((permission) => permission.name);

        if (checked) {
            onChange([...new Set([...selected, ...names])]);

            return;
        }

        onChange(selected.filter((value) => !names.includes(value)));
    }

    function selectAll() {
        if (disabled) {
            return;
        }

        onChange(
            groups.flatMap((group) =>
                group.permissions.map((permission) => permission.name),
            ),
        );
    }

    function clearAll() {
        if (disabled) {
            return;
        }

        onChange([]);
    }

    return (
        <div className="space-y-4">
            <div className="flex flex-wrap items-center justify-between gap-3">
                <div>
                    <Label>Permissions</Label>
                    <p className="text-muted-foreground mt-1 text-xs">
                        {selected.length} / {totalCount} sélectionnée
                        {selected.length > 1 ? 's' : ''}
                    </p>
                </div>
                {!disabled && (
                    <div className="flex gap-2">
                        <Button
                            type="button"
                            variant="outline"
                            size="sm"
                            onClick={selectAll}
                        >
                            Tout sélectionner
                        </Button>
                        <Button
                            type="button"
                            variant="ghost"
                            size="sm"
                            onClick={clearAll}
                            disabled={selected.length === 0}
                        >
                            Tout désélectionner
                        </Button>
                    </div>
                )}
            </div>

            <div className="space-y-3">
                {groups.map((group) => {
                    const groupNames = group.permissions.map(
                        (permission) => permission.name,
                    );
                    const selectedInGroup = groupNames.filter((name) =>
                        selectedSet.has(name),
                    ).length;
                    const allSelected =
                        groupNames.length > 0 &&
                        selectedInGroup === groupNames.length;
                    const someSelected =
                        selectedInGroup > 0 && !allSelected;
                    const isOpen = openGroups[group.key] ?? true;

                    return (
                        <Collapsible
                            key={group.key}
                            open={isOpen}
                            onOpenChange={(open) =>
                                setOpenGroups((current) => ({
                                    ...current,
                                    [group.key]: open,
                                }))
                            }
                        >
                            <div className="overflow-hidden rounded-xl border bg-card">
                                <div className="flex items-center gap-3 border-b bg-muted/30 px-4 py-3">
                                    <Checkbox
                                        checked={
                                            allSelected
                                                ? true
                                                : someSelected
                                                  ? 'indeterminate'
                                                  : false
                                        }
                                        disabled={disabled}
                                        onCheckedChange={(checked) =>
                                            toggleGroup(
                                                group,
                                                checked === true,
                                            )
                                        }
                                        aria-label={`Tout sélectionner — ${group.label}`}
                                    />
                                    <CollapsibleTrigger asChild>
                                        <button
                                            type="button"
                                            className="flex min-w-0 flex-1 items-center justify-between gap-2 text-left"
                                        >
                                            <span className="min-w-0">
                                                <span className="block text-sm font-medium">
                                                    {group.label}
                                                </span>
                                                <span className="text-muted-foreground text-xs">
                                                    {selectedInGroup}/
                                                    {group.permissions.length}{' '}
                                                    permission
                                                    {group.permissions.length >
                                                    1
                                                        ? 's'
                                                        : ''}
                                                </span>
                                            </span>
                                            <ChevronDown
                                                className={cn(
                                                    'text-muted-foreground size-4 shrink-0 transition-transform',
                                                    isOpen && 'rotate-180',
                                                )}
                                            />
                                        </button>
                                    </CollapsibleTrigger>
                                </div>

                                <CollapsibleContent>
                                    <div className="grid gap-2 p-4 sm:grid-cols-2">
                                        {group.permissions.map(
                                            (permission) => {
                                                const isChecked =
                                                    selectedSet.has(
                                                        permission.name,
                                                    );

                                                return (
                                                    <label
                                                        key={permission.name}
                                                        className={cn(
                                                            'flex items-start gap-2 rounded-lg border border-transparent px-2 py-1.5 text-sm transition-colors',
                                                            !disabled &&
                                                                'hover:bg-muted/50 cursor-pointer',
                                                            disabled &&
                                                                'opacity-70',
                                                        )}
                                                    >
                                                        <Checkbox
                                                            className="mt-0.5"
                                                            checked={isChecked}
                                                            disabled={disabled}
                                                            onCheckedChange={(
                                                                checked,
                                                            ) =>
                                                                togglePermission(
                                                                    permission.name,
                                                                    checked ===
                                                                        true,
                                                                )
                                                            }
                                                        />
                                                        <span className="leading-snug">
                                                            {permission.label}
                                                        </span>
                                                        {!disabled &&
                                                            isChecked && (
                                                                <input
                                                                    type="hidden"
                                                                    name={name}
                                                                    value={
                                                                        permission.name
                                                                    }
                                                                />
                                                            )}
                                                    </label>
                                                );
                                            },
                                        )}
                                    </div>
                                </CollapsibleContent>
                            </div>
                        </Collapsible>
                    );
                })}
            </div>
        </div>
    );
}
