import { afterEach, describe, expect, it, vi } from 'vitest'

function installBrowser(_token?: string) {
  const store = new Map<string, string>()
  Object.defineProperty(globalThis, 'window', {
    configurable: true,
    value: {
      localStorage: {
        getItem: vi.fn((key: string) => store.get(key) ?? null),
        setItem: vi.fn((key: string, value: string) => store.set(key, value)),
        removeItem: vi.fn((key: string) => store.delete(key)),
      },
    },
  })
  return store
}

afterEach(() => {
  vi.restoreAllMocks()
  Reflect.deleteProperty(globalThis, 'window')
  Reflect.deleteProperty(globalThis, 'fetch')
  vi.resetModules()
})

describe('renter client helpers', () => {
  it('clears renter sessions through the API logout endpoint', async () => {
    installBrowser('renter-token')
    const fetchMock = vi.fn(async () => ({ ok: true, json: async () => ({ data: { success: true } }) }))
    Object.defineProperty(globalThis, 'fetch', { configurable: true, value: fetchMock })
    const { clearRenterSession } = await import('./renter')

    clearRenterSession()

    expect(fetchMock).toHaveBeenCalledWith(expect.stringMatching(/\/api\/v1\/auth\/renter\/logout$/), expect.objectContaining({
      method: 'POST',
      credentials: 'include',
    }))
  })

  it('sends cookies and unwraps renter profile data', async () => {
    installBrowser('renter-token')
    const fetchMock = vi.fn(async () => ({ ok: true, status: 200, json: async () => ({ data: { id: 'renter_1' } }) }))
    Object.defineProperty(globalThis, 'fetch', { configurable: true, value: fetchMock })
    const { loadRenterProfile } = await import('./renter')

    await expect(loadRenterProfile()).resolves.toEqual({ id: 'renter_1' })
    expect(fetchMock).toHaveBeenCalledWith(expect.stringMatching(/\/api\/v1\/auth\/renter\/me$/), expect.objectContaining({
      credentials: 'include',
      headers: expect.objectContaining({ 'Content-Type': 'application/json' }),
    }))
  })

  it('removes stale tokens and throws renter auth errors on 401', async () => {
    installBrowser('expired-token')
    Object.defineProperty(globalThis, 'fetch', {
      configurable: true,
      value: vi.fn(async () => ({ ok: false, status: 401, json: async () => ({ message: 'Unauthorized' }) })),
    })
    const { loadRenterNotifications, RenterAuthError } = await import('./renter')

    await expect(loadRenterNotifications()).rejects.toBeInstanceOf(RenterAuthError)

  })

  it('serializes preference updates to the renter notification endpoint', async () => {
    installBrowser('renter-token')
    const fetchMock = vi.fn(async () => ({ ok: true, json: async () => ({ data: { success: true } }) }))
    Object.defineProperty(globalThis, 'fetch', { configurable: true, value: fetchMock })
    const { updateRenterPreferences } = await import('./renter')
    const body = [{ notificationType: 'reservation', channel: 'email', enabled: true }]

    await expect(updateRenterPreferences(body)).resolves.toEqual({ success: true })
    expect(fetchMock).toHaveBeenCalledWith(expect.stringMatching(/\/api\/v1\/notifications\/renter\/preferences$/), expect.objectContaining({
      method: 'PATCH',
      body: JSON.stringify(body),
    }))
  })
})
