import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { setActivePinia, createPinia } from 'pinia'
import { useAdminStore } from '../src/stores/admin.js'

// Covers the two helpers the admin store actions route through (DRY Finding C,
// #753): _dryRunPost (URL + dry_run body, sourceId→source_id) and _guard
// (lastError capture + rethrow). The store had no frontend test before.

function stubFetch(handler) {
  globalThis.fetch = vi.fn(async (url, init) => {
    const { status, body } = handler(url, init)
    return {
      ok: status >= 200 && status < 300,
      status,
      statusText: String(status),
      text: async () => (body == null ? '' : JSON.stringify(body)),
    }
  })
}

function lastCallBody(calls) {
  return JSON.parse(calls.at(-1).init.body)
}

describe('admin store', () => {
  beforeEach(() => setActivePinia(createPinia()))
  afterEach(() => vi.restoreAllMocks())

  it('_dryRunPost sends the apply flag to the right endpoint', async () => {
    const s = useAdminStore()
    const calls = []
    stubFetch((url, init) => {
      calls.push({ url, init })
      return { status: 200, body: { deleted: 0 } }
    })
    await s.pruneUnusedTags({ dryRun: false })
    const c = calls.at(-1)
    expect(c.url).toContain('/api/admin/tags/prune-unused')
    expect(c.init.method).toBe('POST')
    expect(lastCallBody(calls)).toEqual({ dry_run: false })
  })

  it('_dryRunPost defaults to the safe preview', async () => {
    const s = useAdminStore()
    const calls = []
    stubFetch((url, init) => {
      calls.push({ url, init })
      return { status: 200, body: { count: 0 } }
    })
    await s.pruneBarePosts()
    expect(lastCallBody(calls)).toEqual({ dry_run: true })
  })

  it('reconcileDuplicatePosts maps sourceId → source_id', async () => {
    const s = useAdminStore()
    const calls = []
    stubFetch((url, init) => {
      calls.push({ url, init })
      return { status: 200, body: { groups: 0 } }
    })
    await s.reconcileDuplicatePosts({ dryRun: false, sourceId: 42 })
    const c = calls.at(-1)
    expect(c.url).toContain('/api/admin/posts/reconcile-duplicates')
    expect(lastCallBody(calls)).toEqual({ dry_run: false, source_id: 42 })
  })

  it('_guard captures the error message on lastError and rethrows', async () => {
    const s = useAdminStore()
    stubFetch(() => ({ status: 500, body: { error: 'boom' } }))
    await expect(s.deleteTag(7)).rejects.toThrow('boom')
    expect(s.lastError).toBe('boom')
  })

  it('_guard clears lastError on a subsequent success', async () => {
    const s = useAdminStore()
    stubFetch(() => ({ status: 500, body: { error: 'boom' } }))
    await expect(s.deleteTag(7)).rejects.toThrow()
    expect(s.lastError).toBe('boom')

    stubFetch(() => ({ status: 200, body: { count: 3 } }))
    const n = await s.tagUsageCount(7)
    expect(n).toBe(3)  // tagUsageCount returns body.count, not the raw body
    expect(s.lastError).toBe(null)
  })
})
