import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen, fireEvent, waitFor } from '@testing-library/svelte'
import { writable } from 'svelte/store'
import Navbar from './Navbar.svelte'
import { auth } from './stores/auth.js'

const mockPush = vi.fn()
const locationStore = writable('/')
vi.mock('svelte-spa-router', () => ({
  push: (...args) => mockPush(...args),
  location: { subscribe: (...args) => locationStore.subscribe(...args) },
}))

vi.mock('./stores/auth.js', () => {
  const { writable } = require('svelte/store')
  const authStore = writable({ user: null, loading: false, error: null })
  return {
    auth: {
      subscribe: authStore.subscribe,
      set: authStore.set,
      clearError: vi.fn(),
      login: vi.fn().mockResolvedValue(true),
      register: vi.fn().mockResolvedValue({ success: true, needsConfirmation: false }),
      logout: vi.fn(),
    },
  }
})

vi.mock('./api/profile.js', () => ({
  getProfile: vi.fn().mockResolvedValue({ id: 'u1', display_name: 'Test User', email: 'test@example.com' }),
}))

describe('Navbar', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    auth.set({ user: null, loading: false, error: null })
    vi.mocked(auth.login).mockResolvedValue(true)
    vi.mocked(auth.register).mockResolvedValue({ success: true, needsConfirmation: false })
  })

  describe('when logged out', () => {
    it('shows Login button and Community link', () => {
      render(Navbar)
      expect(screen.getByRole('button', { name: 'Login' })).toBeInTheDocument()
      expect(screen.getByRole('link', { name: /Community/i })).toBeInTheDocument()
    })

    it('openPopup: clicking Login opens auth popup', async () => {
      render(Navbar)
      await fireEvent.click(screen.getByRole('button', { name: 'Login' }))
      expect(auth.clearError).toHaveBeenCalled()
      expect(screen.getByRole('dialog', { name: /Sign in/i })).toBeInTheDocument()
      expect(screen.getByPlaceholderText('Email or username')).toBeInTheDocument()
    })

    it('closePopup: Close button closes popup', async () => {
      render(Navbar)
      await fireEvent.click(screen.getByRole('button', { name: 'Login' }))
      await fireEvent.click(screen.getByRole('button', { name: 'Close' }))
      expect(screen.queryByRole('dialog')).not.toBeInTheDocument()
    })

    it('handleBackdropClick: clicking backdrop closes popup', async () => {
      const { container } = render(Navbar)
      await fireEvent.click(screen.getByRole('button', { name: 'Login' }))
      const backdrop = container.querySelector('.popup-backdrop')
      await fireEvent.click(backdrop)
      expect(screen.queryByRole('dialog')).not.toBeInTheDocument()
    })

    it('handleSubmit (login): submit form calls auth.login and closes on success', async () => {
      render(Navbar)
      await fireEvent.click(screen.getByRole('button', { name: 'Login' }))
      const form = screen.getByRole('dialog').querySelector('form')
      await fireEvent.input(screen.getByPlaceholderText('Email or username'), { target: { value: 'a@b.com' } })
      await fireEvent.input(screen.getByPlaceholderText('Password'), { target: { value: 'secret' } })
      await fireEvent.submit(form)
      expect(auth.login).toHaveBeenCalledWith('a@b.com', 'secret')
      await waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument())
    })

    it('switch to Register tab and handleSubmit (register)', async () => {
      render(Navbar)
      await fireEvent.click(screen.getByRole('button', { name: 'Login' }))
      await fireEvent.click(screen.getByRole('button', { name: 'Register' }))
      expect(screen.getByRole('dialog', { name: /Register/i })).toBeInTheDocument()
      await fireEvent.input(screen.getByPlaceholderText('Email'), { target: { value: 'new@b.com' } })
      await fireEvent.input(screen.getByPlaceholderText('Username'), { target: { value: 'newuser' } })
      await fireEvent.input(screen.getByPlaceholderText('Password'), { target: { value: 'secret' } })
      await fireEvent.click(screen.getByRole('button', { name: 'Create account' }))
      expect(auth.register).toHaveBeenCalledWith('new@b.com', 'secret', 'newuser')
    })

    it('handleSubmit returns early when email or password empty', async () => {
      render(Navbar)
      await fireEvent.click(screen.getByRole('button', { name: 'Login' }))
      const form = screen.getByRole('dialog').querySelector('form')
      await fireEvent.submit(form)
      expect(auth.login).not.toHaveBeenCalled()
    })
  })

  describe('when logged in', () => {
    beforeEach(() => {
      auth.set({ user: { id: 'u1' }, loading: false, error: null })
    })

    it('shows My decks, Community, Create deck and user menu', () => {
      render(Navbar)
      expect(screen.getByRole('link', { name: /My decks/i })).toBeInTheDocument()
      expect(screen.getByRole('button', { name: 'Create deck' })).toBeInTheDocument()
      expect(screen.getByRole('button', { name: 'User menu' })).toBeInTheDocument()
    })

    it('toggleUserMenu: opens dropdown and fetches profile', async () => {
      const { getProfile } = await import('./api/profile.js')
      render(Navbar)
      await fireEvent.click(screen.getByRole('button', { name: 'User menu' }))
      expect(screen.getByRole('menu')).toBeInTheDocument()
      expect(screen.getByRole('menuitem', { name: 'Settings' })).toBeInTheDocument()
      expect(screen.getByRole('menuitem', { name: 'Logout' })).toBeInTheDocument()
      await waitFor(() => expect(getProfile).toHaveBeenCalledWith(expect.anything(), 'u1'))
    })

    it('goSettings: Settings link calls push and closes menu', async () => {
      render(Navbar)
      await fireEvent.click(screen.getByRole('button', { name: 'User menu' }))
      await fireEvent.click(screen.getByRole('menuitem', { name: 'Settings' }))
      expect(mockPush).toHaveBeenCalledWith('/settings')
    })

    it('handleLogout: Logout calls auth.logout and push', async () => {
      render(Navbar)
      await fireEvent.click(screen.getByRole('button', { name: 'User menu' }))
      await fireEvent.click(screen.getByRole('menuitem', { name: 'Logout' }))
      expect(auth.logout).toHaveBeenCalled()
      expect(mockPush).toHaveBeenCalledWith('/')
    })

    it('handleClickOutside: click outside user menu closes it', async () => {
      render(Navbar)
      await fireEvent.click(screen.getByRole('button', { name: 'User menu' }))
      expect(screen.getByRole('menu')).toBeInTheDocument()
      await fireEvent.click(document.body)
      expect(screen.queryByRole('menu')).not.toBeInTheDocument()
    })
  })

  it('onProfileUpdated: profile-updated event updates profile', async () => {
    auth.set({ user: { id: 'u1' }, loading: false, error: null })
    render(Navbar)
    await fireEvent.click(screen.getByRole('button', { name: 'User menu' }))
    await waitFor(() => expect(screen.getByText('Test User')).toBeInTheDocument())
    window.dispatchEvent(new CustomEvent('profile-updated', { detail: { id: 'u1', display_name: 'Updated', email: 'u@u.com' } }))
    await waitFor(() => expect(screen.getByText('Updated')).toBeInTheDocument())
  })

  it('brand and Community link call push', async () => {
    render(Navbar)
    await fireEvent.click(screen.getByRole('link', { name: /Omotomo/i }))
    expect(mockPush).toHaveBeenCalledWith('/')
    await fireEvent.click(screen.getByRole('link', { name: /Community/i }))
    expect(mockPush).toHaveBeenCalledWith('/community')
  })
})
