import { upsertPushDevice, getPushDevices, deletePushDevice } from 'officerdb';

// Device registration, reached through the platform's authenticated proxy.
//
// The caller comes from X-Officer-User, injected by createSidecarProxy and trusted because this server
// binds loopback only. Nothing else can reach it.
//
// Every route here is scoped to that id, including the DELETE — which takes a token from the URL, and a
// token is the address of a device rather than a secret.

const PLATFORMS = new Set(['ios', 'android']);
const ENVIRONMENTS = new Set(['production', 'sandbox']);

type RegisterBody = {
  token?: string;
  platform?: string;
  environment?: string;
  bundleId?: string;
  appSlug?: string;
};

function ownerId(req: Request): number | null {
  const id = Number(req.headers.get('X-Officer-User'));
  return Number.isFinite(id) && id > 0 ? id : null;
}

export async function handleDeviceRoute(req: Request, url: URL): Promise<Response | null> {
  const userId = ownerId(req);
  if (userId === null) return Response.json({ error: 'missing X-Officer-User' }, { status: 401 });

  if (url.pathname === '/_officer/devices' && req.method === 'GET') {
    const devices = await getPushDevices(userId, url.searchParams.get('appSlug') ?? undefined);
    // Never echo tokens back in full: they are the address of a device, and this response goes to a
    // client. Enough to identify a row, not enough to push to it.
    return Response.json({
      devices: devices.map((d) => ({
        id: d.id,
        platform: d.platform,
        environment: d.environment,
        bundleId: d.bundleId,
        appSlug: d.appSlug,
        tokenSuffix: d.token.slice(-8),
        lastSeenAt: d.lastSeenAt,
      })),
    });
  }

  if (url.pathname === '/_officer/devices' && req.method === 'POST') {
    let body: RegisterBody;
    try {
      body = (await req.json()) as RegisterBody;
    } catch {
      return Response.json({ error: 'invalid json' }, { status: 400 });
    }

    const { token, platform, bundleId, appSlug } = body;
    const environment = body.environment ?? 'production';

    if (!token || !platform || !bundleId || !appSlug) {
      return Response.json({ error: 'token, platform, bundleId and appSlug are required' }, { status: 400 });
    }
    if (!PLATFORMS.has(platform)) {
      return Response.json({ error: "platform must be 'ios' or 'android'" }, { status: 400 });
    }
    // Rejected rather than defaulted: an iOS token from a debug build fails against production APNs with
    // a silent BadDeviceToken, so a wrong value here is a device that never receives anything and never
    // reports why.
    if (!ENVIRONMENTS.has(environment)) {
      return Response.json({ error: "environment must be 'production' or 'sandbox'" }, { status: 400 });
    }

    const device = await upsertPushDevice({ userId, token, platform, environment, bundleId, appSlug });
    return Response.json({ ok: true, id: device.id });
  }

  const match = url.pathname.match(/^\/_officer\/devices\/(.+)$/);
  if (match && req.method === 'DELETE') {
    await deletePushDevice(decodeURIComponent(match[1]!), userId);
    return Response.json({ ok: true });
  }

  return null;
}
