/**
 * The wire format.
 *
 * Imported by BOTH the route handlers and the client hooks, so any drift
 * between server and client is a type error rather than a runtime surprise.
 * When a real backend arrives this file is the negotiation artifact — it is
 * already the contract, not a description of one.
 */

export type RangeKey = '7d' | '30d' | '90d' | 'mtd' | 'ytd' | 'custom';

export interface ApiMeta {
  /** The SERVER's clock. Every relative time in the UI measures against it. */
  generatedAt: string;
  /**
   * The scope the server actually applied, echoed back. Optional because not
   * every endpoint is scoped — auth has no range and no store, and forcing it
   * to invent one would make the envelope lie about what it answered.
   */
  range?: RangeKey;
  storeId?: string;
}

export interface ApiSuccess<T> {
  data: T;
  meta: ApiMeta;
}

export type ApiErrorCode =
  | 'internal'
  | 'not_found'
  | 'bad_request'
  | 'unauthorized';

export interface ApiFailure {
  error: {code: ApiErrorCode; message: string};
}

export type ApiResponse<T> = ApiSuccess<T> | ApiFailure;

export function isFailure<T>(r: ApiResponse<T>): r is ApiFailure {
  return (r as ApiFailure).error !== undefined;
}
