import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen, fireEvent, waitFor } from '@testing-library/svelte'
import CreateDeck from './CreateDeck.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 mockCreateDeck = vi.fn()
vi.mock('../lib/api/decks.js', () => ({
  createDeck: (...args) => mockCreateDeck(...args),
}))

describe('CreateDeck', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    auth.set({ user: { id: 'u1' }, loading: false, error: null })
    mockCreateDeck.mockResolvedValue('new-deck-id')
  })

  it('shows form when user is logged in', async () => {
    render(CreateDeck)
    await waitFor(() => expect(screen.getByPlaceholderText('Deck title')).toBeInTheDocument())
    expect(screen.getByRole('button', { name: 'Save deck' })).toBeInTheDocument()
  })

  it('shows sign in message when user is null', () => {
    auth.set({ user: null, loading: false, error: null })
    render(CreateDeck)
    expect(screen.getByText('Sign in to create a deck.')).toBeInTheDocument()
  })

  it('Cancel calls push to home', async () => {
    render(CreateDeck)
    await waitFor(() => expect(screen.getByPlaceholderText('Deck title')).toBeInTheDocument())
    await fireEvent.click(screen.getByRole('button', { name: 'Cancel' }))
    expect(mockPush).toHaveBeenCalledWith('/')
  })

  it('loadFromJson sets error for invalid JSON', async () => {
    render(CreateDeck)
    await waitFor(() => expect(screen.getByPlaceholderText('Deck title')).toBeInTheDocument())
    const textarea = screen.getByPlaceholderText(/Paste deck JSON/)
    await fireEvent.input(textarea, { target: { value: 'not json' } })
    await fireEvent.click(screen.getByRole('button', { name: 'Load from JSON' }))
    expect(screen.getByText(/Invalid JSON/)).toBeInTheDocument()
  })

  it('loadFromJson sets error when title missing', async () => {
    render(CreateDeck)
    await waitFor(() => expect(screen.getByPlaceholderText('Deck title')).toBeInTheDocument())
    const textarea = screen.getByPlaceholderText(/Paste deck JSON/)
    await fireEvent.input(textarea, { target: { value: '{"description":"x","questions":[{"prompt":"Q","answers":["A"],"correctAnswerIndices":[0]}]}' } })
    await fireEvent.click(screen.getByRole('button', { name: 'Load from JSON' }))
    expect(screen.getByText(/must include a "title"/)).toBeInTheDocument()
  })

  it('loadFromJson populates title and questions from valid JSON', async () => {
    render(CreateDeck)
    await waitFor(() => expect(screen.getByPlaceholderText('Deck title')).toBeInTheDocument())
    const validJson = JSON.stringify({
      title: 'Imported Deck',
      description: 'Desc',
      questions: [{ prompt: 'Question?', answers: ['A', 'B'], correctAnswerIndices: [0] }],
    })
    const textarea = screen.getByPlaceholderText(/Paste deck JSON/)
    await fireEvent.input(textarea, { target: { value: validJson } })
    await fireEvent.click(screen.getByRole('button', { name: 'Load from JSON' }))
    expect(screen.getByDisplayValue('Imported Deck')).toBeInTheDocument()
    expect(screen.getByDisplayValue('Question?')).toBeInTheDocument()
  })

  it('save with empty title shows error', async () => {
    render(CreateDeck)
    await waitFor(() => expect(screen.getByPlaceholderText('Deck title')).toBeInTheDocument())
    await fireEvent.click(screen.getByRole('button', { name: 'Save deck' }))
    expect(screen.getByText('Title is required')).toBeInTheDocument()
    expect(mockCreateDeck).not.toHaveBeenCalled()
  })

  it('save with title and question calls createDeck and pushes home', async () => {
    render(CreateDeck)
    await waitFor(() => expect(screen.getByPlaceholderText('Deck title')).toBeInTheDocument())
    await fireEvent.input(screen.getByPlaceholderText('Deck title'), { target: { value: 'My Deck' } })
    await fireEvent.input(screen.getByPlaceholderText('Prompt'), { target: { value: 'First question?' } })
    await fireEvent.input(screen.getByPlaceholderText('Answer 1'), { target: { value: 'Yes' } })
    await fireEvent.click(screen.getByRole('button', { name: 'Save deck' }))
    await waitFor(() => expect(mockCreateDeck).toHaveBeenCalled())
    expect(mockCreateDeck).toHaveBeenCalledWith('u1', expect.objectContaining({ title: 'My Deck' }))
    expect(mockPush).toHaveBeenCalledWith('/')
  })

  it('Add question button adds a question editor', async () => {
    render(CreateDeck)
    await waitFor(() => expect(screen.getByText('Question 1')).toBeInTheDocument())
    await fireEvent.click(screen.getByRole('button', { name: '+ Add question' }))
    expect(screen.getByText('Question 2')).toBeInTheDocument()
  })
})
