/**
 * Real-encoding regression test for M2-T10 (REWORK 1).
 *
 * Motivation: RecordsPage.test.tsx mocks the entire apiClient module, so
 * openapi-fetch's defaultPathSerializer never runs in those tests. That means
 * the integration between hooks.ts and the real client cannot be verified there.
 *
 * This file uses two complementary strategies:
 *
 * A) Direct serializer test — import openapi-fetch's defaultPathSerializer and
 *    verify that raw PK values (with ':') produce single-encoded URLs (%3A,
 *    NOT %253A). This is a pure-function test with no network I/O.
 *
 * B) Live fetch stub — create a real openapi-fetch client instance with a
 *    custom fetch stub, call the same path that hooks.ts calls (with a raw PK),
 *    and assert the URL the client constructs contains exactly one level of
 *    encoding. This exercises the full openapi-fetch → URL-construction path.
 *
 * Together these prove:
 *  1. openapi-fetch encodes raw ':' correctly (as '%3A', once).
 *  2. The path template /api/poo/{timestamp} with a raw timestamp produces
 *     the right URL — and would break if encodeURIComponent were applied first.
 */

import { describe, it, expect, vi, afterEach } from 'vitest'
import createClient, { defaultPathSerializer } from 'openapi-fetch'
import type { paths } from '../api/schema.d.ts'

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

// ---------------------------------------------------------------------------
// A) defaultPathSerializer unit tests
// ---------------------------------------------------------------------------

describe('openapi-fetch defaultPathSerializer (raw PK → single-encoded URL)', () => {
  it('encodes a poo timestamp with colons exactly once', () => {
    const template = '/api/poo/{timestamp}'
    const rawTs = '2026-06-12T10:00:00Z'
    const result = defaultPathSerializer(template, { timestamp: rawTs })
    // Single-encoded colon
    expect(result).toContain('%3A')
    // Double-encoded colon must NOT appear
    expect(result).not.toContain('%253A')
    expect(result).toBe('/api/poo/2026-06-12T10%3A00%3A00Z')
  })

  it('encodes location person+datetime with colons exactly once', () => {
    const template = '/api/locations/{person}/{datetime}'
    const rawDt = '2026-06-12T09:00:00Z'
    const result = defaultPathSerializer(template, { person: 'alice', datetime: rawDt })
    expect(result).toContain('%3A')
    expect(result).not.toContain('%253A')
    expect(result).toBe('/api/locations/alice/2026-06-12T09%3A00%3A00Z')
  })

  it('pre-encoding a PK before passing it causes double-encoding (%253A)', () => {
    // This test documents the BUG that was present before REWORK 1:
    // hooks.ts was calling encodeURIComponent(timestamp) before passing to
    // the client, so defaultPathSerializer would encode it a second time.
    const template = '/api/poo/{timestamp}'
    const rawTs = '2026-06-12T10:00:00Z'
    const preEncoded = encodeURIComponent(rawTs) // what the old hooks.ts did
    const result = defaultPathSerializer(template, { timestamp: preEncoded })
    // Double-encoded: '%' → '%25', then '3A' stays → '%253A'
    expect(result).toContain('%253A')
    // This is WRONG — after fix, hooks must NOT pre-encode.
  })
})

// ---------------------------------------------------------------------------
// B) Live fetch-stub test using a real openapi-fetch client instance
// ---------------------------------------------------------------------------

describe('real openapi-fetch client URL construction (fetch-stub)', () => {
  it('DELETE /api/poo/{timestamp} with raw PK produces single-encoded URL', async () => {
    const capturedUrls: string[] = []
    const fakeFetch = vi.fn((_input: RequestInfo | URL) => {
      const url =
        typeof _input === 'string'
          ? _input
          : _input instanceof URL
            ? _input.href
            : (_input as Request).url
      capturedUrls.push(url)
      return Promise.resolve(new Response(null, { status: 204 }))
    })

    // Create a real client with our fake fetch — same config as client.ts
    // but with an explicit fetch override so we control the transport.
    const testClient = createClient<paths>({
      baseUrl: 'http://localhost/',
      fetch: fakeFetch as typeof fetch,
    })

    const rawTs = '2026-06-12T10:00:00Z'
    await testClient.DELETE('/api/poo/{timestamp}', {
      params: { path: { timestamp: rawTs } },
    })

    expect(fakeFetch).toHaveBeenCalled()
    const url = capturedUrls[0]
    expect(url).toBeDefined()

    // Single-encoded colon: present
    expect(url).toContain('%3A')
    // Double-encoded colon: must be absent
    expect(url).not.toContain('%253A')
    expect(url).toContain('/api/poo/2026-06-12T10%3A00%3A00Z')
  })

  it('DELETE /api/locations/{person}/{datetime} with raw PK produces single-encoded URL', async () => {
    const capturedUrls: string[] = []
    const fakeFetch = vi.fn((_input: RequestInfo | URL) => {
      const url =
        typeof _input === 'string'
          ? _input
          : _input instanceof URL
            ? _input.href
            : (_input as Request).url
      capturedUrls.push(url)
      return Promise.resolve(new Response(null, { status: 204 }))
    })

    const testClient = createClient<paths>({
      baseUrl: 'http://localhost/',
      fetch: fakeFetch as typeof fetch,
    })

    const rawDt = '2026-06-12T09:00:00Z'
    await testClient.DELETE('/api/locations/{person}/{datetime}', {
      params: { path: { person: 'alice', datetime: rawDt } },
    })

    expect(fakeFetch).toHaveBeenCalled()
    const url = capturedUrls[0]
    expect(url).toBeDefined()

    expect(url).toContain('%3A')
    expect(url).not.toContain('%253A')
    expect(url).toContain('/api/locations/alice/2026-06-12T09%3A00%3A00Z')
  })

  it('double-encoded PK produces wrong URL — documents the fixed bug', async () => {
    // This test shows what the OLD hooks.ts would produce.
    // It is intentionally asserting the BAD behavior to document the regression.
    const capturedUrls: string[] = []
    const fakeFetch = vi.fn((_input: RequestInfo | URL) => {
      const url =
        typeof _input === 'string'
          ? _input
          : _input instanceof URL
            ? _input.href
            : (_input as Request).url
      capturedUrls.push(url)
      return Promise.resolve(new Response(null, { status: 204 }))
    })

    const testClient = createClient<paths>({
      baseUrl: 'http://localhost/',
      fetch: fakeFetch as typeof fetch,
    })

    const rawTs = '2026-06-12T10:00:00Z'
    // Simulate what the old hooks.ts did: pre-encode before passing to client
    const preEncoded = encodeURIComponent(rawTs)
    await testClient.DELETE('/api/poo/{timestamp}', {
      params: { path: { timestamp: preEncoded } },
    })

    const url = capturedUrls[0]
    // The OLD code would produce double-encoding (%253A), which caused 404 on the backend
    expect(url).toContain('%253A')
  })
})
