import { buildBackup, restoreBackup } from '@/lib/io/backup';

/**
 * Optional cloud account + backup sync against the same-origin server (/api).
 * Local-first stays the default: this only does anything when the user signs in.
 * Sync is a whole-backup push/pull (last-write-wins), not a live merge.
 */

const TOKEN_KEY = 'ttrpg-cloud-token';
const USER_KEY = 'ttrpg-cloud-user';
const base = () => `${location.origin}/api`;

export function cloudUsername(): string | null { return localStorage.getItem(USER_KEY); }
function token(): string | null { return localStorage.getItem(TOKEN_KEY); }
function setSession(t: string, username: string): void { localStorage.setItem(TOKEN_KEY, t); localStorage.setItem(USER_KEY, username); }
function clearSession(): void { localStorage.removeItem(TOKEN_KEY); localStorage.removeItem(USER_KEY); }

export class CloudError extends Error {}

async function authPost(path: string, body: unknown): Promise<{ token: string; username: string }> {
  let res: Response;
  try {
    res = await fetch(`${base()}${path}`, { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify(body) });
  } catch {
    throw new CloudError('Could not reach the server.');
  }
  const data = (await res.json().catch(() => ({}))) as { token?: string; username?: string; message?: string };
  if (!res.ok || !data.token) throw new CloudError(data.message ?? 'Request failed.');
  setSession(data.token, data.username ?? '');
  return { token: data.token, username: data.username ?? '' };
}

export function register(username: string, password: string) { return authPost('/register', { username, password }); }
export function login(username: string, password: string) { return authPost('/login', { username, password }); }

export async function logout(): Promise<void> {
  const t = token();
  if (t) { try { await fetch(`${base()}/logout`, { method: 'POST', headers: { authorization: `Bearer ${t}` } }); } catch { /* ignore */ } }
  clearSession();
}

/** Upload this device's full backup to the cloud. */
export async function pushBackup(): Promise<number> {
  const t = token();
  if (!t) throw new CloudError('Not signed in.');
  const blob = JSON.stringify(await buildBackup());
  const res = await fetch(`${base()}/save`, { method: 'PUT', headers: { 'content-type': 'application/json', authorization: `Bearer ${t}` }, body: JSON.stringify({ blob }) });
  if (res.status === 401) { clearSession(); throw new CloudError('Session expired — sign in again.'); }
  if (!res.ok) throw new CloudError('Upload failed.');
  return blob.length;
}

/** Replace this device's data with the cloud copy. Returns false if there's no cloud save yet. */
export async function pullBackup(): Promise<boolean> {
  const t = token();
  if (!t) throw new CloudError('Not signed in.');
  const res = await fetch(`${base()}/save`, { headers: { authorization: `Bearer ${t}` } });
  if (res.status === 404) return false;
  if (res.status === 401) { clearSession(); throw new CloudError('Session expired — sign in again.'); }
  if (!res.ok) throw new CloudError('Download failed.');
  await restoreBackup(await res.text());
  return true;
}
