import { Button } from '@/components/ui/button';
import { Calendar } from '@/components/ui/calendar';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { cn } from '@/utils/common';
import axios from 'axios';
import { CalendarIcon, Check, ChevronDown, RotateCcw, Search, SlidersHorizontal } from 'lucide-react';
import React, { useEffect, useRef, useState } from 'react';

// ─── Types ────────────────────────────────────────────────────────────────────

export interface FilterOption {
    value: string | number;
    label: string;
}

export interface FilterDefinition {
    key: string;
    type: 'date' | 'select' | 'multi_select' | 'async_select' | 'number_range' | 'text';
    label: string;
    options?: FilterOption[];
    default?: string;
    endpoint?: string;
}

export type FilterValues = Record<string, any>;

interface ReportFilterPanelProps {
    filters: FilterDefinition[];
    values: FilterValues;
    onChange: (values: FilterValues) => void;
    onRun: () => void;
    loading?: boolean;
}

type DateRangeFilter = {
    key: '__date_range__';
    type: 'date_range';
    fromKey: string;
    toKey: string;
};

type ProcessedFilter = FilterDefinition | DateRangeFilter;

function processFilters(filters: FilterDefinition[]): ProcessedFilter[] {
    const result: ProcessedFilter[] = [];
    const skip = new Set<string>();
    for (const f of filters) {
        if (skip.has(f.key)) continue;
        if (f.key === 'date_from' && filters.some((x) => x.key === 'date_to')) {
            result.push({ key: '__date_range__', type: 'date_range', fromKey: 'date_from', toKey: 'date_to' });
            skip.add('date_from');
            skip.add('date_to');
        } else {
            result.push(f);
        }
    }
    return result;
}

// ─── Sub-components ───────────────────────────────────────────────────────────

function DateRangeInput({
    fromValue,
    toValue,
    onFromChange,
    onToChange,
}: {
    fromValue: string;
    toValue: string;
    onFromChange: (v: string) => void;
    onToChange: (v: string) => void;
}) {
    const [open, setOpen] = useState(false);

    const from = fromValue ? new Date(fromValue + 'T00:00:00') : undefined;
    const to   = toValue   ? new Date(toValue   + 'T00:00:00') : undefined;

    const fmt = (d?: Date) =>
        d ? d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }) : '';

    const displayText =
        from || to ? `${fmt(from)}${to ? ' – ' + fmt(to) : ''}` : 'Select date range';

    return (
        <div className="flex flex-col gap-1">
            <Label className="text-xs font-medium text-[#6d7175]">Date Range</Label>
            <Popover open={open} onOpenChange={setOpen}>
                <PopoverTrigger asChild>
                    <button
                        type="button"
                        className="flex h-9 w-full items-center gap-2 rounded-md border border-input bg-background px-3 text-left text-sm transition-colors hover:bg-gray-50"
                    >
                        <CalendarIcon className="h-4 w-4 shrink-0 text-muted-foreground" />
                        <span className={cn('truncate', from || to ? 'text-[#202223]' : 'text-muted-foreground')}>
                            {displayText}
                        </span>
                    </button>
                </PopoverTrigger>
                <PopoverContent className="w-auto p-0" align="start">
                    <Calendar
                        mode="range"
                        selected={{ from, to } as any}
                        onSelect={(range: any) => {
                            onFromChange(range?.from ? (range.from as Date).toISOString().split('T')[0] : '');
                            onToChange(range?.to   ? (range.to   as Date).toISOString().split('T')[0] : '');
                            if (range?.from && range?.to) setOpen(false);
                        }}
                        numberOfMonths={2}
                    />
                    {(from || to) && (
                        <div className="border-t px-3 py-2">
                            <button
                                type="button"
                                onClick={() => { onFromChange(''); onToChange(''); setOpen(false); }}
                                className="text-xs text-[#6d7175] hover:text-red-500"
                            >
                                Clear dates
                            </button>
                        </div>
                    )}
                </PopoverContent>
            </Popover>
        </div>
    );
}

function DateInput({ value, onChange, label }: { value: string; onChange: (v: string) => void; label: string }) {
    return (
        <div className="flex flex-col gap-1">
            <Label className="text-xs font-medium text-[#6d7175]">{label}</Label>
            <Input type="date" value={value || ''} onChange={(e) => onChange(e.target.value)} className="h-9 text-sm" />
        </div>
    );
}

function SelectInput({
    value, onChange, label, options,
}: { value: string; onChange: (v: string) => void; label: string; options: FilterOption[] }) {
    return (
        <div className="flex flex-col gap-1">
            <Label className="text-xs font-medium text-[#6d7175]">{label}</Label>
            <Select value={value || '__all__'} onValueChange={(v) => onChange(v === '__all__' ? '' : v)}>
                <SelectTrigger className="h-9 text-sm">
                    <SelectValue placeholder={`All ${label}`} />
                </SelectTrigger>
                <SelectContent>
                    <SelectItem value="__all__">All</SelectItem>
                    {options.map((opt) => (
                        <SelectItem key={String(opt.value)} value={String(opt.value)}>
                            {opt.label}
                        </SelectItem>
                    ))}
                </SelectContent>
            </Select>
        </div>
    );
}

function MultiSelectInput({
    value, onChange, label, options,
}: { value: string[]; onChange: (v: string[]) => void; label: string; options: FilterOption[] }) {
    const [open, setOpen] = useState(false);
    const selected = Array.isArray(value) ? value : [];

    const toggle = (val: string) => {
        onChange(selected.includes(val) ? selected.filter((v) => v !== val) : [...selected, val]);
    };

    const getLabel = (val: string) => options.find((o) => String(o.value) === val)?.label ?? val;

    const CHIPS_LIMIT = 2;
    const hiddenCount = Math.max(0, selected.length - CHIPS_LIMIT);

    return (
        <div className="flex flex-col gap-1">
            <Label className="text-xs font-medium text-[#6d7175]">{label}</Label>
            <Popover open={open} onOpenChange={setOpen}>
                <PopoverTrigger asChild>
                    <button
                        type="button"
                        className="flex min-h-9 w-full flex-wrap items-center gap-1 rounded-md border border-input bg-background px-2 py-1.5 text-left text-sm transition-colors hover:bg-gray-50"
                    >
                        {selected.length === 0 ? (
                            <span className="px-1 text-sm text-muted-foreground">All {label}</span>
                        ) : (
                            <>
                                {selected.slice(0, CHIPS_LIMIT).map((v) => (
                                    <span
                                        key={v}
                                        className="inline-flex items-center gap-1 rounded bg-[#e3f1ef] px-2 py-0.5 text-xs font-medium text-[#008060]"
                                    >
                                        {getLabel(v)}
                                        <span
                                            role="button"
                                            tabIndex={-1}
                                            onClick={(e) => { e.stopPropagation(); toggle(v); }}
                                            className="cursor-pointer leading-none hover:text-red-500"
                                        >
                                            ×
                                        </span>
                                    </span>
                                ))}
                                {hiddenCount > 0 && (
                                    <span className="rounded bg-gray-100 px-2 py-0.5 text-xs text-[#6d7175]">
                                        +{hiddenCount} More
                                    </span>
                                )}
                            </>
                        )}
                        <ChevronDown className="ml-auto h-3.5 w-3.5 shrink-0 text-muted-foreground" />
                    </button>
                </PopoverTrigger>
                <PopoverContent className="w-52 p-1.5" align="start">
                    <div className="max-h-52 overflow-y-auto">
                        {options.map((opt) => {
                            const active = selected.includes(String(opt.value));
                            return (
                                <button
                                    key={String(opt.value)}
                                    type="button"
                                    onClick={() => toggle(String(opt.value))}
                                    className="flex w-full items-center gap-2.5 rounded px-2 py-1.5 text-left text-sm hover:bg-gray-50"
                                >
                                    <span
                                        className={cn(
                                            'flex h-4 w-4 shrink-0 items-center justify-center rounded border transition-colors',
                                            active ? 'border-[#008060] bg-[#008060]' : 'border-[#d8d8d8]',
                                        )}
                                    >
                                        {active && <Check className="h-3 w-3 text-white" />}
                                    </span>
                                    <span>{opt.label}</span>
                                </button>
                            );
                        })}
                    </div>
                    {selected.length > 0 && (
                        <div className="mt-1 border-t border-[#f0f0f0] pt-1.5">
                            <button
                                type="button"
                                onClick={() => { onChange([]); setOpen(false); }}
                                className="w-full rounded px-2 py-1 text-left text-xs text-[#6d7175] hover:text-red-500"
                            >
                                Clear all
                            </button>
                        </div>
                    )}
                </PopoverContent>
            </Popover>
        </div>
    );
}

function AsyncSelectInput({
    value, onChange, label, endpoint,
}: { value: string; onChange: (v: string, label?: string) => void; label: string; endpoint?: string }) {
    const [search, setSearch]           = useState('');
    const [results, setResults]         = useState<FilterOption[]>([]);
    const [open, setOpen]               = useState(false);
    const [selectedLabel, setSelectedLabel] = useState('');
    const debounceRef = useRef<ReturnType<typeof setTimeout>>();
    const wrapperRef  = useRef<HTMLDivElement>(null);

    useEffect(() => {
        if (!search || !endpoint) return;
        clearTimeout(debounceRef.current);
        debounceRef.current = setTimeout(async () => {
            try {
                const res  = await axios.get(route(endpoint), { params: { search } });
                const data = res.data?.data ?? res.data ?? [];
                setResults(Array.isArray(data) ? data : []);
            } catch {
                setResults([]);
            }
        }, 300);
    }, [search, endpoint]);

    useEffect(() => {
        const handler = (e: MouseEvent) => {
            if (wrapperRef.current && !wrapperRef.current.contains(e.target as Node)) setOpen(false);
        };
        document.addEventListener('mousedown', handler);
        return () => document.removeEventListener('mousedown', handler);
    }, []);

    const handleSelect = (opt: FilterOption) => {
        onChange(String(opt.value), opt.label);
        setSelectedLabel(opt.label);
        setSearch('');
        setOpen(false);
    };

    const handleClear = () => { onChange(''); setSelectedLabel(''); setSearch(''); };

    return (
        <div className="flex flex-col gap-1" ref={wrapperRef}>
            <Label className="text-xs font-medium text-[#6d7175]">{label}</Label>
            <div className="relative">
                <Search className="absolute top-1/2 left-2.5 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
                <Input
                    value={selectedLabel || search}
                    onChange={(e) => { setSearch(e.target.value); setSelectedLabel(''); setOpen(true); }}
                    onFocus={() => setOpen(true)}
                    placeholder={`Search ${label}…`}
                    className="h-9 pl-8 text-sm"
                />
                {(value || selectedLabel) && (
                    <button
                        type="button"
                        onClick={handleClear}
                        className="absolute top-1/2 right-2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
                    >
                        ✕
                    </button>
                )}
                {open && results.length > 0 && (
                    <div className="absolute top-full left-0 z-50 mt-1 w-full rounded-md border border-[#d8d8d8] bg-white shadow-lg">
                        {results.slice(0, 8).map((opt) => (
                            <button
                                key={String(opt.value)}
                                type="button"
                                onClick={() => handleSelect(opt)}
                                className="flex w-full items-center px-3 py-2 text-left text-sm hover:bg-gray-50"
                            >
                                {opt.label}
                            </button>
                        ))}
                    </div>
                )}
            </div>
        </div>
    );
}

function TextInput({ value, onChange, label }: { value: string; onChange: (v: string) => void; label: string }) {
    return (
        <div className="flex flex-col gap-1">
            <Label className="text-xs font-medium text-[#6d7175]">{label}</Label>
            <Input
                value={value || ''}
                onChange={(e) => onChange(e.target.value)}
                placeholder={`Filter by ${label}…`}
                className="h-9 text-sm"
            />
        </div>
    );
}

// ─── Main Panel ───────────────────────────────────────────────────────────────

declare const route: (...args: any[]) => string;

export default function ReportFilterPanel({ filters, values, onChange, onRun, loading = false }: ReportFilterPanelProps) {
    const [showAdvanced, setShowAdvanced] = useState(false);

    const set = (key: string, val: any) => onChange({ ...values, [key]: val });

    const handleClear = () => {
        const empty: FilterValues = {};
        filters.forEach((f) => (empty[f.key] = f.default ?? (f.type === 'multi_select' ? [] : '')));
        onChange(empty);
    };

    const hasActiveFilters = filters.some((f) => {
        const v = values[f.key];
        return Array.isArray(v) ? v.length > 0 : Boolean(v);
    });

    const processed      = processFilters(filters);
    const basicFilters   = processed.slice(0, 4);
    const advancedFilters = processed.slice(4);
    const visibleFilters = showAdvanced || advancedFilters.length === 0 ? processed : basicFilters;

    function renderFilter(filter: ProcessedFilter) {
        if (filter.type === 'date_range') {
            const df = filter as DateRangeFilter;
            return (
                <DateRangeInput
                    key={df.key}
                    fromValue={values[df.fromKey] ?? ''}
                    toValue={values[df.toKey] ?? ''}
                    onFromChange={(v) => set(df.fromKey, v)}
                    onToChange={(v) => set(df.toKey, v)}
                />
            );
        }
        const f   = filter as FilterDefinition;
        const val = values[f.key] ?? (f.type === 'multi_select' ? [] : '');
        switch (f.type) {
            case 'date':
                return <DateInput key={f.key} label={f.label} value={val} onChange={(v) => set(f.key, v)} />;
            case 'select':
                return <SelectInput key={f.key} label={f.label} value={val} options={f.options ?? []} onChange={(v) => set(f.key, v)} />;
            case 'multi_select':
                return <MultiSelectInput key={f.key} label={f.label} value={val} options={f.options ?? []} onChange={(v) => set(f.key, v)} />;
            case 'async_select':
                return <AsyncSelectInput key={f.key} label={f.label} value={val} endpoint={f.endpoint} onChange={(v) => set(f.key, v)} />;
            case 'text':
                return <TextInput key={f.key} label={f.label} value={val} onChange={(v) => set(f.key, v)} />;
            default:
                return null;
        }
    }

    return (
        <div className="rounded-xl border border-[#d8d8d8] bg-white shadow-sm">
            {/* Header */}
            <div className="flex items-center justify-between px-4 py-3">
                <span className="text-sm font-semibold text-[#202223]">Filters</span>
                <div className="flex items-center gap-2">
                    {hasActiveFilters && (
                        <button
                            type="button"
                            onClick={handleClear}
                            className="flex items-center gap-1.5 rounded-lg border border-[#d8d8d8] bg-white px-3 py-1.5 text-xs text-[#6d7175] hover:bg-[#f6f6f7]"
                        >
                            <RotateCcw className="h-3 w-3" />
                            Reset
                        </button>
                    )}
                    {advancedFilters.length > 0 && (
                        <button
                            type="button"
                            onClick={() => setShowAdvanced((s) => !s)}
                            className={cn(
                                'flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-xs font-medium transition-colors',
                                showAdvanced
                                    ? 'bg-primary/80 text-white'
                                    : 'bg-primary text-white hover:bg-primary/90',
                            )}
                        >
                            <SlidersHorizontal className="h-3.5 w-3.5" />
                            {showAdvanced ? 'Less Filters' : 'Advance Filter'}
                        </button>
                    )}
                </div>
            </div>

            {/* Filter grid */}
            <div className="border-t border-[#e3e3e3] px-4 py-4">
                <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
                    {visibleFilters.map(renderFilter)}
                </div>

                {/* Actions */}
                <div className="mt-4 flex items-center justify-end gap-2 border-t border-[#e3e3e3] pt-3">
                    <Button
                        size="sm"
                        onClick={onRun}
                        disabled={loading}
                        className="bg-primary text-white hover:bg-primary/90 disabled:opacity-60"
                    >
                        {loading ? (
                            <span className="flex items-center gap-1.5">
                                <span className="h-3.5 w-3.5 animate-spin rounded-full border-2 border-white border-t-transparent" />
                                Generating…
                            </span>
                        ) : (
                            'Generate Report'
                        )}
                    </Button>
                </div>
            </div>
        </div>
    );
}
