/**
 * Local persistent config — ~/.claudemesh/config.json
 *
 * Stores: joined meshes, per-mesh identity keys (ed25519 keypairs),
 * last-seen broker URL. Loaded on CLI start, on MCP server start,
 * and on every join/leave.
 */

import {
  readFileSync,
  writeFileSync,
  existsSync,
  mkdirSync,
  chmodSync,
} from "node:fs";
import { homedir } from "node:os";
import { join, dirname } from "node:path";
import { env } from "../env";

export interface JoinedMesh {
  meshId: string;
  memberId: string;
  slug: string;
  name: string;
  pubkey: string; // ed25519 hex (32 bytes = 64 chars)
  secretKey: string; // ed25519 hex (64 bytes = 128 chars)
  brokerUrl: string;
  joinedAt: string;
  /**
   * Mesh root key (32 bytes) as URL-safe base64url, no padding.
   * Present for v2 invite joins (sealed then unsealed client-side).
   * Absent for v1 joins, where the root key lives inside the saved
   * invite token on disk instead. Used by channel/group `crypto_secretbox`.
   */
  rootKey?: string;
  /** Invite protocol version used to join. `2` for v2, omitted/`1` for legacy. */
  inviteVersion?: 1 | 2;
}

export interface GroupEntry {
  name: string;
  role?: string;
}

export interface Config {
  version: 1;
  meshes: JoinedMesh[];
  displayName?: string; // per-session override, written by `claudemesh launch --name`
  role?: string;        // per-session role tag (display + hello)
  groups?: GroupEntry[];
  messageMode?: "push" | "inbox" | "off";
  accountId?: string;  // linked dashboard user ID (from CLI sync flow)
}

const CONFIG_DIR = env.CLAUDEMESH_CONFIG_DIR ?? join(homedir(), ".claudemesh");
const CONFIG_PATH = join(CONFIG_DIR, "config.json");

export function loadConfig(): Config {
  if (!existsSync(CONFIG_PATH)) {
    return { version: 1, meshes: [] };
  }
  try {
    const raw = readFileSync(CONFIG_PATH, "utf-8");
    const parsed = JSON.parse(raw);
    if (!parsed || !Array.isArray(parsed.meshes)) {
      return { version: 1, meshes: [] };
    }
    return { version: 1, meshes: parsed.meshes, displayName: parsed.displayName, role: parsed.role, groups: parsed.groups, messageMode: parsed.messageMode, accountId: parsed.accountId };
  } catch (e) {
    throw new Error(
      `Failed to load ${CONFIG_PATH}: ${e instanceof Error ? e.message : String(e)}`,
    );
  }
}

export function saveConfig(config: Config): void {
  mkdirSync(dirname(CONFIG_PATH), { recursive: true });
  writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
  // Config holds ed25519 secret keys — restrict to owner read/write.
  try {
    chmodSync(CONFIG_PATH, 0o600);
  } catch {
    // Windows filesystems ignore chmod; that's fine.
  }
}

export function getConfigPath(): string {
  return CONFIG_PATH;
}
