// @vitest-environment jsdom
import { beforeEach, describe, expect, it, vi } from 'vitest'
import type { EntityRef } from '@platform-modules/content'

type ApiErrorBody = { error?: { code?: string; message?: string } }

async function apiFetch<T>(url: string, init?: RequestInit): Promise<T> {
  const headers = new Headers(init?.headers)
  if (init?.body != null && !headers.has('Content-Type')) {
    headers.set('Content-Type', 'application/json')
  }

  const res = await fetch(url, {
    ...init,
    credentials: 'same-origin',
    headers,
  })

  const body: unknown = await res.json().catch(() => null)

  if (!res.ok) {
    const err = body as ApiErrorBody | null
    const message = err?.error?.message ?? res.statusText
    throw new Error(message)
  }

  return body as T
}

const ref: EntityRef = { id: 'entry-1', slug: 'hello', type: 'post' }

beforeEach(() => {
  vi.restoreAllMocks()
})

describe('ContentClient HTTP mutations (host adapter contract)', () => {
  it('trash POSTs { id } to /api/admin/trash and returns EntityRef', async () => {
    const fetchMock = vi.fn(async () => new Response(JSON.stringify(ref), { status: 200 }))
    vi.stubGlobal('fetch', fetchMock)

    const result = await apiFetch<EntityRef>('/api/admin/trash', {
      method: 'POST',
      body: JSON.stringify({ id: ref.id }),
    })

    const [url, init] = fetchMock.mock.calls[0] as unknown as [string, RequestInit]
    expect(url).toBe('/api/admin/trash')
    expect(init.method).toBe('POST')
    expect(JSON.parse(init.body as string)).toEqual({ id: ref.id })
    expect(result).toEqual(ref)
  })

  it('restore POSTs { id } to /api/admin/restore and returns EntityRef', async () => {
    const fetchMock = vi.fn(async () => new Response(JSON.stringify(ref), { status: 200 }))
    vi.stubGlobal('fetch', fetchMock)

    const result = await apiFetch<EntityRef>('/api/admin/restore', {
      method: 'POST',
      body: JSON.stringify({ id: ref.id }),
    })

    const [url, init] = fetchMock.mock.calls[0] as unknown as [string, RequestInit]
    expect(url).toBe('/api/admin/restore')
    expect(init.method).toBe('POST')
    expect(result.id).toBe(ref.id)
  })

  it('remove DELETEs { id } to /api/admin/remove and rejects with nested error message', async () => {
    const fetchMock = vi.fn(async () =>
      new Response(JSON.stringify({ error: { code: 'not_found', message: 'Entry not found' } }), {
        status: 404,
      }),
    )
    vi.stubGlobal('fetch', fetchMock)

    const promise = apiFetch<EntityRef>('/api/admin/remove', {
      method: 'DELETE',
      body: JSON.stringify({ id: ref.id }),
    })

    await expect(promise).rejects.toThrow('Entry not found')
    const [url, init] = fetchMock.mock.calls[0] as unknown as [string, RequestInit]
    expect(url).toBe('/api/admin/remove')
    expect(init.method).toBe('DELETE')
  })
})
