<template>
  <q-page padding>
    <q-card
      bordered
      flat
    >
      <q-card-section class="row items-center justify-between">
        <div class="text-h4">
          Passkey Management
        </div>
        <div>
          <q-btn
            label="Identify Passkey"
            color="secondary"
            class="q-mx-md"
            @click="handleIdentify"
            :loading="identifyLoading"
            :disable="identifyLoading || !isLoggedIn"
          />
          <q-btn
            label="Register New Passkey"
            color="primary"
            @click="handleRegister"
            :loading="registerLoading"
            :disable="registerLoading || !isLoggedIn"
          />
        </div>
      </q-card-section>

      <q-separator />

      <q-card-section>
        <div class="text-h6 q-mb-sm">
          Registered Passkeys
        </div>

        <!-- Display registration messages above the grid -->
        <div
          v-if="registerSuccessMessage"
          class="text-positive q-mb-md"
        >
          {{ registerSuccessMessage }}
        </div>
        <div
          v-if="registerErrorMessage"
          class="text-negative q-mb-md"
        >
          {{ registerErrorMessage }}
        </div>

        <!-- Responsive Grid for Passkeys -->
        <div
          v-if="passkeys.length > 0 && !fetchLoading"
          class="row q-col-gutter-md justify-center align-center"
        >
          <div
            v-for="passkey in passkeys"
            :key="passkey.credentialID"
            class="col-12 col-sm-6 col-md-4 col-lg-3"
          >
            <q-card
              bordered
              flat
              :class="{ 'bg-info': identifiedPasskeyId === passkey.credentialID }"
            >
              <q-card-section>
                <div class="text-subtitle2 ellipsis">
                  Passkey ID:
                  <q-tooltip>{{ passkey.credentialID }}</q-tooltip>
                </div>
                <div class="text-caption ellipsis">
                  {{ passkey.credentialID }}
                </div>
                <q-item-label
                  caption
                  class="text-positive"
                  v-if="identifiedPasskeyId === passkey.credentialID"
                >
                  Verified just now!
                </q-item-label>
              </q-card-section>

              <q-separator />

              <q-card-actions align="right">
                <q-btn
                  flat
                  dense
                  round
                  color="negative"
                  icon="delete"
                  @click="handleDelete(passkey.credentialID)"
                  :loading="deleteLoading === passkey.credentialID"
                  :disable="!!deleteLoading || !!identifyLoading"
                >
                  <q-tooltip>Delete Passkey</q-tooltip>
                </q-btn>
              </q-card-actions>
            </q-card>
          </div>
        </div>
        <div
          v-else-if="fetchLoading"
          class="q-mt-md"
        >
          Loading passkeys...
        </div>
        <div
          v-else
          class="q-mt-md"
        >
          You have no passkeys registered yet.
        </div>

        <div
          v-if="fetchErrorMessage"
          class="text-negative q-mt-md"
        >
          {{ fetchErrorMessage }}
        </div>
        <div
          v-if="deleteSuccessMessage"
          class="text-positive q-mt-md"
        >
          {{ deleteSuccessMessage }}
        </div>
        <div
          v-if="deleteErrorMessage"
          class="text-negative q-mt-md"
        >
          {{ deleteErrorMessage }}
        </div>
        <div
          v-if="identifyErrorMessage"
          class="text-negative q-mt-md"
        >
          {{ identifyErrorMessage }}
        </div>
      </q-card-section>
    </q-card>
  </q-page>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue';
import { startRegistration, startAuthentication } from '@simplewebauthn/browser';
import axios from 'boot/axios';
import { useAuthStore } from 'stores/auth';
import { useQuasar } from 'quasar';

const registerLoading = ref(false);
const registerErrorMessage = ref('');
const registerSuccessMessage = ref('');
const fetchLoading = ref(false);
const fetchErrorMessage = ref('');
const deleteLoading = ref(null);
const deleteErrorMessage = ref('');
const deleteSuccessMessage = ref('');
const identifyLoading = ref(null);
const identifyErrorMessage = ref('');
const identifiedPasskeyId = ref(null);

const $q = useQuasar();

const authStore = useAuthStore();
const passkeys = ref([]);

const isLoggedIn = computed(() => authStore.isAuthenticated);
const username = computed(() => authStore.user?.username);

async function fetchPasskeys()
{
  if (!isLoggedIn.value) return;
  fetchLoading.value = true;
  fetchErrorMessage.value = '';
  deleteSuccessMessage.value = '';
  deleteErrorMessage.value = '';
  identifyErrorMessage.value = '';
  identifiedPasskeyId.value = null;
  try
  {
    const response = await axios.get('/api/auth/passkeys');
    passkeys.value = response.data || [];
  }
  catch (error)
  {
    console.error('Error fetching passkeys:', error);
    fetchErrorMessage.value = error.response?.data?.error || 'Failed to load passkeys.';
    passkeys.value = [];
  }
  finally
  {
    fetchLoading.value = false;
  }
}

onMounted(async() =>
{
  let initialAuthError = '';
  if (!authStore.isAuthenticated)
  {
    await authStore.checkAuthStatus();
    if (authStore.error)
    {
      initialAuthError = `Authentication error: ${authStore.error}`;
    }
  }
  if (!isLoggedIn.value)
  {
    registerErrorMessage.value = initialAuthError || 'You must be logged in to manage passkeys.';
  }
  else
  {
    fetchPasskeys();
  }
});

async function handleRegister()
{
  if (!isLoggedIn.value || !username.value)
  {
    registerErrorMessage.value = 'User not authenticated.';
    return;
  }
  registerLoading.value = true;
  registerErrorMessage.value = '';
  registerSuccessMessage.value = '';
  deleteSuccessMessage.value = '';
  deleteErrorMessage.value = '';
  identifyErrorMessage.value = '';
  identifiedPasskeyId.value = null;

  try
  {
    const optionsRes = await axios.post('/api/auth/generate-registration-options', {
      username: username.value,
    });
    const options = optionsRes.data;

    const regResp = await startRegistration(options);

    const verificationRes = await axios.post('/api/auth/verify-registration', {
      registrationResponse: regResp,
    });

    if (verificationRes.data.verified)
    {
      registerSuccessMessage.value = 'New passkey registered successfully!';
      fetchPasskeys();
    }
    else
    {
      registerErrorMessage.value = 'Passkey verification failed.';
    }
  }
  catch (error)
  {
    console.error('Registration error:', error);
    const message = error.response?.data?.error || error.message || 'An unknown error occurred during registration.';
    if (error.name === 'InvalidStateError')
    {
      registerErrorMessage.value = 'Authenticator may already be registered.';
    }
    else if (error.name === 'NotAllowedError')
    {
      registerErrorMessage.value = 'Registration ceremony was cancelled or timed out.';
    }
    else if (error.response?.status === 409)
    {
      registerErrorMessage.value = 'This passkey seems to be registered already.';
    }
    else
    {
      registerErrorMessage.value = `Registration failed: ${message}`;
    }
  }
  finally
  {
    registerLoading.value = false;
  }
}


async function handleDelete(credentialID)
{
  if (!credentialID) return;

  if (passkeys.value.length <= 1)
  {
    deleteErrorMessage.value = 'You cannot delete your last passkey. Register another one first.';
    deleteSuccessMessage.value = '';
    registerSuccessMessage.value = '';
    registerErrorMessage.value = '';
    identifyErrorMessage.value = '';
    identifiedPasskeyId.value = null;
    return;
  }

  $q.dialog({
    title: 'Confirm Deletion',
    message: 'Are you sure you want to delete this passkey? This action cannot be undone.',
    cancel: true,
    persistent: true,
    ok: {
      label: 'Delete',
      color: 'negative',
      flat: true,
    },
    cancel: {
      label: 'Cancel',
      flat: true,
    },
  }).onOk(async() =>
  {
    deleteLoading.value = credentialID;
    deleteErrorMessage.value = '';
    deleteSuccessMessage.value = '';
    registerSuccessMessage.value = '';
    registerErrorMessage.value = '';
    identifyErrorMessage.value = '';
    identifiedPasskeyId.value = null;

    try
    {
      await axios.delete(`/api/auth/passkeys/${credentialID}`);
      deleteSuccessMessage.value = 'Passkey deleted successfully.';
      fetchPasskeys();
    }
    catch (error)
    {
      console.error('Error deleting passkey:', error);
      deleteErrorMessage.value = error.response?.data?.error || 'Failed to delete passkey.';
    }
    finally
    {
      deleteLoading.value = null;
    }
  });
}

async function handleIdentify()
{
  if (!isLoggedIn.value)
  {
    identifyErrorMessage.value = 'You must be logged in.';
    return;
  }

  identifyLoading.value = true;
  identifyErrorMessage.value = '';
  identifiedPasskeyId.value = null;
  registerSuccessMessage.value = '';
  registerErrorMessage.value = '';
  deleteSuccessMessage.value = '';
  deleteErrorMessage.value = '';

  try
  {
    const optionsRes = await axios.post('/api/auth/generate-authentication-options', {});
    const options = optionsRes.data;

    const authResp = await startAuthentication(options);

    identifiedPasskeyId.value = authResp.id;

    setTimeout(() =>
    {
      if (identifiedPasskeyId.value === authResp.id)
      {
        identifiedPasskeyId.value = null;
      }
    }, 5000);

  }
  catch (error)
  {
    console.error('Identification error:', error);
    identifiedPasskeyId.value = null;
    if (error.name === 'NotAllowedError')
    {
      identifyErrorMessage.value = 'Identification ceremony was cancelled or timed out.';
    }
    else
    {
      identifyErrorMessage.value = error.response?.data?.error || error.message || 'Failed to identify passkey.';
    }
  }
  finally
  {
    identifyLoading.value = null;
  }
}

</script>