<script setup lang="ts">
import { useForm } from '@inertiajs/vue3';
import { Camera, Loader2 } from '@lucide/vue';
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue';
import { toast } from 'vue-sonner';
import { Button } from '@/components/ui/button';
import {
    Dialog,
    DialogContent,
    DialogFooter,
    DialogHeader,
    DialogTitle,
} from '@/components/ui/dialog';
import { useGeolocation } from '@/composables/useGeolocation';
import { useWebcamCapture } from '@/composables/useWebcamCapture';
import { check_in, check_out } from '@/routes/admin/hr/attendances';
import type { AttendanceCaptureFormData } from '@/types/attendance';

const open = defineModel<boolean>('open', { default: false });

const props = defineProps<{
    mode: 'check-in' | 'check-out';
}>();

const videoRef = ref<HTMLVideoElement | null>(null);
const cameraReady = ref(false);
const cameraLoading = ref(false);
const capturing = ref(false);
const previewPhoto = ref<string | null>(null);

const { getCurrentPosition } = useGeolocation();
const { startCamera, stopCamera, capture } = useWebcamCapture();

const form = useForm<AttendanceCaptureFormData>({
    photo: '',
    latitude: 0,
    longitude: 0,
});

const title = computed(() =>
    props.mode === 'check-in' ? 'Presensi Masuk' : 'Presensi Pulang',
);
const submitLabel = computed(() =>
    props.mode === 'check-in' ? 'Konfirmasi Masuk' : 'Konfirmasi Pulang',
);
const submitUrl = computed(() =>
    props.mode === 'check-in'
        ? check_in.url()
        : check_out.url(),
);

async function initializeCamera() {
    if (!videoRef.value) {
        return;
    }

    cameraLoading.value = true;
    cameraReady.value = false;
    previewPhoto.value = null;

    try {
        await startCamera(videoRef.value);
        cameraReady.value = true;
    } catch {
        toast.error('Gagal mengakses kamera. Pastikan izin kamera diaktifkan.');
        open.value = false;
    } finally {
        cameraLoading.value = false;
    }
}

function resetState() {
    form.reset();
    form.clearErrors();
    previewPhoto.value = null;
    cameraReady.value = false;
    capturing.value = false;
    stopCamera();
}

async function capturePhoto() {
    if (!videoRef.value || !cameraReady.value) {
        return;
    }

    capturing.value = true;

    try {
        const position = await getCurrentPosition();
        const photo = capture(videoRef.value);

        stopCamera();
        cameraReady.value = false;

        previewPhoto.value = photo;
        form.photo = photo;
        form.latitude = position.latitude;
        form.longitude = position.longitude;
    } catch (error) {
        toast.error(
            error instanceof Error
                ? error.message
                : 'Gagal mengambil foto presensi.',
        );
    } finally {
        capturing.value = false;
    }
}

async function retakePhoto() {
    previewPhoto.value = null;
    form.photo = '';
    form.latitude = 0;
    form.longitude = 0;
    form.clearErrors();

    await nextTick();
    await initializeCamera();
}

function submitAttendance() {
    form.post(submitUrl.value, {
        preserveScroll: true,
        onSuccess: () => {
            open.value = false;
        },
        onError: (errors: any) => {
            if (errors.system) {
                toast.error(errors.system);
            }
        },
    });
}

watch(open, async (isOpen) => {
    if (isOpen) {
        resetState();
        await nextTick();
        await initializeCamera();

        return;
    }

    resetState();
});

onBeforeUnmount(() => {
    stopCamera();
});
</script>

<template>
    <Dialog v-model:open="open">
        <DialogContent class="sm:max-w-lg">
            <DialogHeader>
                <DialogTitle>{{ title }}</DialogTitle>
            </DialogHeader>

            <div class="space-y-4">
                <p v-if="!previewPhoto" class="text-sm text-muted-foreground">
                    Ambil foto langsung dari kamera. Upload dari galeri tidak
                    diizinkan.
                </p>

                <div v-if="!previewPhoto" class="space-y-2">
                    <p class="text-sm font-medium">Kamera</p>
                    <div class="relative aspect-4/3 overflow-hidden rounded-lg border bg-muted">
                        <video ref="videoRef" class="size-full scale-x-[-1] object-cover" autoplay muted playsinline />

                        <div v-if="cameraLoading"
                            class="absolute inset-0 flex items-center justify-center bg-background/80">
                            <Loader2 class="size-8 animate-spin text-muted-foreground" />
                        </div>
                    </div>
                </div>

                <div v-else class="space-y-2">
                    <p class="text-sm font-medium">Hasil Foto</p>
                    <div class="relative aspect-4/3 overflow-hidden rounded-lg border bg-muted">
                        <img :src="previewPhoto" alt="Hasil foto presensi" class="size-full object-cover" />
                    </div>
                </div>
            </div>

            <DialogFooter>
                <Button v-if="previewPhoto" type="button" variant="outline" @click="retakePhoto">
                    Ambil Ulang
                </Button>

                <Button v-if="!previewPhoto" type="button" :disabled="!cameraReady || capturing" @click="capturePhoto">
                    <Loader2 v-if="capturing" class="size-4 animate-spin" />
                    <Camera v-else class="size-4" />
                    Ambil Foto
                </Button>

                <Button v-else type="button" :disabled="form.processing" @click="submitAttendance">
                    <Loader2 v-if="form.processing" class="size-4 animate-spin" />
                    {{ submitLabel }}
                </Button>
            </DialogFooter>
        </DialogContent>
    </Dialog>
</template>
