<script setup lang="ts">
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 type { AttendanceCaptureFormData } from '@/types/attendance';
import { useForm } from '@inertiajs/vue3';
import { Camera, Loader2 } from '@lucide/vue';
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue';
import { toast } from 'vue-sonner';

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, buildLocationTag } = useGeolocation();
const { startCamera, stopCamera, captureWithLocationTag } = useWebcamCapture();

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

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'
        ? '/admin/hr/attendances/check-in'
        : '/admin/hr/attendances/check-out',
);

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 locationTag = buildLocationTag(
            position.latitude,
            position.longitude,
        );
        const photo = captureWithLocationTag(videoRef.value, locationTag);

        stopCamera();
        cameraReady.value = false;

        previewPhoto.value = photo;
        form.photo = photo;
        form.latitude = position.latitude;
        form.longitude = position.longitude;
        form.location_tag = locationTag;
    } 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.location_tag = '';
    form.clearErrors();

    await nextTick();
    await initializeCamera();
}

function submitAttendance() {
    form.post(submitUrl.value, {
        preserveScroll: true,
        onSuccess: () => {
            open.value = false;
        },
        onError: () => {
            toast.error('Gagal menyimpan presensi.');
        },
    });
}

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>

                    <p
                        class="text-xs whitespace-pre-line text-muted-foreground"
                    >
                        {{ form.location_tag }}
                    </p>
                </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>
