import { describe, it, expect, beforeEach } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'

import { useAuthStore } from './auth'

describe('useAuthStore', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
  })

  it('starts with no authenticated user', () => {
    /**
     * Test that the auth store initializes in an unauthenticated state.
     *
     * New users should not be authenticated until they complete OAuth flow,
     * ensuring protected routes are inaccessible by default.
     */
    const store = useAuthStore()

    expect(store.isAuthenticated).toBe(false)
    expect(store.user).toBeNull()
    expect(store.accessToken).toBeNull()
    expect(store.refreshToken).toBeNull()
  })

  it('tracks loading state', () => {
    /**
     * Test that the loading state ref is accessible.
     *
     * Components need to check loading state to show spinners
     * and disable buttons during async operations.
     */
    const store = useAuthStore()

    expect(store.isLoading).toBe(false)
  })

  it('tracks error state', () => {
    /**
     * Test that the error state ref is accessible.
     *
     * Components need to display error messages when
     * token refresh or other auth operations fail.
     */
    const store = useAuthStore()

    expect(store.error).toBeNull()
  })

  it('setTokens updates auth state', () => {
    /**
     * Test that setTokens correctly stores OAuth tokens.
     *
     * After OAuth callback, tokens are extracted from URL and
     * stored via setTokens. This should update all token refs
     * and make isAuthenticated return true.
     */
    const store = useAuthStore()

    store.setTokens({
      accessToken: 'test-access-token',
      refreshToken: 'test-refresh-token',
      expiresAt: Date.now() + 3600000,
    })

    expect(store.accessToken).toBe('test-access-token')
    expect(store.refreshToken).toBe('test-refresh-token')
    expect(store.isAuthenticated).toBe(true)
  })

  it('setUser updates user data', () => {
    /**
     * Test that setUser correctly stores user profile data.
     *
     * After fetching user profile, setUser is called to store
     * the basic user info needed for guards and UI display.
     */
    const store = useAuthStore()

    store.setUser({
      id: 'user-123',
      displayName: 'Test User',
      avatarUrl: 'https://example.com/avatar.png',
      hasStarterDeck: true,
    })

    expect(store.user).toEqual({
      id: 'user-123',
      displayName: 'Test User',
      avatarUrl: 'https://example.com/avatar.png',
      hasStarterDeck: true,
    })
  })

  it('logout clears all auth state', async () => {
    /**
     * Test that logout clears all authentication state.
     *
     * When user logs out, all tokens and user data should be
     * cleared to prevent unauthorized access.
     */
    const store = useAuthStore()

    // Set up authenticated state
    store.setTokens({
      accessToken: 'test-access-token',
      refreshToken: 'test-refresh-token',
      expiresAt: Date.now() + 3600000,
    })
    store.setUser({
      id: 'user-123',
      displayName: 'Test User',
      avatarUrl: null,
      hasStarterDeck: false,
    })

    // Logout (without server call in test)
    await store.logout(false)

    expect(store.accessToken).toBeNull()
    expect(store.refreshToken).toBeNull()
    expect(store.user).toBeNull()
    expect(store.isAuthenticated).toBe(false)
  })

  it('isTokenExpired returns true when no expiry set', () => {
    /**
     * Test that tokens without expiry are considered expired.
     *
     * If expiresAt is null (e.g., before tokens are set), the
     * token should be treated as expired to force refresh.
     */
    const store = useAuthStore()

    expect(store.isTokenExpired).toBe(true)
  })

  it('isTokenExpired returns false for future expiry', () => {
    /**
     * Test that tokens with future expiry are not expired.
     *
     * Valid tokens should not trigger refresh attempts.
     */
    const store = useAuthStore()

    store.setTokens({
      accessToken: 'test-access-token',
      refreshToken: 'test-refresh-token',
      expiresAt: Date.now() + 3600000, // 1 hour from now
    })

    expect(store.isTokenExpired).toBe(false)
  })

  it('isTokenExpired returns true for past expiry', () => {
    /**
     * Test that tokens with past expiry are considered expired.
     *
     * Expired tokens should trigger refresh before API calls.
     */
    const store = useAuthStore()

    store.setTokens({
      accessToken: 'test-access-token',
      refreshToken: 'test-refresh-token',
      expiresAt: Date.now() - 1000, // 1 second ago
    })

    expect(store.isTokenExpired).toBe(true)
  })

  it('getOAuthUrl returns correct provider URL with redirect_uri', () => {
    /**
     * Test that OAuth URLs are correctly generated.
     *
     * The login page uses these URLs to redirect users to
     * OAuth providers for authentication. The redirect_uri
     * tells the backend where to send the user after OAuth.
     */
    const store = useAuthStore()

    const googleUrl = store.getOAuthUrl('google')
    const discordUrl = store.getOAuthUrl('discord')

    expect(googleUrl).toContain('/api/auth/google')
    expect(googleUrl).toContain('redirect_uri=')
    expect(discordUrl).toContain('/api/auth/discord')
    expect(discordUrl).toContain('redirect_uri=')
  })
})
