<script setup lang="ts">
import { computed, ref, watch } from 'vue';

import Card from 'primevue/card';
import Button from 'primevue/button';
import DataTable from 'primevue/datatable';
import Column from 'primevue/column';
import InputText from 'primevue/inputtext';
import Paginator from 'primevue/paginator';
import { useConfirm } from 'primevue/useconfirm';
import { useToast } from 'primevue/usetoast';

import { locationServices } from '../../services/location.services';
import type { Location, LocationCreateRequest, LocationFormErrors, LocationPaginatedResponse } from '../../types/locations.interfaces';
import LocationForm from './LocationForm.vue';
import { useAuth } from '@/modules/auth/composables/useAuth';

const locations = ref<Location[]>([]);
const pagination = ref({
    first: 0,
    rows: 5,
    total: 0,
    page: 1,
    lastPage: 1,
});
const loading = ref(false);
const submitting = ref(false);

const searchName = ref('');
const searchCity = ref('');
const searchState = ref('');
const searchCountry = ref('');

const showFormDialog = ref(false);
const isEditMode = ref(false);
const currentLocation = ref<Location | null>(null);
const formErrors = ref<LocationFormErrors>({});

const confirm = useConfirm();
const toast = useToast();
const { hasPermission } = useAuth();

const canViewLocations = computed(() =>
    hasPermission([
        'locations.index',
        'locations.show',
        'locations.store',
        'locations.update',
        'locations.destroy',
    ])
);
const canCreateLocation = computed(() => hasPermission('locations.store'));
const canUpdateLocation = computed(() => hasPermission('locations.update'));
const canDeleteLocation = computed(() => hasPermission('locations.destroy'));

const handleCreateClick = () => {
    if (!canCreateLocation.value) {
        toast.add({ severity: 'warn', summary: 'Sin permisos', detail: 'No puedes crear ubicaciones.', life: 4000 });
        return;
    }

    isEditMode.value = false;
    currentLocation.value = null;
    formErrors.value = {};
    showFormDialog.value = true;
};

const handleEditClick = async (location: Location) => {
    if (!canUpdateLocation.value) {
        toast.add({ severity: 'warn', summary: 'Sin permisos', detail: 'No puedes actualizar ubicaciones.', life: 4000 });
        return;
    }

    isEditMode.value = true;
    formErrors.value = {};

    try {
        const response = await locationServices.getLocationById(location.id);
        currentLocation.value = response.data;
        showFormDialog.value = true;
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Error', detail: 'No se pudo cargar la ubicación', life: 3000 });
    }
};

const closeFormDialog = () => {
    showFormDialog.value = false;
    isEditMode.value = false;
    currentLocation.value = null;
    formErrors.value = {};
};

const handleFormSubmit = async (payload: LocationCreateRequest) => {
    formErrors.value = {};
    submitting.value = true;

    try {
        if (isEditMode.value && currentLocation.value) {
            await locationServices.updateLocation(currentLocation.value.id, payload, 'patch');
            toast.add({ severity: 'success', summary: 'Ubicación actualizada', detail: 'La ubicación se actualizó correctamente.', life: 3000 });
        } else {
            await locationServices.createLocation(payload);
            toast.add({ severity: 'success', summary: 'Ubicación creada', detail: 'La ubicación se registró correctamente.', life: 3000 });
        }

        closeFormDialog();
        fetchLocations(pagination.value.page);
    } catch (e: any) {
        if (e?.response?.data?.errors) {
            formErrors.value = e.response.data.errors;
        }

        toast.add({
            severity: 'error',
            summary: 'Error',
            detail: e?.response?.data?.message || 'No se pudo guardar la ubicación.',
            life: 3500,
        });
    } finally {
        submitting.value = false;
    }
};

const handleDelete = (locationId: number) => {
    if (!canDeleteLocation.value) {
        toast.add({ severity: 'warn', summary: 'Sin permisos', detail: 'No puedes eliminar ubicaciones.', life: 4000 });
        return;
    }

    confirm.require({
        message: '¿Seguro que deseas eliminar esta ubicación?',
        header: 'Confirmar eliminación',
        icon: 'pi pi-exclamation-triangle',
        acceptLabel: 'Sí, eliminar',
        rejectLabel: 'Cancelar',
        accept: async () => {
            try {
                await locationServices.deleteLocation(locationId);
                toast.add({ severity: 'success', summary: 'Eliminado', detail: 'Ubicación eliminada correctamente', life: 3000 });
                fetchLocations(pagination.value.page);
            } catch (e) {
                toast.add({ severity: 'error', summary: 'Error', detail: 'No se pudo eliminar la ubicación', life: 3000 });
            }
        },
    });
};

const fetchLocations = async (page = 1) => {
    if (!canViewLocations.value) {
        locations.value = [];
        pagination.value = {
            ...pagination.value,
            page: 1,
            total: 0,
            first: 0,
        };
        return;
    }

    pagination.value.page = page;
    loading.value = true;

    try {
        const name = searchName.value || undefined;
        const city = searchCity.value || undefined;
        const state = searchState.value || undefined;
        const country = searchCountry.value || undefined;

        const response = await locationServices.getLocations(true, name, city, state, country);
        const paginated = response as LocationPaginatedResponse;

        locations.value = paginated.data;
        pagination.value.total = paginated.total;
        pagination.value.page = paginated.current_page;
        pagination.value.lastPage = paginated.last_page;
        pagination.value.first = (paginated.current_page - 1) * paginated.per_page;
        pagination.value.rows = paginated.per_page;
    } catch (e) {
        toast.add({ severity: 'error', summary: 'Error', detail: 'No se pudieron cargar las ubicaciones.', life: 3000 });
    } finally {
        loading.value = false;
    }
};

watch(
    () => canViewLocations.value,
    (allowed) => {
        if (allowed) {
            fetchLocations();
        } else {
            locations.value = [];
        }
    },
    { immediate: true }
);

const clearFilters = () => {
    searchName.value = '';
    searchCity.value = '';
    searchState.value = '';
    searchCountry.value = '';
    fetchLocations(1);
};

const onFilter = () => {
    fetchLocations(1);
};

const onPageChange = (event: any) => {
    const newPage = Math.floor(event.first / event.rows) + 1;
    fetchLocations(newPage);
};

const hexToBytes = (hex: string): Uint8Array | null => {
    const normalized = hex.trim();
    if (normalized.length % 2 !== 0) return null;
    if (!/^[0-9a-fA-F]+$/.test(normalized)) return null;

    const bytes = new Uint8Array(normalized.length / 2);
    for (let i = 0; i < normalized.length; i += 2) {
        bytes[i / 2] = Number.parseInt(normalized.slice(i, i + 2), 16);
    }

    return bytes;
};

const parseHexEwkbPoint = (value: string): { lat: number; lng: number } | null => {
    const bytes = hexToBytes(value);
    if (!bytes || bytes.length < 1 + 4 + 16) return null;

    const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
    const littleEndian = view.getUint8(0) === 1;

    const typeWithFlags = view.getUint32(1, littleEndian);
    const hasSrid = (typeWithFlags & 0x20000000) !== 0;
    const geometryType = typeWithFlags & 0x0fffffff;
    if (geometryType !== 1) return null;

    let offset = 1 + 4;
    if (hasSrid) {
        if (bytes.length < offset + 4 + 16) return null;
        offset += 4;
    }

    if (bytes.length < offset + 16) return null;
    const lng = view.getFloat64(offset, littleEndian);
    const lat = view.getFloat64(offset + 8, littleEndian);
    if (Number.isNaN(lat) || Number.isNaN(lng)) return null;
    return { lat, lng };
};

const parseCoordinates = (value?: string | null): { lat: number; lng: number } | null => {
    if (!value) return null;

    const normalized = value.trim();
    const wkt = normalized.replace(/^SRID=\d+;/i, '');
    const match = wkt.match(/POINT\s*\(\s*([-\d.]+)\s+([-\d.]+)\s*\)/i);
    if (match) {
        const lng = Number(match[1]);
        const lat = Number(match[2]);
        if (Number.isNaN(lat) || Number.isNaN(lng)) return null;
        return { lat, lng };
    }

    return parseHexEwkbPoint(normalized);
};

const formatCoordinates = (value?: string | null): string => {
    const point = parseCoordinates(value);
    if (!point) return value || '-';

    return `Lat ${point.lat.toFixed(6)}, Lng ${point.lng.toFixed(6)}`;
};
</script>

<template>
    <div class="space-y-6">
        <!-- Form view -->
        <template v-if="showFormDialog">
            <div class="flex items-center gap-3 mb-6">
                <Button icon="pi pi-arrow-left" text rounded @click="closeFormDialog" />
                <div>
                    <h2 class="text-3xl font-black text-surface-900 dark:text-white tracking-tight">
                        {{ isEditMode ? 'Editar Ubicación' : 'Nueva Ubicación' }}
                    </h2>
                    <p class="text-gray-500 dark:text-gray-400 text-sm mt-1">Administra los datos y la geolocalización de la ubicación.</p>
                </div>
            </div>
            <LocationForm
                :initialData="currentLocation || undefined"
                :formErrors="formErrors"
                :isEditing="isEditMode"
                :loading="submitting"
                @submit="handleFormSubmit"
                @cancel="closeFormDialog"
            />
        </template>

        <!-- List view -->
        <template v-else>
            <div class="flex flex-col md:flex-row justify-between items-start md:items-center mb-8 gap-4">
                <div>
                    <h2 class="text-3xl font-black text-surface-900 dark:text-white tracking-tight">Gestión de Ubicaciones</h2>
                    <p class="text-gray-500 dark:text-gray-400 text-sm mt-1">Administra las ubicaciones operativas del sistema.</p>
                </div>
                <Button
                    v-if="canCreateLocation"
                    label="Nueva Ubicación"
                    icon="pi pi-plus"
                    @click="handleCreateClick"
                />
            </div>

            <Card v-if="canViewLocations">
                <template #content>
                    <div class="grid grid-cols-1 md:grid-cols-5 gap-4 items-end">
                        <div>
                            <label class="block text-xs font-bold text-gray-500 dark:text-gray-400 uppercase mb-2">Nombre</label>
                            <InputText v-model="searchName" placeholder="Ej. Bodega Norte" class="w-full" />
                        </div>
                        <div>
                            <label class="block text-xs font-bold text-gray-500 dark:text-gray-400 uppercase mb-2">Ciudad</label>
                            <InputText v-model="searchCity" placeholder="Ej. Monterrey" class="w-full" />
                        </div>
                        <div>
                            <label class="block text-xs font-bold text-gray-500 dark:text-gray-400 uppercase mb-2">Estado</label>
                            <InputText v-model="searchState" placeholder="Ej. Nuevo León" class="w-full" />
                        </div>
                        <div>
                            <label class="block text-xs font-bold text-gray-500 dark:text-gray-400 uppercase mb-2">País</label>
                            <InputText v-model="searchCountry" placeholder="Ej. México" class="w-full" />
                        </div>
                        <div class="flex gap-2">
                            <Button icon="pi pi-search" text rounded @click="onFilter" />
                            <Button icon="pi pi-times" text rounded severity="secondary" label="Limpiar" @click="clearFilters" />
                        </div>
                    </div>
                </template>
            </Card>

            <Card v-if="canViewLocations">
                <template #content>
                    <DataTable :value="locations" :loading="loading" stripedRows responsiveLayout="scroll" class="p-datatable-sm">
                        <Column field="name" header="Nombre" style="min-width: 180px" />
                        <Column field="address" header="Dirección" style="min-width: 220px" />
                        <Column field="city" header="Ciudad" style="min-width: 140px" />
                        <Column field="state" header="Estado" style="min-width: 140px" />
                        <Column field="country" header="País" style="min-width: 120px" />
                        <Column field="zip_code" header="CP" style="min-width: 100px" />
                        <Column header="Coordenadas" style="min-width: 220px">
                            <template #body="{ data }">
                                <span class="font-mono text-xs">
                                    {{ formatCoordinates(data.coordinates) }}
                                </span>
                            </template>
                        </Column>
                        <Column field="geofence" header="Geocerca" style="min-width: 180px">
                            <template #body="{ data }">
                                <span class="text-xs">{{ data.geofence ? 'Definida' : 'Sin definir' }}</span>
                            </template>
                        </Column>
                        <Column field="created_at" header="Fecha de Registro" style="min-width: 120px">
                            <template #body="{ data }">
                                <span class="text-sm">{{ new Date(data.created_at).toLocaleDateString('es-MX') }}</span>
                            </template>
                        </Column>
                        <Column header="Acciones" headerStyle="text-align: right" bodyStyle="text-align: right" style="min-width: 130px">
                            <template #body="{ data }">
                                <div class="flex items-center justify-end gap-2">
                                    <Button
                                        v-if="canUpdateLocation"
                                        icon="pi pi-pencil"
                                        text
                                        rounded
                                        size="small"
                                        @click="handleEditClick(data)"
                                    />
                                    <Button
                                        v-if="canDeleteLocation"
                                        icon="pi pi-trash"
                                        text
                                        rounded
                                        size="small"
                                        severity="danger"
                                        @click="handleDelete(data.id)"
                                    />
                                </div>
                            </template>
                        </Column>
                    </DataTable>
                    <div class="mt-4">
                        <Paginator :first="pagination.first" :rows="pagination.rows" :totalRecords="pagination.total" :rowsPerPageOptions="[5, 10, 20, 50]" @page="onPageChange" />
                    </div>
                </template>
            </Card>

            <Card v-else>
                <template #content>
                    <div class="text-center py-10 text-surface-500 dark:text-surface-400">
                        <i class="pi pi-lock text-4xl mb-3"></i>
                        <p>No tienes permisos para visualizar este módulo.</p>
                    </div>
                </template>
            </Card>
        </template>
    </div>

    <ConfirmDialog />
    <Toast />
</template>
