<script setup lang="ts">
import { ListFilter, Search } from '@lucide/vue';
import { useMediaQuery } from '@vueuse/core';
import { computed } from 'vue';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
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 type { DataTableFilterDef } from '@/types/data-table';

const props = defineProps<{
    filterDefs?: DataTableFilterDef[];
    filterValues?: Record<string, string>;
    searchPlaceholder?: string;
}>();

const search = defineModel<string>('search', { default: '' });

const emit = defineEmits<{
    'filter-change': [key: string, value: string];
    'filters-reset': [];
}>();

const activeFilterCount = computed(() => {
    if (!props.filterDefs?.length || !props.filterValues) {
        return 0;
    }

    return props.filterDefs.filter((filter) => {
        const value = props.filterValues?.[filter.key];

        return value !== undefined && value !== '';
    }).length;
});

function filterValue(key: string): string {
    return props.filterValues?.[key] ?? '';
}

function onFilterChange(key: string, value: string): void {
    emit('filter-change', key, value === 'all' ? '' : value);
}

function resetFilters(): void {
    emit('filters-reset');
}

const isMobile = useMediaQuery('(max-width: 640px)');
const selectSide = computed(() => (isMobile.value ? 'bottom' : 'left'));
const selectSideOffset = computed(() => (isMobile.value ? 4 : 12));
</script>

<template>
    <div class="flex items-center justify-between gap-4">
        <div class="relative w-full max-w-sm">
            <Search class="text-muted-foreground absolute top-1/2 left-3 size-4 -translate-y-1/2" />
            <Input v-model="search" type="search" :placeholder="searchPlaceholder ?? 'Ketikkan sesuatu...'" class="pl-9" />
        </div>

        <Popover v-if="filterDefs?.length">
            <PopoverTrigger as-child>
                <Button variant="outline" class="shrink-0">
                    <ListFilter class="size-4" />
                    Filter
                    <Badge v-if="activeFilterCount > 0" variant="secondary"
                        class="ml-1 size-5 rounded-full px-1 text-xs">
                        {{ activeFilterCount }}
                    </Badge>
                </Button>
            </PopoverTrigger>
            <PopoverContent align="end" class="w-80 space-y-4 p-4" @pointer-down-outside="(event) => {
                const target = event.target as HTMLElement;
                if (target.closest('[data-slot=select-content]') || target.closest('[data-slot=select-trigger]')) {
                    event.preventDefault();
                }
            }">
                <div class="space-y-1">
                    <h4 class="text-sm font-medium">
                        Filter
                    </h4>
                    <p class="text-muted-foreground text-xs">
                        Sesuaikan filter untuk mempersempit data.
                    </p>
                </div>

                <div v-for="filter in filterDefs" :key="filter.key" class="space-y-2">
                    <Label :for="`filter-${filter.key}`">{{ filter.label }}</Label>

                    <Input v-if="filter.type === 'text'" :id="`filter-${filter.key}`"
                        :model-value="filterValue(filter.key)"
                        :placeholder="filter.placeholder ?? `Filter ${filter.label.toLowerCase()}`"
                        @update:model-value="onFilterChange(filter.key, String($event ?? ''))" />

                    <Select v-else :model-value="filterValue(filter.key) || 'all'"
                        @update:model-value="onFilterChange(filter.key, String($event ?? ''))">
                        <SelectTrigger :id="`filter-${filter.key}`" class="w-full">
                            <SelectValue :placeholder="filter.placeholder ?? 'Semua'" />
                        </SelectTrigger>
                        <SelectContent class="z-[300]" :side="selectSide" :side-offset="selectSideOffset">
                            <SelectItem value="all">
                                Semua
                            </SelectItem>
                            <SelectItem v-for="option in filter.options" :key="option.value" :value="option.value">
                                {{ option.label }}
                            </SelectItem>
                        </SelectContent>
                    </Select>
                </div>

                <Button v-if="activeFilterCount > 0" variant="ghost" size="sm" class="w-full" @click="resetFilters">
                    Reset Filter
                </Button>
            </PopoverContent>
        </Popover>
    </div>
</template>
