// §22.8 — the request-to-join API client builds scope-keyed URLs and methods.
import { describe, it, expect, vi, afterEach } from 'vitest'
import { joinTarget, requestJoin, acceptJoinRequest, declineJoinRequest } from './api.js'

function mockFetch() {
  const fn = vi.fn(async () => ({
    ok: true,
    status: 200,
    json: async () => ({ ok: true }),
  }))
  global.fetch = fn
  return fn
}

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

describe('join-request api URLs', () => {
  it('joinTarget GETs the scope join-target', async () => {
    const f = mockFetch()
    await joinTarget('collection', 'features')
    expect(f).toHaveBeenCalledWith('/api/scopes/collection/features/join-target')
  })

  it('requestJoin POSTs the desired role + message', async () => {
    const f = mockFetch()
    await requestJoin('project', 'ohm', { role: 'contributor', message: 'hi' })
    expect(f.mock.calls[0][0]).toBe('/api/scopes/project/ohm/join-requests')
    const opts = f.mock.calls[0][1]
    expect(opts.method).toBe('POST')
    expect(JSON.parse(opts.body)).toEqual({ role: 'contributor', message: 'hi' })
  })

  it('acceptJoinRequest POSTs the accept route with an optional role override', async () => {
    const f = mockFetch()
    await acceptJoinRequest('collection', 'features', 7, 'contributor')
    expect(f.mock.calls[0][0]).toBe('/api/scopes/collection/features/join-requests/7/accept')
    expect(JSON.parse(f.mock.calls[0][1].body)).toEqual({ role: 'contributor' })
  })

  it('declineJoinRequest POSTs the decline route', async () => {
    const f = mockFetch()
    await declineJoinRequest('collection', 'features', 7)
    expect(f.mock.calls[0][0]).toBe('/api/scopes/collection/features/join-requests/7/decline')
    expect(f.mock.calls[0][1].method).toBe('POST')
  })
})
