<script setup lang="ts">
import { Head } from '@inertiajs/vue3';
import {
    BellRing,
    Camera,
    CheckCircle2,
    FlaskConical,
    MapPin,
    XCircle,
} from '@lucide/vue';
import { onMounted, ref, watch } from 'vue';
import { toast } from 'vue-sonner';
import { Button } from '@/components/ui/button';
import { Card, CardContent } from '@/components/ui/card';
import { usePushNotification } from '@/composables/usePushNotification';
import AccountLayout from '@/layouts/AccountLayout.vue';

type PermissionState = 'granted' | 'denied' | 'prompt' | 'unsupported';

interface PermissionItem {
    key: 'notification' | 'camera' | 'location';
    label: string;
    description: string;
    icon: typeof BellRing;
    state: PermissionState;
    requesting: boolean;
    testing: boolean;
}

const { isSupported, isSubscribed, isLoading, subscribe, unsubscribe } =
    usePushNotification();

watch(isSubscribed, (subscribed) => {
    const notif = permissions.value.find((p) => p.key === 'notification');

    if (!notif) {
return;
}

    if (subscribed) {
        notif.state = 'granted';
    } else if (isSupported.value) {
        notif.state = 'prompt';
    }
});

const permissions = ref<PermissionItem[]>([
    {
        key: 'notification',
        label: 'Notifikasi',
        description:
            'Izinkan aplikasi mengirimkan notifikasi push ke perangkat.',
        icon: BellRing,
        state: 'prompt',
        requesting: false,
        testing: false,
    },
    {
        key: 'camera',
        label: 'Kamera',
        description: 'Izinkan kamera untuk melakukan presensi.',
        icon: Camera,
        state: 'prompt',
        requesting: false,
        testing: false,
    },
    {
        key: 'location',
        label: 'Lokasi',
        description: 'Izinkan lokasi untuk melakukan presensi.',
        icon: MapPin,
        state: 'prompt',
        requesting: false,
        testing: false,
    },
]);

async function checkPermissions() {
    for (const perm of permissions.value) {
        if (perm.key === 'notification') {
            if (!isSupported.value) {
                perm.state = 'unsupported';
            } else if (isSubscribed.value) {
                perm.state = 'granted';
            } else {
                perm.state = 'prompt';
            }
        } else if (perm.key === 'camera') {
            if (!navigator.mediaDevices?.getUserMedia) {
                perm.state = 'unsupported';
            } else {
                try {
                    const result = await navigator.permissions.query({
                        name: 'camera' as PermissionName,
                    });
                    perm.state = result.state as PermissionState;
                } catch {
                    perm.state = 'prompt';
                }
            }
        } else if (perm.key === 'location') {
            if (!navigator.geolocation) {
                perm.state = 'unsupported';
            } else {
                try {
                    const result = await navigator.permissions.query({
                        name: 'geolocation',
                    });
                    perm.state = result.state as PermissionState;
                } catch {
                    perm.state = 'prompt';
                }
            }
        }
    }
}

async function requestPermission(perm: PermissionItem) {
    if (
        perm.requesting ||
        perm.state === 'denied' ||
        perm.state === 'unsupported'
    ) {
return;
}

    perm.requesting = true;

    try {
        if (perm.key === 'notification') {
            const result = await Notification.requestPermission();

            if (result === 'denied') {
                perm.state = 'denied';
            } else if (result === 'granted') {
                await subscribe();
                perm.state = isSubscribed.value ? 'granted' : 'denied';
            }
        } else if (perm.key === 'camera') {
            const stream = await navigator.mediaDevices.getUserMedia({
                video: true,
            });
            stream.getTracks().forEach((track) => track.stop());
            perm.state = 'granted';
        } else if (perm.key === 'location') {
            await new Promise<void>((resolve, reject) => {
                navigator.geolocation.getCurrentPosition(
                    () => resolve(),
                    () => reject(),
                );
            });
            perm.state = 'granted';
        }
    } catch {
        perm.state = 'denied';
    } finally {
        perm.requesting = false;
    }
}

async function handleUnsubscribeNotification(perm: PermissionItem) {
    perm.requesting = true;

    try {
        await unsubscribe();
        perm.state = 'prompt';
    } catch {
        // state unchanged on error
    } finally {
        perm.requesting = false;
    }
}

async function testPermission(perm: PermissionItem) {
    perm.testing = true;

    try {
        if (perm.key === 'notification') {
            if ('serviceWorker' in navigator) {
                const registration = await navigator.serviceWorker.ready;
                await registration.showNotification('Tes Notifikasi', {
                    body: 'Notifikasi berhasil diterima oleh perangkat Anda.',
                    icon: '/favicon.ico',
                });
            } else {
                new Notification('Tes Notifikasi', {
                    body: 'Notifikasi berhasil diterima oleh perangkat Anda.',
                    icon: '/favicon.ico',
                });
            }

            toast.success('Notifikasi tes berhasil dikirim.');
        } else if (perm.key === 'camera') {
            const stream = await navigator.mediaDevices.getUserMedia({
                video: true,
            });
            stream.getTracks().forEach((track) => track.stop());
            toast.success('Kamera berhasil diakses.');
        } else if (perm.key === 'location') {
            await new Promise<void>((resolve, reject) => {
                navigator.geolocation.getCurrentPosition(
                    (pos) => {
                        toast.success(
                            `Lokasi berhasil diambil: ${pos.coords.latitude.toFixed(5)}, ${pos.coords.longitude.toFixed(5)}`,
                        );
                        resolve();
                    },
                    () => reject(new Error('Gagal mengambil lokasi.')),
                );
            });
        }
    } catch (err) {
        toast.error(err instanceof Error ? err.message : 'Tes gagal.');
    } finally {
        perm.testing = false;
    }
}

const stateLabel: Record<PermissionState, string> = {
    granted: 'Diizinkan',
    denied: 'Ditolak',
    prompt: 'Belum Diizinkan',
    unsupported: 'Tidak Didukung',
};

const stateClass: Record<PermissionState, string> = {
    granted: 'text-green-600 dark:text-green-400',
    denied: 'text-red-500 dark:text-red-400',
    prompt: 'text-muted-foreground',
    unsupported: 'text-muted-foreground',
};

onMounted(() => {
    checkPermissions();
});
</script>

<template>
    <Head title="Izin" />

    <AccountLayout>
        <div class="grid gap-4">
            <Card v-for="perm in permissions" :key="perm.key">
                <CardContent>
                    <div class="flex items-start gap-4">
                        <div
                            class="flex size-10 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary"
                        >
                            <component :is="perm.icon" class="size-5" />
                        </div>

                        <div class="min-w-0 flex-1">
                            <div class="flex flex-wrap items-center gap-2">
                                <p class="text-sm font-semibold">
                                    {{ perm.label }}
                                </p>
                                <span
                                    :class="[
                                        'inline-flex items-center gap-1 text-xs font-medium',
                                        stateClass[perm.state],
                                    ]"
                                >
                                    <CheckCircle2
                                        v-if="perm.state === 'granted'"
                                        class="size-3.5"
                                    />
                                    <XCircle
                                        v-else-if="perm.state === 'denied'"
                                        class="size-3.5"
                                    />
                                    {{ stateLabel[perm.state] }}
                                </span>
                            </div>
                            <p class="mt-0.5 text-sm text-muted-foreground">
                                {{ perm.description }}
                            </p>
                        </div>

                        <div class="flex shrink-0 gap-2">
                            <template v-if="perm.state === 'granted'">
                                <Button
                                    variant="outline"
                                    size="sm"
                                    :disabled="perm.testing"
                                    @click="testPermission(perm)"
                                >
                                    <FlaskConical class="size-3.5" />
                                    {{ perm.testing ? 'Mencoba...' : 'Tes' }}
                                </Button>
                                <Button
                                    v-if="perm.key === 'notification'"
                                    variant="outline"
                                    size="sm"
                                    :disabled="isLoading || perm.requesting"
                                    @click="handleUnsubscribeNotification(perm)"
                                >
                                    {{
                                        perm.requesting || isLoading
                                            ? 'Memproses...'
                                            : 'Nonaktifkan'
                                    }}
                                </Button>
                            </template>

                            <Button
                                v-else-if="perm.state === 'prompt'"
                                size="sm"
                                :disabled="perm.requesting"
                                @click="requestPermission(perm)"
                            >
                                {{ perm.requesting ? 'Meminta...' : 'Izinkan' }}
                            </Button>

                            <span
                                v-else-if="perm.state === 'denied'"
                                class="text-xs text-muted-foreground"
                            >
                                Ditolak di browser
                            </span>

                            <span
                                v-else-if="perm.state === 'unsupported'"
                                class="text-xs text-muted-foreground"
                            >
                                —
                            </span>
                        </div>
                    </div>
                </CardContent>
            </Card>
        </div>
    </AccountLayout>
</template>
