/// Device management — reads/writes .relicario/devices.json and revoked.json

import type { GitHost } from './git-host';
import type { Device } from '../shared/types';

const DEVICES_PATH = '.relicario/devices.json';
const REVOKED_PATH = '.relicario/revoked.json';

interface DevicesFile {
  devices: Device[];
}

export interface RevokedEntry {
  name: string;
  public_key: string;
  revoked_at: number;   // unix timestamp
  revoked_by: string;   // name of device that performed the revocation
}

export async function readDevices(gitHost: GitHost): Promise<Device[]> {
  try {
    const raw = await gitHost.readFile(DEVICES_PATH);
    const text = new TextDecoder().decode(raw);
    const parsed: DevicesFile = JSON.parse(text);
    return parsed.devices ?? [];
  } catch {
    return [];
  }
}

export async function writeDevices(
  gitHost: GitHost,
  devices: Device[],
  message: string,
): Promise<void> {
  const content: DevicesFile = { devices };
  const bytes = new TextEncoder().encode(JSON.stringify(content, null, 2));
  await gitHost.writeFile(DEVICES_PATH, bytes, message);
}

export async function readRevoked(gitHost: GitHost): Promise<RevokedEntry[]> {
  try {
    const raw = await gitHost.readFile(REVOKED_PATH);
    const text = new TextDecoder().decode(raw);
    return JSON.parse(text) as RevokedEntry[];
  } catch {
    return [];
  }
}

async function writeRevoked(
  gitHost: GitHost,
  revoked: RevokedEntry[],
  message: string,
): Promise<void> {
  const bytes = new TextEncoder().encode(JSON.stringify(revoked, null, 2));
  await gitHost.writeFile(REVOKED_PATH, bytes, message);
}

export async function addDevice(
  gitHost: GitHost,
  device: Device,
): Promise<void> {
  const existing = await readDevices(gitHost);
  if (existing.some((d) => d.name === device.name)) {
    throw new Error(`device '${device.name}' already exists`);
  }
  existing.push(device);
  await writeDevices(gitHost, existing, `device: add ${device.name}`);
}

export async function revokeDevice(
  gitHost: GitHost,
  name: string,
  revokedBy?: string,
): Promise<void> {
  const existing = await readDevices(gitHost);
  const device = existing.find((d) => d.name === name);
  if (!device) {
    throw new Error(`device '${name}' not found`);
  }

  // Remove from devices.json
  const filtered = existing.filter((d) => d.name !== name);
  await writeDevices(gitHost, filtered, `device: revoke ${name}`);

  // Add to revoked.json
  const revoked = await readRevoked(gitHost);
  revoked.push({
    name,
    public_key: device.public_key,
    revoked_at: Math.floor(Date.now() / 1000),
    revoked_by: revokedBy ?? 'unknown',
  });
  await writeRevoked(gitHost, revoked, `device: revoke ${name} (revoked log)`);
}
