import { Badge } from '@/Components/ui/badge';
import { cn } from '@/lib/utils';
import { Option } from '@/types/admin';
import { Popover, PopoverButton, PopoverPanel } from '@headlessui/react';
import { Command } from 'cmdk';
import { Check, ImagePlus, Plus, Search, Trash2, Undo2, X } from 'lucide-react';
import { InputHTMLAttributes, ReactNode, useEffect, useMemo, useRef, useState } from 'react';

export const selectClass = 'h-10 w-full rounded-lg border border-input bg-card/60 px-3 text-sm outline-none transition focus:border-ring focus:ring-4 focus:ring-ring/15';

export function SearchInput({ value, onChange, placeholder = 'Search…' }: { value: string; onChange: (v: string) => void; placeholder?: string }) {
    return (
        <div className="relative w-full max-w-xs">
            <Search className="absolute left-3 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
            <input value={value} onChange={(e) => onChange(e.target.value)} placeholder={placeholder} aria-label={placeholder} maxLength={80} className="h-9 w-full rounded-lg border border-input bg-card/60 pl-9 pr-8 text-sm outline-none transition placeholder:text-muted-foreground/70 focus:border-ring focus:ring-4 focus:ring-ring/15" />
            {value && <button onClick={() => onChange('')} aria-label="Clear search" className="absolute right-2 top-1/2 -translate-y-1/2 rounded p-0.5 text-muted-foreground hover:text-foreground"><X className="size-3.5" /></button>}
        </div>
    );
}

export function Switch({ checked, onChange, label }: { checked: boolean; onChange: (v: boolean) => void; label: string }) {
    return (
        <button type="button" role="switch" aria-checked={checked} onClick={() => onChange(!checked)} className="flex w-full items-center justify-between gap-3 rounded-lg py-1 text-left text-sm">
            <span>{label}</span>
            <span className={cn('relative h-5 w-9 rounded-full border border-border transition', checked ? 'bg-primary' : 'bg-muted')}>
                <span className={cn('absolute top-0.5 size-4 rounded-full bg-white shadow transition-all', checked ? 'left-[18px]' : 'left-0.5')} />
            </span>
        </button>
    );
}

export function MultiSelectField({ options, value, onChange, placeholder }: { options: Option[]; value: number[]; onChange: (v: number[]) => void; placeholder: string }) {
    const byId = useMemo(() => new Map(options.map((o) => [o.id, o.name])), [options]);
    const toggle = (id: number) => onChange(value.includes(id) ? value.filter((v) => v !== id) : [...value, id]);
    return (
        <div className="space-y-2">
            <div className="flex flex-wrap gap-1.5">
                {value.map((id) => (
                    <Badge key={id} variant="default" className="gap-1 py-1 pl-2 pr-1 text-xs">
                        {byId.get(id) ?? id}
                        <button type="button" onClick={() => toggle(id)} aria-label={`Remove ${byId.get(id)}`} className="rounded p-0.5 hover:bg-foreground/10"><X className="size-3" /></button>
                    </Badge>
                ))}
            </div>
            <Popover className="relative inline-block">
                <PopoverButton className="inline-flex h-8 items-center gap-1.5 rounded-lg border border-dashed border-border px-2.5 text-sm text-muted-foreground outline-none transition hover:border-foreground/30 hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/60"><Plus className="size-3.5" />{placeholder}</PopoverButton>
                <PopoverPanel anchor="bottom start" className="glass z-50 overflow-hidden rounded-xl border border-border shadow-lift outline-none [--anchor-gap:6px]">
                    <Command label={placeholder} className="w-64">
                        <Command.Input autoFocus placeholder="Search…" className="h-10 w-full border-b border-border bg-transparent px-3 text-sm outline-none placeholder:text-muted-foreground/70" />
                        <Command.List className="max-h-64 overflow-y-auto p-1">
                            <Command.Empty className="px-3 py-6 text-center text-sm text-muted-foreground">No matches.</Command.Empty>
                            {options.map((o) => (
                                <Command.Item key={o.id} value={o.name} onSelect={() => toggle(o.id)} className="flex cursor-pointer items-center gap-2.5 rounded-md px-2.5 py-1.5 text-sm aria-selected:bg-accent">
                                    <span className={cn('flex size-4 items-center justify-center rounded border border-input', value.includes(o.id) && 'border-primary bg-primary text-primary-foreground')}>{value.includes(o.id) && <Check className="size-3" strokeWidth={3} />}</span>
                                    {o.name}
                                </Command.Item>
                            ))}
                        </Command.List>
                    </Command>
                </PopoverPanel>
            </Popover>
        </div>
    );
}

function usePreview(file: File | null) {
    const url = useMemo(() => (file ? URL.createObjectURL(file) : null), [file]);
    useEffect(() => () => { if (url) URL.revokeObjectURL(url); }, [url]);
    return url;
}

const ACCEPT = 'image/png,image/jpeg,image/webp';

export function ImageField({ label, hint, current, file, removed, onFile, onRemove, aspect = 'aspect-[3/4]', error }: { label: string; hint?: string; current: string | null; file: File | null; removed: boolean; onFile: (f: File | null) => void; onRemove: (r: boolean) => void; aspect?: string; error?: string }) {
    const ref = useRef<HTMLInputElement>(null);
    const preview = usePreview(file);
    const src = preview ?? (removed ? null : current);
    return (
        <div className="space-y-1.5">
            <p className="text-[13px] font-medium text-foreground/90">{label}</p>
            <div className={cn('group relative w-full overflow-hidden rounded-xl border border-dashed border-border bg-muted/40', aspect)}>
                {src ? <img src={src} alt="" className="size-full object-cover" /> : (
                    <button type="button" onClick={() => ref.current?.click()} className="flex size-full flex-col items-center justify-center gap-1.5 text-muted-foreground transition hover:text-foreground"><ImagePlus className="size-6" /><span className="text-xs">Upload image</span></button>
                )}
                {src && (
                    <div className="absolute inset-x-2 bottom-2 flex gap-1.5 opacity-0 transition group-hover:opacity-100 group-focus-within:opacity-100">
                        <button type="button" onClick={() => ref.current?.click()} className="glass flex-1 rounded-md border border-border py-1 text-xs">Replace</button>
                        <button type="button" onClick={() => { onFile(null); onRemove(true); }} aria-label={`Remove ${label}`} className="glass rounded-md border border-border px-2 py-1 text-destructive"><Trash2 className="size-3.5" /></button>
                    </div>
                )}
            </div>
            <input ref={ref} type="file" accept={ACCEPT} className="sr-only" onChange={(e) => { const f = e.target.files?.[0] ?? null; if (f) { onFile(f); onRemove(false); } e.target.value = ''; }} />
            {hint && <p className="text-caption">{hint}</p>}
            {error && <p role="alert" className="text-xs text-destructive">{error}</p>}
        </div>
    );
}

function Thumb({ src, children, dim }: { src: string; children: ReactNode; dim?: boolean }) {
    return (
        <div className="group relative aspect-video overflow-hidden rounded-lg border border-border bg-muted">
            <img src={src} alt="" className={cn('size-full object-cover transition', dim && 'opacity-30 grayscale')} />
            <div className="absolute right-1.5 top-1.5">{children}</div>
        </div>
    );
}
function NewThumb({ file, onRemove }: { file: File; onRemove: () => void }) {
    const url = usePreview(file)!;
    return <Thumb src={url}><button type="button" onClick={onRemove} aria-label="Remove new screenshot" className="glass rounded-md border border-border p-1"><X className="size-3.5" /></button></Thumb>;
}

export function ScreenshotsField({ existing, removeIds, onToggleRemove, files, onFiles, max = 12, error }: { existing: { id: number; thumb: string }[]; removeIds: number[]; onToggleRemove: (id: number) => void; files: File[]; onFiles: (f: File[]) => void; max?: number; error?: string }) {
    const ref = useRef<HTMLInputElement>(null);
    const kept = existing.length - removeIds.length + files.length;
    return (
        <div className="space-y-2">
            <div className="flex items-center justify-between"><p className="text-[13px] font-medium text-foreground/90">Screenshots</p><span className="text-caption">{kept}/{max}</span></div>
            <div className="grid grid-cols-2 gap-2 sm:grid-cols-3">
                {existing.map((s) => {
                    const gone = removeIds.includes(s.id);
                    return (
                        <Thumb key={s.id} src={s.thumb} dim={gone}>
                            <button type="button" onClick={() => onToggleRemove(s.id)} aria-label={gone ? 'Keep screenshot' : 'Remove screenshot'} className="glass rounded-md border border-border p-1">{gone ? <Undo2 className="size-3.5" /> : <Trash2 className="size-3.5 text-destructive" />}</button>
                        </Thumb>
                    );
                })}
                {files.map((f, i) => <NewThumb key={f.name + i} file={f} onRemove={() => onFiles(files.filter((_, j) => j !== i))} />)}
                {kept < max && (
                    <button type="button" onClick={() => ref.current?.click()} className="flex aspect-video items-center justify-center gap-1.5 rounded-lg border border-dashed border-border text-xs text-muted-foreground transition hover:text-foreground"><ImagePlus className="size-4" />Add</button>
                )}
            </div>
            <input ref={ref} type="file" multiple accept={ACCEPT} className="sr-only" onChange={(e) => { onFiles([...files, ...Array.from(e.target.files ?? [])].slice(0, max - (existing.length - removeIds.length))); e.target.value = ''; }} />
            {error && <p role="alert" className="text-xs text-destructive">{error}</p>}
        </div>
    );
}

export type { InputHTMLAttributes };
