// Cold-launch gap-fill against the bulk `since` endpoint. Collapses an
// N-page forward catch-up into one MGET-backed round-trip. Server-side
// caps the window at 48 h (`MAX_SINCE_MINUTES = 2880`) — values older
// than that return a `since_too_old` 422 so the client knows to discard
// its cache and re-bootstrap from `currentPage` instead.
//
// Server implementation: app/Halflight/Http/Controllers/TapestryController.php
// (in the Halflight server fork).

import { ContextForActiveAccount } from 'src/lib/api-context'

export type BucketRow = { bucket: string; letters: string }

export class TapestrySinceTooOldError extends Error {
  readonly status = 422
  readonly code = 'since_too_old'
  constructor(public readonly maxMinutes: number) {
    super(`since bucket older than ${maxMinutes} minutes`)
    this.name = 'TapestrySinceTooOldError'
  }
}

export class TapestrySinceNotSupportedError extends Error {
  readonly status = 404
  constructor() {
    super('server does not support /api/v1/tapestry/since')
    this.name = 'TapestrySinceNotSupportedError'
  }
}

/**
 * Bulk fetch every populated bucket from `sinceBucket` (inclusive)
 * through `now`. Throws `TapestrySinceTooOldError` when the server's
 * 48 h cap rejects the request, and `TapestrySinceNotSupportedError`
 * when the server hasn't yet deployed the endpoint (typed 404 so
 * callers can fall back to the page walk rather than treating it
 * as a generic failure).
 */
// Server-side cap on the `since` lookback window (matches
// `TapestryController::MAX_SINCE_MINUTES`). Hard-coded client-side
// because `ApiContext` doesn't surface response bodies on errors and
// the cap is a stable contract, not a runtime-tuned value.
export const MAX_SINCE_MINUTES = 2880

export async function fetchTapestrySince(sinceBucket: string): Promise<BucketRow[]> {
  const ctx = ContextForActiveAccount()
  let res: Response
  try {
    res = await ctx.request(`/api/v1/tapestry/since/${sinceBucket}`, { method: 'GET' })
  } catch (err: any) {
    // `ApiContext.request` throws `ApiError` for non-2xx; surface the
    // typed 404 (server hasn't deployed `since` yet) so callers can
    // fall back to the page-by-page walk.
    if (err?.status === 404) throw new TapestrySinceNotSupportedError()
    // 422 with `error: 'since_too_old'` — server's JSON `error` field
    // lands in `ApiError.message` (api-context.ts:490–495).
    if (err?.status === 422 && err?.message === 'since_too_old') {
      throw new TapestrySinceTooOldError(MAX_SINCE_MINUTES)
    }
    throw err
  }
  return (await res.json()) as BucketRow[]
}
