import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useSurveyStore } from './survey'

vi.mock('../composables/useApi', () => ({
  useApiFetch: vi.fn(),
}))

import { useApiFetch } from '../composables/useApi'

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

  afterEach(() => {
    vi.clearAllMocks()
  })

  it('fetchFor loads history and vision availability in parallel', async () => {
    const mockApiFetch = vi.mocked(useApiFetch)
    mockApiFetch
      .mockResolvedValueOnce({ data: [], error: null })                    // history
      .mockResolvedValueOnce({ data: { available: true }, error: null })   // vision

    const store = useSurveyStore()
    await store.fetchFor(1)

    expect(store.history).toEqual([])
    expect(store.visionAvailable).toBe(true)
    expect(store.currentJobId).toBe(1)
    expect(mockApiFetch).toHaveBeenCalledTimes(2)
  })

  it('fetchFor clears state when called for a different job', async () => {
    const mockApiFetch = vi.mocked(useApiFetch)
    // Job 1
    mockApiFetch
      .mockResolvedValueOnce({ data: [{ id: 1, llm_output: 'old' }], error: null })
      .mockResolvedValueOnce({ data: { available: false }, error: null })

    const store = useSurveyStore()
    await store.fetchFor(1)
    expect(store.history.length).toBe(1)

    // Job 2 — state must be cleared before new data arrives
    mockApiFetch
      .mockResolvedValueOnce({ data: [], error: null })
      .mockResolvedValueOnce({ data: { available: true }, error: null })

    await store.fetchFor(2)
    expect(store.history).toEqual([])
    expect(store.currentJobId).toBe(2)
  })

  it('analyze stores result including mode and rawInput', async () => {
    vi.useFakeTimers()
    const mockApiFetch = vi.mocked(useApiFetch)
    // POST → task accepted
    mockApiFetch.mockResolvedValueOnce({ data: { task_id: 7, is_new: true }, error: null })
    // Poll → completed with result
    mockApiFetch.mockResolvedValueOnce({
      data: { status: 'completed', stage: null, message: null,
              result: { output: '1. B — reason', source: 'text_paste' } },
      error: null,
    })

    const store = useSurveyStore()
    await store.analyze(1, { text: 'Q1: test', mode: 'quick' })
    await vi.advanceTimersByTimeAsync(3000)

    expect(store.analysis).not.toBeNull()
    expect(store.analysis!.output).toBe('1. B — reason')
    expect(store.analysis!.source).toBe('text_paste')
    expect(store.analysis!.mode).toBe('quick')
    expect(store.analysis!.rawInput).toBe('Q1: test')
    expect(store.loading).toBe(false)
    vi.useRealTimers()
  })

  it('analyze sets error on failure', async () => {
    const mockApiFetch = vi.mocked(useApiFetch)
    mockApiFetch.mockResolvedValueOnce({
      data: null,
      error: { kind: 'http', status: 500, detail: 'LLM unavailable' },
    })

    const store = useSurveyStore()
    await store.analyze(1, { text: 'Q1: test', mode: 'quick' })

    expect(store.analysis).toBeNull()
    expect(store.error).toBeTruthy()
    expect(store.loading).toBe(false)
  })

  it('saveResponse prepends to history and clears analysis', async () => {
    const mockApiFetch = vi.mocked(useApiFetch)
    // Setup: fetchFor
    mockApiFetch
      .mockResolvedValueOnce({ data: [], error: null })
      .mockResolvedValueOnce({ data: { available: true }, error: null })

    const store = useSurveyStore()
    await store.fetchFor(1)

    // Set analysis state manually (as if analyze() was called)
    store.analysis = {
      output: '1. B — reason',
      source: 'text_paste',
      mode: 'quick',
      rawInput: 'Q1: test',
    }

    // Save
    mockApiFetch.mockResolvedValueOnce({
      data: { id: 42 },
      error: null,
    })

    await store.saveResponse(1, { surveyName: 'Round 1', reportedScore: '85%' })

    expect(store.history.length).toBe(1)
    expect(store.history[0].id).toBe(42)
    expect(store.history[0].llm_output).toBe('1. B — reason')
    expect(store.analysis).toBeNull()
    expect(store.saving).toBe(false)
  })

  it('saveResponse sets error and preserves analysis on POST failure', async () => {
    const mockApiFetch = vi.mocked(useApiFetch)
    // Setup: fetchFor
    mockApiFetch
      .mockResolvedValueOnce({ data: [], error: null })
      .mockResolvedValueOnce({ data: { available: true }, error: null })

    const store = useSurveyStore()
    await store.fetchFor(1)

    // Set analysis state manually
    store.analysis = {
      output: '1. B — reason',
      source: 'text_paste',
      mode: 'quick',
      rawInput: 'Q1: test',
    }

    // Save fails
    mockApiFetch.mockResolvedValueOnce({
      data: null,
      error: { kind: 'http', status: 500, detail: 'Internal Server Error' },
    })

    await store.saveResponse(1, { surveyName: 'Round 1', reportedScore: '85%' })

    expect(store.saving).toBe(false)
    expect(store.error).toBeTruthy()
    expect(store.analysis).not.toBeNull()
    expect(store.analysis!.output).toBe('1. B — reason')
  })

  it('clear resets all state to initial values', async () => {
    const mockApiFetch = vi.mocked(useApiFetch)
    mockApiFetch
      .mockResolvedValueOnce({ data: [{ id: 1, llm_output: 'test' }], error: null })
      .mockResolvedValueOnce({ data: { available: true }, error: null })

    const store = useSurveyStore()
    await store.fetchFor(1)

    store.clear()

    expect(store.history).toEqual([])
    expect(store.analysis).toBeNull()
    expect(store.visionAvailable).toBe(false)
    expect(store.loading).toBe(false)
    expect(store.saving).toBe(false)
    expect(store.error).toBeNull()
    expect(store.currentJobId).toBeNull()
  })
})
