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

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

vi.mock('../lib/stores/auth.js', () => {
  const { writable } = require('svelte/store')
  const store = writable({ user: { id: 'u1' }, loading: false, error: null })
  return { auth: { subscribe: store.subscribe, set: store.set } }
})

const mockFetchPublishedDecks = vi.fn()
const mockCopyDeckToUser = vi.fn()
vi.mock('../lib/api/decks.js', () => ({
  fetchPublishedDecks: (...args) => mockFetchPublishedDecks(...args),
  copyDeckToUser: (...args) => mockCopyDeckToUser(...args),
  getMyDeckRating: vi.fn(),
  submitDeckRating: vi.fn(),
}))

describe('Community', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    auth.set({ user: { id: 'u1' }, loading: false, error: null })
    mockFetchPublishedDecks.mockResolvedValue([])
  })

  it('shows loading then empty message when no decks', async () => {
    render(Community)
    expect(screen.getByText(/Loading/)).toBeInTheDocument()
    await waitFor(() => expect(screen.getByText(/No published decks yet/)).toBeInTheDocument())
    expect(mockFetchPublishedDecks).toHaveBeenCalled()
  })

  it('shows error when fetch fails', async () => {
    mockFetchPublishedDecks.mockRejectedValue(new Error('Network error'))
    render(Community)
    await waitFor(() => expect(screen.getByText('Network error')).toBeInTheDocument())
  })

  it('renders deck list and goPreview on card click', async () => {
    mockFetchPublishedDecks.mockResolvedValue([
      {
        id: 'd1',
        title: 'Cool Deck',
        description: 'A deck',
        owner_id: 'o1',
        owner_display_name: 'Alice',
        owner_email: 'a@b.com',
        question_count: 5,
        average_rating: 4.5,
        rating_count: 2,
        user_has_this: false,
      },
    ])
    render(Community)
    await waitFor(() => expect(screen.getByText('Cool Deck')).toBeInTheDocument())
    await fireEvent.click(screen.getByRole('button', { name: /Cool Deck/ }))
    expect(mockPush).toHaveBeenCalledWith('/decks/d1/preview')
  })

  it('handleUse without userId shows sign in error', async () => {
    auth.set({ user: null, loading: false, error: null })
    mockFetchPublishedDecks.mockResolvedValue([
      { id: 'd1', title: 'Deck', owner_id: 'o1', owner_display_name: 'A', question_count: 1, user_has_this: false },
    ])
    render(Community)
    await waitFor(() => expect(screen.getByText('Deck')).toBeInTheDocument())
    await fireEvent.click(screen.getByRole('button', { name: 'Add' }))
    expect(screen.getByText(/Sign in to add this deck/)).toBeInTheDocument()
    expect(mockCopyDeckToUser).not.toHaveBeenCalled()
  })

  it('handleUse with userId calls copyDeckToUser and reloads', async () => {
    mockFetchPublishedDecks
      .mockResolvedValueOnce([
        { id: 'd1', title: 'Deck', owner_id: 'o1', owner_display_name: 'A', question_count: 1, user_has_this: false },
      ])
      .mockResolvedValueOnce([
        { id: 'd1', title: 'Deck', owner_id: 'o1', owner_display_name: 'A', question_count: 1, user_has_this: true },
      ])
    mockCopyDeckToUser.mockResolvedValue(undefined)
    render(Community)
    await waitFor(() => expect(screen.getByRole('button', { name: 'Add' })).toBeInTheDocument())
    await fireEvent.click(screen.getByRole('button', { name: 'Add' }))
    await waitFor(() => expect(mockCopyDeckToUser).toHaveBeenCalledWith(expect.anything(), 'd1', 'u1'))
    await waitFor(() => expect(screen.getByText('In My decks')).toBeInTheDocument())
  })
})
