<script setup lang="ts">
import { ref, onMounted, computed, watch } from 'vue';
import { useRoute } from 'vue-router';
import { useUserStore } from '@KTXC/stores/userStore';
import { authenticationService } from '@KTXC/services/authenticationService';
import type { AuthenticationMethod, VerifyResponse } from '@KTXC/types/authenticationTypes';
import { Form } from 'vee-validate';

const route = useRoute();
const userStore = useUserStore();

// Login flow phases
type LoginPhase = 'identity' | 'method' | 'mfa';

// Form state
const identity = ref('');
const authResponse = ref(''); // password, code, etc.
const showPassword = ref(false);
const rememberMe = ref(false);

// Auth state
const session = ref<string | null>(null);
const phase = ref<LoginPhase>('identity');
const allMethods = ref<AuthenticationMethod[]>([]);
const availableMethods = ref<AuthenticationMethod[]>([]);
const selectedMethod = ref<AuthenticationMethod | null>(null);
const loading = ref(true);
const submitting = ref(false);
const ssoLoading = ref<string | null>(null);
const error = ref<string | null>(null);
const challengeSent = ref(false);

// Separate methods by type
const redirectMethods = computed(() =>
  allMethods.value.filter(m => m.method === 'redirect')
);

const nonRedirectMethods = computed(() =>
  availableMethods.value.filter(m => m.method !== 'redirect')
);

const hasNonRedirectMethods = computed(() =>
  allMethods.value.some(m => m.method !== 'redirect')
);

// Computed UI states
const showIdentityForm = computed(() => phase.value === 'identity');
const showAuthForm = computed(() => phase.value === 'method' && selectedMethod.value !== null);
const showMfaForm = computed(() => phase.value === 'mfa');
const showSsoButtons = computed(() => redirectMethods.value.length > 0 && phase.value === 'identity');

// Title based on phase
const pageTitle = computed(() => {
  switch (phase.value) {
    case 'identity': return 'Login';
    case 'method': return 'Verify Your Identity';
    case 'mfa': return 'Additional Verification';
    default: return 'Login';
  }
});

// Input label/type based on selected method
const authInputLabel = computed(() => {
  if (!selectedMethod.value) return 'Password';
  return selectedMethod.value.method === 'credential' ? 'Password' : 'Verification Code';
});

const authInputType = computed(() => {
  if (!selectedMethod.value) return 'password';
  return selectedMethod.value.method === 'credential' ? 'password' : 'text';
});

// Validation rules
const identityRules = [
  (v: string) => !!v.trim() || 'Email is required',
  (v: string) => !/\s/.test(v.trim()) || 'Email must not contain spaces',
  (v: string) => /.+@.+\..+/.test(v.trim()) || 'Email must be valid'
];

const authResponseRules = [
  (v: string) => !!v || 'This field is required',
];

// Initialize authentication
onMounted(async () => {
  try {
    // Check for error from SSO callback
    const errorParam = route.query.error as string;
    if (errorParam) {
      error.value = decodeURIComponent(errorParam);
    }

    // Check for MFA session from redirect
    const mfaSession = route.query.session as string;
    if (mfaSession) {
      session.value = mfaSession;
      await loadSessionStatus();
    } else {
      // Initialize new auth session
      await initSession();
    }

    // Auto-trigger SSO if provider param present
    const providerParam = route.query.provider as string;
    if (providerParam && phase.value === 'identity') {
      const provider = allMethods.value.find(m => m.id === providerParam);
      if (provider && provider.method === 'redirect') {
        await initiateSsoLogin(provider.id);
      }
    }
  } catch (e: any) {
    error.value = e.message || 'Failed to initialize authentication';
  } finally {
    loading.value = false;
  }
});

// Watch for method selection changes (for challenge-based methods)
watch(selectedMethod, async (newMethod) => {
  if (newMethod && newMethod.method === 'challenge' && !challengeSent.value) {
    // Initiate challenge for methods that need it (SMS, email, TOTP)
    await initiateChallenge(newMethod.id);
  }
});

// Initialize a new session
async function initSession() {
  const result = await authenticationService.start();
  session.value = result.session;
  allMethods.value = result.methods;
  phase.value = 'identity';
}

// Load existing session status (for MFA continuation)
async function loadSessionStatus() {
  if (!session.value) return;
  
  try {
    const status = await authenticationService.getStatus(session.value);
    
    if (status.state === 'secondary_pending') {
      phase.value = 'mfa';
      availableMethods.value = status.methods;
      if (availableMethods.value.length > 0) {
        selectedMethod.value = availableMethods.value[0];
      }
    } else if (status.state === 'identified') {
      // Session has identity, show method selection
      phase.value = 'method';
      availableMethods.value = status.methods;
      autoSelectMethod();
    } else {
      // Session not in expected state, reinitialize
      await initSession();
    }
  } catch (e) {
    // Session expired or invalid, reinitialize
    await initSession();
  }
}

// Handle identity submission (step 1)
async function handleIdentitySubmit(_values: any, { setErrors }: any) {
  if (!session.value) return;
  
  error.value = null;
  submitting.value = true;

  try {
    const result = await authenticationService.identify(session.value, identity.value.trim());
    
    session.value = result.session;
    availableMethods.value = result.methods;
    phase.value = 'method';
    
    autoSelectMethod();
  } catch (e: any) {
    const errorMessage = e.message || 'Failed to continue. Please try again.';
    setErrors({ apiError: errorMessage });
  } finally {
    submitting.value = false;
  }
}

// Auto-select method if only one available
function autoSelectMethod() {
  const methods = nonRedirectMethods.value;
  if (methods.length === 1) {
    selectedMethod.value = methods[0];
  } else if (methods.length > 1) {
    // Default to credential if available
    const credMethod = methods.find(m => m.method === 'credential');
    selectedMethod.value = credMethod || methods[0];
  }
}

// Handle method selection
function selectMethod(method: AuthenticationMethod) {
  selectedMethod.value = method;
  authResponse.value = '';
  challengeSent.value = false;
}

// Initiate a challenge (for SMS, email, TOTP)
async function initiateChallenge(methodId: string) {
  if (!session.value) return;

  try {
    await authenticationService.beginChallenge(session.value, methodId);
    challengeSent.value = true;
  } catch (e: any) {
    // Challenge initiation failed - show generic error
    error.value = e.message || 'Failed to send verification code.';
  }
}

// Handle authentication response submission (step 2)
async function handleAuthSubmit(_values: any, { setErrors }: any) {
  if (!session.value || !selectedMethod.value) return;

  error.value = null;
  submitting.value = true;

  try {
    const result = await authenticationService.verify(
      session.value,
      selectedMethod.value.id,
      authResponse.value
      // identity is already in session from identify() step
    );

    handleVerifyResponse(result);
  } catch (e: any) {
    const errorMessage = e.message || 'Verification failed. Please try again.';
    setErrors({ apiError: errorMessage });
  } finally {
    submitting.value = false;
  }
}

// Handle MFA verification (step 3)
async function handleMfaSubmit(_values: any, { setErrors }: any) {
  if (!session.value || !selectedMethod.value) return;

  error.value = null;
  submitting.value = true;

  try {
    const result = await authenticationService.verify(
      session.value,
      selectedMethod.value.id,
      authResponse.value
    );

    handleVerifyResponse(result);
  } catch (e: any) {
    const errorMessage = e.message || 'Verification failed. Please try again.';
    setErrors({ apiError: errorMessage });
  } finally {
    submitting.value = false;
  }
}

// Handle verify response
function handleVerifyResponse(result: VerifyResponse) {
  if (result.status === 'success' && result.user) {
    // Authentication complete
    userStore.setAuth(result.user);
    window.location.replace('/');
  } else if (result.status === 'pending') {
    // MFA required
    phase.value = 'mfa';
    availableMethods.value = result.methods || [];
    if (result.session) {
      session.value = result.session;
    }
    if (availableMethods.value.length > 0) {
      selectedMethod.value = availableMethods.value[0];
    }
    authResponse.value = '';
    challengeSent.value = false;
  } else if (result.error) {
    error.value = result.error;
  }
}

// Initiate SSO login
async function initiateSsoLogin(methodId: string) {
  if (!session.value) return;

  ssoLoading.value = methodId;
  error.value = null;

  try {
    const result = await authenticationService.beginRedirect(session.value, methodId, '/');
    window.location.href = result.redirect_url;
  } catch (e: any) {
    error.value = e.message || 'Failed to initiate SSO login';
    ssoLoading.value = null;
  }
}

// Go back to identity phase
function backToIdentity() {
  phase.value = 'identity';
  selectedMethod.value = null;
  authResponse.value = '';
  challengeSent.value = false;
  error.value = null;
  
  // Reinitialize session
  initSession();
}

function getMethodIcon(method: AuthenticationMethod): string {
  if (method.icon) return method.icon;
  switch (method.method) {
    case 'credential': return 'mdi-key';
    case 'challenge': return 'mdi-shield-check';
    case 'redirect': return 'mdi-login';
    default: return 'mdi-shield-check';
  }
}
</script>

<template>
  <div class="d-flex justify-space-between align-center">
    <h3 class="text-h3 text-center mb-0">{{ pageTitle }}</h3>
  </div>

  <!-- Loading state -->
  <div v-if="loading" class="mt-7 text-center">
    <v-progress-circular indeterminate color="primary"></v-progress-circular>
    <p class="mt-2 text-medium-emphasis">Loading login options...</p>
  </div>

  <template v-else>
    <!-- Error Alert -->
    <v-alert v-if="error" type="error" class="mt-4" closable @click:close="error = null">
      {{ error }}
    </v-alert>

    <!-- Phase 1: Identity Input -->
    <template v-if="showIdentityForm">
      <!-- Identity Form -->
      <Form 
        v-if="hasNonRedirectMethods"
        @submit="handleIdentitySubmit" 
        class="loginForm" 
        :class="{ 'mt-7': !showSsoButtons }" 
        v-slot="{ errors, isSubmitting }"
      >
        <div class="mb-6">
          <v-label>Email Address</v-label>
          <v-text-field
            v-model="identity"
            :rules="identityRules"
            class="mt-2"
            required
            hide-details="auto"
            variant="outlined"
            color="primary"
            autocomplete="email"
            autofocus
          ></v-text-field>
        </div>

        <v-btn 
          color="primary" 
          :loading="isSubmitting || submitting" 
          block 
          class="mt-5" 
          variant="flat" 
          size="large" 
          type="submit"
        >
          Continue
        </v-btn>

        <!-- SSO Buttons -->
        <div v-if="showSsoButtons" class="mt-7">
          <v-btn
            v-for="method in redirectMethods"
            :key="method.id"
            color="secondary"
            :loading="ssoLoading === method.id"
            :disabled="ssoLoading !== null"
            block
            class="mb-3"
            variant="outlined"
            size="large"
            @click="initiateSsoLogin(method.id)"
          >
            <v-icon v-if="method.icon" start>{{ method.icon }}</v-icon>
            {{ method.label }}
          </v-btn>
        </div>

        <div v-if="errors.apiError" class="mt-2">
          <v-alert color="error">{{ errors.apiError }}</v-alert>
        </div>
      </Form>

      <!-- No providers -->
      <div v-if="!hasNonRedirectMethods && !showSsoButtons" class="mt-7 text-center">
        <v-alert type="warning">
          No login methods are currently available. Please contact your administrator.
        </v-alert>
      </div>
    </template>

    <!-- Phase 2: Method Selection & Authentication -->
    <template v-else-if="showAuthForm && !showMfaForm">
      <p class="text-body-1 text-medium-emphasis mt-4 mb-2">
        Signing in as <strong>{{ identity }}</strong>
      </p>

      <!-- Method Selector (if multiple methods) -->
      <div v-if="nonRedirectMethods.length > 1" class="mb-4">
        <v-label class="mb-2">Choose verification method</v-label>
        <v-btn-toggle
          :model-value="selectedMethod?.id"
          mandatory
          variant="outlined"
          divided
          class="w-100"
        >
          <v-btn
            v-for="method in nonRedirectMethods"
            :key="method.id"
            :value="method.id"
            @click="selectMethod(method)"
            class="flex-grow-1"
          >
            <v-icon start>{{ getMethodIcon(method) }}</v-icon>
            {{ method.label }}
          </v-btn>
        </v-btn-toggle>
      </div>

      <!-- Auth Response Form -->
      <Form 
        @submit="handleAuthSubmit" 
        class="loginForm mt-4" 
        v-slot="{ errors, isSubmitting }"
      >
        <div class="mb-6">
          <v-label>{{ authInputLabel }}</v-label>
          <v-text-field
            v-model="authResponse"
            :rules="authResponseRules"
            :type="authInputType === 'password' && !showPassword ? 'password' : 'text'"
            class="mt-2"
            required
            hide-details="auto"
            variant="outlined"
            color="primary"
            :autocomplete="selectedMethod?.method === 'credential' ? 'current-password' : 'one-time-code'"
            :inputmode="selectedMethod?.method !== 'credential' ? 'numeric' : undefined"
            autofocus
          >
            <template v-if="authInputType === 'password'" v-slot:append-inner>
              <v-btn
                variant="text"
                density="compact"
                :icon="showPassword ? 'mdi-eye-off' : 'mdi-eye'"
                @click="showPassword = !showPassword"
              ></v-btn>
            </template>
          </v-text-field>
        </div>

        <div v-if="selectedMethod?.method === 'credential'" class="d-flex align-center mt-4 mb-7 mb-sm-0">
          <v-checkbox
            v-model="rememberMe"
            label="Keep me logged in"
            color="primary"
            hide-details
          ></v-checkbox>
          <div class="ml-auto">
            <router-link to="/forgot-password" class="text-primary text-decoration-none">
              Forgot Password?
            </router-link>
          </div>
        </div>

        <v-btn 
          color="primary" 
          :loading="isSubmitting || submitting" 
          block 
          class="mt-5" 
          variant="flat" 
          size="large" 
          type="submit"
        >
          {{ selectedMethod?.method === 'credential' ? 'Login' : 'Verify' }}
        </v-btn>

        <v-btn 
          variant="text" 
          block 
          class="mt-3" 
          @click="backToIdentity"
        >
          Use different account
        </v-btn>

        <div v-if="errors.apiError" class="mt-2">
          <v-alert color="error">{{ errors.apiError }}</v-alert>
        </div>
      </Form>
    </template>

    <!-- Phase 3: MFA Verification -->
    <template v-if="showMfaForm">
      <p class="text-body-1 text-medium-emphasis mt-4 mb-6">
        Additional verification is required. Please enter the code from your {{ selectedMethod?.label || 'authenticator' }}.
      </p>

      <!-- MFA Method Selector (if multiple) -->
      <v-select
        v-if="availableMethods.length > 1"
        v-model="selectedMethod"
        :items="availableMethods"
        item-title="label"
        item-value="id"
        return-object
        label="Verification Method"
        variant="outlined"
        class="mb-4"
      ></v-select>

      <Form @submit="handleMfaSubmit" v-slot="{ errors, isSubmitting }">
        <div class="mb-6">
          <v-label>Verification Code</v-label>
          <v-text-field
            v-model="authResponse"
            :rules="authResponseRules"
            type="text"
            class="mt-2"
            required
            hide-details="auto"
            variant="outlined"
            color="primary"
            autocomplete="one-time-code"
            inputmode="numeric"
            autofocus
          ></v-text-field>
        </div>

        <v-btn 
          color="primary" 
          :loading="isSubmitting || submitting" 
          block 
          class="mt-5" 
          variant="flat" 
          size="large" 
          type="submit"
        >
          Verify
        </v-btn>

        <v-btn 
          variant="text" 
          block 
          class="mt-3" 
          @click="backToIdentity"
        >
          Back to Login
        </v-btn>

        <div v-if="errors.apiError" class="mt-2">
          <v-alert color="error">{{ errors.apiError }}</v-alert>
        </div>
      </Form>
    </template>
  </template>
</template>

<style lang="scss">
.loginForm {
  .v-text-field .v-field--active input {
    font-weight: 500;
  }
}
</style>
