<script setup lang="ts">
import { computed, ref } from 'vue'
import { useRouter } from 'vue-router'
import { AuthRequestError, changePassword } from '@/services/authSession'
import { useAppBannersStore } from '@/stores/appBanners'

const router = useRouter()
const appBannersStore = useAppBannersStore()

const oldPassword = ref('')
const newPassword = ref('')
const newPasswordConfirm = ref('')

const showOldPassword = ref(false)
const showNewPassword = ref(false)
const showNewPasswordConfirm = ref(false)

const isSubmitting = ref(false)
const errorMessage = ref('')

const submitDisabled = computed(() => {
  return (
    isSubmitting.value ||
    oldPassword.value.length === 0 ||
    newPassword.value.length === 0 ||
    newPasswordConfirm.value.length === 0
  )
})

const passwordsMatch = computed(() => {
  if (newPassword.value.length === 0 || newPasswordConfirm.value.length === 0) {
    return null
  }

  return newPassword.value === newPasswordConfirm.value
})

const passwordHints = computed(() => [
  {
    label: 'Mindestens 8 Zeichen',
    valid: newPassword.value.length >= 8,
  },
  {
    label: 'Buchstabe enthalten',
    valid: /[A-Za-zÄÖÜäöüß]/.test(newPassword.value),
  },
  {
    label: 'Ziffer enthalten',
    valid: /\d/.test(newPassword.value),
  },
  {
    label: 'Übereinstimmung mit Bestätigung',
    valid: passwordsMatch.value === true,
  },
])

async function handleSubmit() {
  if (submitDisabled.value) {
    errorMessage.value = 'Bitte alle Passwortfelder ausfüllen.'
    return
  }

  if (newPassword.value !== newPasswordConfirm.value) {
    errorMessage.value = 'Die neuen Passwörter stimmen nicht überein.'
    return
  }

  isSubmitting.value = true
  errorMessage.value = ''

  try {
    await changePassword({
      oldPassword: oldPassword.value,
      newPassword: newPassword.value,
      newPasswordConfirm: newPasswordConfirm.value,
    })

    await router.replace({
      name: 'Login',
      query: { passwordChanged: '1' },
    })
  } catch (error) {
    if (error instanceof AuthRequestError) {
      errorMessage.value = error.message

      if (error.status === 401 || error.status === 403) {
        appBannersStore.pushError('Session abgelaufen. Bitte erneut anmelden.', 'Passwort ändern')
        await router.replace({ name: 'Login' })
        return
      }
    } else {
      errorMessage.value = 'Passwortänderung fehlgeschlagen. Bitte versuche es erneut.'
    }
  } finally {
    isSubmitting.value = false
  }
}
</script>

<template>
  <v-container fluid class="change-password-page hoard-page hoard-page--centered">
    <section class="change-password-shell hoard-panel hoard-shell-grid">
      <header class="change-password-head">
        <span class="hoard-icon-tile hoard-icon-tile--lg">
          <v-icon icon="mdi-shield-key-outline" size="24" />
        </span>
        <div>
          <p class="hoard-kicker hoard-kicker--xs">Sicherheitsvorgabe</p>
          <h1>Passwort ändern</h1>
          <p>Aktualisiere dein Hoard-Passwort. Nach der Änderung wirst du erneut zur Anmeldung weitergeleitet.</p>
        </div>
      </header>

      <v-alert
        v-if="errorMessage"
        type="error"
        density="comfortable"
      >
        {{ errorMessage }}
      </v-alert>

      <v-form class="change-password-form" @submit.prevent="handleSubmit">
        <section class="change-password-section">
          <p class="hoard-kicker hoard-kicker--xs hoard-kicker--plain">Aktuell</p>
          <v-text-field
            v-model="oldPassword"
            label="Altes Passwort"
            :type="showOldPassword ? 'text' : 'password'"
            prepend-inner-icon="mdi-lock-outline"
            :append-inner-icon="showOldPassword ? 'mdi-eye-off-outline' : 'mdi-eye-outline'"
            autocomplete="current-password"
            required
            :disabled="isSubmitting"
            @click:append-inner="showOldPassword = !showOldPassword"
          />
        </section>

        <hr class="hoard-divider-soft" />

        <section class="change-password-section">
          <p class="hoard-kicker hoard-kicker--xs hoard-kicker--plain">Neues Passwort</p>

          <v-text-field
            v-model="newPassword"
            label="Neues Passwort"
            :type="showNewPassword ? 'text' : 'password'"
            prepend-inner-icon="mdi-lock-reset"
            :append-inner-icon="showNewPassword ? 'mdi-eye-off-outline' : 'mdi-eye-outline'"
            autocomplete="new-password"
            required
            :disabled="isSubmitting"
            @click:append-inner="showNewPassword = !showNewPassword"
          />

          <v-text-field
            v-model="newPasswordConfirm"
            label="Neues Passwort bestätigen"
            :type="showNewPasswordConfirm ? 'text' : 'password'"
            prepend-inner-icon="mdi-lock-check-outline"
            :append-inner-icon="showNewPasswordConfirm ? 'mdi-eye-off-outline' : 'mdi-eye-outline'"
            autocomplete="new-password"
            required
            :disabled="isSubmitting"
            :error="passwordsMatch === false"
            :error-messages="
              passwordsMatch === false ? 'Bestätigung stimmt nicht mit dem neuen Passwort überein.' : undefined
            "
            @click:append-inner="showNewPasswordConfirm = !showNewPasswordConfirm"
          />

          <ul class="password-hints">
            <li
              v-for="hint in passwordHints"
              :key="hint.label"
              :class="['password-hint', { 'password-hint--valid': hint.valid }]"
            >
              <v-icon :icon="hint.valid ? 'mdi-check-circle' : 'mdi-circle-outline'" size="14" />
              {{ hint.label }}
            </li>
          </ul>
        </section>

        <p class="change-password-hint">
          <v-icon icon="mdi-information-outline" size="14" />
          Nach erfolgreicher Änderung wirst du automatisch abgemeldet und meldest dich anschließend mit deinem
          neuen Passwort wieder an.
        </p>

        <v-btn
          type="submit"
          variant="elevated"
          size="large"
          prepend-icon="mdi-content-save-outline"
          :loading="isSubmitting"
          :disabled="submitDisabled"
          block
        >
          Passwort speichern
        </v-btn>
      </v-form>
    </section>
  </v-container>
</template>

<style scoped>
.change-password-page {
  --hoard-shell-width: min(720px, 100%);
}

.change-password-shell {
  gap: var(--space-5);
}

.change-password-head {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-4);
  align-items: flex-start;
}

.change-password-head h1 {
  margin: var(--space-1) 0 var(--space-2);
  font-size: var(--font-size-2xl);
  letter-spacing: -0.015em;
}

.change-password-head p {
  margin: 0;
  color: var(--color-text-secondary);
}

.change-password-form {
  display: grid;
  gap: var(--space-4);
}

.change-password-section {
  display: grid;
  gap: var(--space-3);
}

.password-hints {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2);
  padding: 0;
  margin: 0;
  list-style: none;
}

.password-hint {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  line-height: 1.3;
  transition: color var(--transition-fast);
}

.password-hint--valid {
  color: var(--color-primary-700);
}

.password-hint .v-icon {
  flex: 0 0 auto;
}

.change-password-hint {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  background-color: color-mix(in srgb, var(--color-surface-alt) 80%, var(--color-surface) 20%);
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  line-height: 1.45;
}

.change-password-hint .v-icon {
  color: var(--color-primary-700);
  flex: 0 0 auto;
}

@media (prefers-reduced-motion: no-preference) {
  .change-password-shell {
    animation: hoard-soft-enter 280ms both;
  }
}

@media (width <= 600px) {
  .change-password-head {
    grid-template-columns: 1fr;
  }

  .password-hints {
    grid-template-columns: 1fr;
  }
}
</style>
