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

    <q-card-section>
      <h5>Your Registered Passkeys</h5>
      <q-list
        bordered
        separator
        v-if="passkeys.length > 0 && !fetchLoading"
      >
        <q-item v-if="registerSuccessMessage || registerErrorMessage">
          <div
            v-if="registerSuccessMessage"
            class="text-positive q-mt-md"
          >
            {{ registerSuccessMessage }}
          </div>
          <div
            v-if="registerErrorMessage"
            class="text-negative q-mt-md"
          >
            {{ registerErrorMessage }}
          </div>
        </q-item>
        <q-item
          v-for="passkey in passkeys"
          :key="passkey.credentialID"
          :class="{ 'bg-info text-h6': identifiedPasskeyId === passkey.credentialID }"
        >
          <q-item-section>
            <q-item-label>Passkey ID: {{ passkey.credentialID }} </q-item-label>
            <q-item-label
              caption
              v-if="identifiedPasskeyId === passkey.credentialID"
            >
              Verified just now!
            </q-item-label>
          </q-item-section>

          <q-item-section
            side
            class="row no-wrap items-center"
          >
            <q-btn
              flat
              dense
              round
              color="negative"
              icon="delete"
              @click="handleDelete(passkey.credentialID)"
              :loading="deleteLoading === passkey.credentialID"
              :disable="!!deleteLoading || !!identifyLoading"
            />
          </q-item-section>
        </q-item>
      </q-list>
      <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-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;
    console.log('Identified Passkey ID:', identifiedPasskeyId.value);

    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>