import { z } from 'zod';
import { characterSchema } from '@/lib/schemas/character';
import { systemIdSchema } from '@/lib/schemas/common';

/**
 * Self-contained payload a GM shares with a player ("Share with player"). It
 * carries the character plus enough campaign identity to mirror it locally, so
 * the player can develop the character offline and hand changes back at session
 * start. No server-side token storage — the security gate is the GM's seat grant.
 */
export const claimPayloadSchema = z.object({
  character: characterSchema,
  campaignName: z.string(),
  campaignSystem: systemIdSchema,
});
export type ClaimPayload = z.infer<typeof claimPayloadSchema>;

function toB64url(json: string): string {
  const bytes = new TextEncoder().encode(json);
  let bin = '';
  for (const b of bytes) bin += String.fromCharCode(b);
  return btoa(bin).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}

function fromB64url(s: string): string {
  const b64 = s.replace(/-/g, '+').replace(/_/g, '/');
  const bin = atob(b64);
  const bytes = Uint8Array.from(bin, (ch) => ch.charCodeAt(0));
  return new TextDecoder().decode(bytes);
}

export function encodeClaim(p: ClaimPayload): string {
  return toB64url(JSON.stringify(p));
}

export function decodeClaim(s: string): ClaimPayload | null {
  try {
    const parsed = claimPayloadSchema.safeParse(JSON.parse(fromB64url(s)));
    return parsed.success ? parsed.data : null;
  } catch {
    return null;
  }
}
