/**
 * Epic 1: Authentication & User Management
 * Component Test: Navigation
 * 
 * Tests the navigation component for proper display based on session state
 */

import { describe, it, expect, mock, beforeEach, afterEach } from 'bun:test'
import { render, screen, waitFor } from '@testing-library/react'
import Navigation from '@/components/Navigation'
import { RoleSwitcherProvider } from '@/components/RoleSwitcher'

// Mock next/link
mock.module('next/link', () => ({
  default: ({ children, href }: { children: React.ReactNode; href: string }) => (
    <a href={href}>{children}</a>
  ),
}))

// Mock the SessionProvider
mock.module('@/components/SessionProvider', () => ({
  useSession: mock(() => ({ session: null, loading: false, refreshSession: mock(() => {}) })),
}))

// Mock the auth-client
mock.module('@/lib/auth-client', () => ({
  authClient: {
    signOut: mock(() => {}),
  },
}))

// Mock fetch for role API call
global.fetch = mock(async () => new Response()) as any

function renderNavigation() {
  return render(
    <RoleSwitcherProvider>
      <Navigation />
    </RoleSwitcherProvider>
  )
}

import { useSession as useSessionOriginal } from '@/components/SessionProvider'
const useSession = useSessionOriginal as any

describe('Epic 1: Navigation Component', () => {
  beforeEach(() => {
    // Don't clear all mocks as it might affect bun-setup.ts
    // Set up default fetch mock
    (global.fetch as any).mockImplementation?.(async (url: any) => {
      if (url?.toString().includes('/api/users/')) {
        return new Response(JSON.stringify({ role: 'player' }), {
          status: 200,
          headers: { 'Content-Type': 'application/json' },
        })
      }
      return new Response(JSON.stringify({}), { status: 200 })
    })
  })

  afterEach(() => {
    // Don't clear mocks - let them persist for other test files
    // Navigation relies on module mocks set up at file level
  })

  it('renders the logo and basic links when not logged in', () => {
    (useSession).mockReturnValue({
      session: null,
      loading: false,
      refreshSession: mock(() => {}),
    })

    renderNavigation()

    expect(screen.getByText('EuchreCamp')).toBeInTheDocument()
    expect(screen.getByText('Rankings')).toBeInTheDocument()
    expect(screen.getByText('Sign in')).toBeInTheDocument()
    expect(screen.getByText('Sign up')).toBeInTheDocument()
  })

  it('shows user menu when logged in', async () => {
    (useSession).mockReturnValue({
      session: {
        user: { 
          id: 'user-123',
          email: 'test@example.com', 
          name: 'Test User',
          role: 'player'
        },
        session: { token: 'abc123' },
      },
      loading: false,
      refreshSession: mock(() => {}),
    })

    renderNavigation()

    await waitFor(() => {
      expect(screen.getByText('Test User')).toBeInTheDocument()
    })
    
    expect(screen.getByText('Sign out')).toBeInTheDocument()
    expect(screen.getByText('Tournaments')).toBeInTheDocument()
  })

  it('shows Tournaments link when logged in', async () => {
    (useSession).mockReturnValue({
      session: {
        user: { 
          id: 'user-123',
          email: 'test@example.com', 
          name: 'Test User',
          role: 'player'
        },
        session: { token: 'abc123' },
      },
      loading: false,
      refreshSession: mock(() => {}),
    })

    renderNavigation()

    await waitFor(() => {
      expect(screen.getByText('Tournaments')).toBeInTheDocument()
    })
  })

  it('shows admin link for club_admin role', async () => {
    (useSession).mockReturnValue({
      session: {
        user: {
          id: 'admin-123',
          email: 'admin@example.com',
          name: 'Admin User',
          role: 'club_admin',
        },
        session: { token: 'abc123' },
      },
      loading: false,
      refreshSession: mock(() => {}),
    });

    // Mock fetch to return club_admin role
    (global.fetch as any).mockImplementation(async (url: any) => {
      if (url?.toString().includes('/api/users/admin-123/role')) {
        return new Response(JSON.stringify({ role: 'club_admin' }), {
          status: 200,
          headers: { 'Content-Type': 'application/json' },
        })
      }
      return new Response(JSON.stringify({}), { status: 200 })
    })

    renderNavigation()

    await waitFor(() => {
      expect(screen.getByText('Admin')).toBeInTheDocument()
    }, { timeout: 3000 })
    expect(screen.getByText('Tournaments')).toBeInTheDocument()
  })

  it('hides admin link for non-admin users', async () => {
    (useSession).mockReturnValue({
      session: {
        user: {
          id: 'player-123',
          email: 'player@example.com',
          name: 'Player User',
          role: 'player',
        },
        session: { token: 'abc123' },
      },
      loading: false,
      refreshSession: mock(() => {}),
    });

    // Mock fetch to return player role (already set in beforeEach, but explicit here)
    (global.fetch as any).mockImplementation(async (url: any) => {
      if (url?.toString().includes('/api/users/')) {
        return {
          json: () => Promise.resolve({ role: 'player' }),
        } as Response
      }
      return {
        json: () => Promise.resolve({}),
      } as Response
    })

    renderNavigation()

    await waitFor(() => {
      expect(screen.getByText('Tournaments')).toBeInTheDocument()
    })
    expect(screen.queryByText('Admin')).not.toBeInTheDocument()
  })

  it('shows loading state', () => {
    (useSession).mockReturnValue({
      session: null,
      loading: true,
      refreshSession: mock(() => {}),
    })

    renderNavigation()

    expect(screen.getByText('Loading...')).toBeInTheDocument()
  })
})
