<script setup lang="ts">
/**
 * OAuth callback page.
 *
 * Handles the redirect from OAuth providers (Google, Discord).
 * Extracts tokens from URL fragment, stores them, fetches user
 * profile, and redirects to the appropriate destination.
 *
 * Success URL format: /auth/callback#access_token={token}&refresh_token={token}&expires_in={seconds}
 * Error URL format: /auth/callback?error={code}&message={message}
 */
import { ref, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'

import { useAuthStore } from '@/stores/auth'
import { apiClient } from '@/api/client'
import type { User } from '@/stores/auth'

interface UserResponse {
  id: string
  display_name: string
  avatar_url: string | null
  has_starter_deck: boolean
}

const router = useRouter()
const route = useRoute()
const auth = useAuthStore()

const status = ref<'processing' | 'error'>('processing')
const errorMessage = ref<string | null>(null)

/**
 * Parse tokens from URL hash fragment.
 *
 * The backend redirects with tokens in the fragment (after #) for security,
 * since fragments are not sent to servers in HTTP requests.
 */
function parseTokensFromHash(): { accessToken: string; refreshToken: string; expiresIn: number } | null {
  const hash = window.location.hash.substring(1) // Remove leading #
  if (!hash) return null

  const params = new URLSearchParams(hash)
  const accessToken = params.get('access_token')
  const refreshToken = params.get('refresh_token')
  const expiresIn = params.get('expires_in')

  if (!accessToken || !refreshToken || !expiresIn) {
    return null
  }

  return {
    accessToken,
    refreshToken,
    expiresIn: parseInt(expiresIn, 10),
  }
}

/**
 * Check for error in URL query params.
 */
function parseErrorFromQuery(): { error: string; message: string } | null {
  const error = route.query.error as string | undefined
  const message = route.query.message as string | undefined

  if (error) {
    return {
      error,
      message: message || 'Authentication failed. Please try again.',
    }
  }

  return null
}

/**
 * Fetch user profile from API.
 */
async function fetchUserProfile(): Promise<UserResponse> {
  return apiClient.get<UserResponse>('/api/users/me')
}

/**
 * Transform API response to auth store User type.
 */
function transformUser(response: UserResponse): User {
  return {
    id: response.id,
    displayName: response.display_name,
    avatarUrl: response.avatar_url,
    hasStarterDeck: response.has_starter_deck,
  }
}

/**
 * Handle the OAuth callback process.
 */
async function handleCallback(): Promise<void> {
  // First, check for errors from failed OAuth
  const errorInfo = parseErrorFromQuery()
  if (errorInfo) {
    // Redirect back to login with error message
    router.push({
      name: 'Login',
      query: { error: errorInfo.error, message: errorInfo.message },
    })
    return
  }

  // Parse tokens from URL fragment
  const tokens = parseTokensFromHash()
  if (!tokens) {
    status.value = 'error'
    errorMessage.value = 'Invalid authentication response. Missing tokens.'
    return
  }

  try {
    // Store tokens in auth store
    auth.setTokens({
      accessToken: tokens.accessToken,
      refreshToken: tokens.refreshToken,
      expiresAt: Date.now() + tokens.expiresIn * 1000,
    })

    // Clear the hash from URL for security (tokens shouldn't linger in browser history)
    window.history.replaceState(null, '', window.location.pathname)

    // Fetch user profile
    const userResponse = await fetchUserProfile()
    const user = transformUser(userResponse)
    auth.setUser(user)

    // Redirect based on starter deck status
    if (!user.hasStarterDeck) {
      router.push({ name: 'StarterSelection' })
    } else {
      // Check if there was an intended destination before login
      const redirect = route.query.redirect as string | undefined
      if (redirect && redirect.startsWith('/') && !redirect.startsWith('//')) {
        router.push(redirect)
      } else {
        router.push({ name: 'Dashboard' })
      }
    }
  } catch (error) {
    status.value = 'error'
    if (error instanceof Error) {
      errorMessage.value = error.message
    } else {
      errorMessage.value = 'Failed to complete authentication. Please try again.'
    }
  }
}

onMounted(() => {
  handleCallback()
})

function goToLogin(): void {
  router.push({ name: 'Login' })
}
</script>

<template>
  <div class="flex flex-col items-center justify-center min-h-[50vh] p-4">
    <!-- Processing state -->
    <div
      v-if="status === 'processing'"
      class="text-center"
    >
      <div class="mb-4">
        <svg
          class="animate-spin h-8 w-8 text-primary mx-auto"
          xmlns="http://www.w3.org/2000/svg"
          fill="none"
          viewBox="0 0 24 24"
        >
          <circle
            class="opacity-25"
            cx="12"
            cy="12"
            r="10"
            stroke="currentColor"
            stroke-width="4"
          />
          <path
            class="opacity-75"
            fill="currentColor"
            d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
          />
        </svg>
      </div>
      <div class="text-lg font-medium">
        Completing login...
      </div>
      <div class="text-sm text-gray-400 mt-2">
        Please wait while we set up your session
      </div>
    </div>

    <!-- Error state -->
    <div
      v-else-if="status === 'error'"
      class="text-center max-w-md"
    >
      <div class="mb-4">
        <svg
          class="h-12 w-12 text-error mx-auto"
          xmlns="http://www.w3.org/2000/svg"
          fill="none"
          viewBox="0 0 24 24"
          stroke="currentColor"
        >
          <path
            stroke-linecap="round"
            stroke-linejoin="round"
            stroke-width="2"
            d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
          />
        </svg>
      </div>
      <div class="text-lg font-medium text-error mb-2">
        Authentication Failed
      </div>
      <div class="text-sm text-gray-400 mb-6">
        {{ errorMessage }}
      </div>
      <button
        class="px-6 py-2 bg-primary text-white rounded-lg hover:bg-primary/90 transition-colors"
        @click="goToLogin"
      >
        Back to Login
      </button>
    </div>
  </div>
</template>
