import { join } from 'node:path';
import { mkdirSync, existsSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';

const DATA_PATH = process.env.DATA_PATH ?? join(process.cwd(), 'data');

export type PersistedState = {
  proxySecret: string;
  claudeSessions: Record<string, string>; // sessionKey → Claude Code session_id
};

const DEFAULT_STATE: PersistedState = {
  proxySecret: '',
  claudeSessions: {},
};

let stateDir: string;
let stateFile: string;
let lockFile: string;
let currentState: PersistedState = { ...DEFAULT_STATE };
let saveTimer: Timer | null = null;

/** Call once at startup to configure paths. For proxy: no email. For per-user: pass email. */
export function initPaths(email?: string): void {
  if (email) {
    stateDir = join(DATA_PATH, email, 'sidecar');
    stateFile = join(stateDir, 'claude-state.json');
    lockFile = join(stateDir, 'claude.lock');
  } else {
    stateDir = join(DATA_PATH, 'sidecar');
    stateFile = join(stateDir, 'claude-state.json');
    lockFile = join(stateDir, 'claude.lock');
  }
}

// Default to proxy paths
initPaths();

function ensureDir() {
  if (!existsSync(stateDir)) {
    mkdirSync(stateDir, { recursive: true });
  }
}

export function loadState(): PersistedState {
  ensureDir();
  try {
    if (!existsSync(stateFile)) {
      currentState = { ...DEFAULT_STATE };
      return currentState;
    }
    const text = readFileSync(stateFile, 'utf-8');
    currentState = { ...DEFAULT_STATE, ...JSON.parse(text) };
    return currentState;
  } catch {
    currentState = { ...DEFAULT_STATE };
    return currentState;
  }
}

export async function saveState(): Promise<void> {
  ensureDir();
  await Bun.write(stateFile, JSON.stringify(currentState, null, 2));
}

export function getState(): PersistedState {
  return currentState;
}

export function updateState(patch: Partial<PersistedState>): void {
  Object.assign(currentState, patch);
  scheduleSave();
}

export function setClaudeSession(sessionKey: string, sessionId: string): void {
  currentState.claudeSessions[sessionKey] = sessionId;
  scheduleSave();
}

export function clearClaudeSession(sessionKey: string): void {
  delete currentState.claudeSessions[sessionKey];
  scheduleSave();
}

export function getClaudeSession(sessionKey: string): string | undefined {
  return currentState.claudeSessions[sessionKey];
}

function scheduleSave() {
  if (saveTimer) return;
  saveTimer = setTimeout(async () => {
    saveTimer = null;
    await saveState();
  }, 30_000);
}

export async function flushAndSave(): Promise<void> {
  if (saveTimer) {
    clearTimeout(saveTimer);
    saveTimer = null;
  }
  await saveState();
}

// ── Lockfile ──

export function acquireLock(): boolean {
  ensureDir();
  try {
    if (existsSync(lockFile)) {
      const pidStr = readFileSync(lockFile, 'utf-8').trim();
      const pid = Number(pidStr);
      if (pid && isProcessAlive(pid)) {
        return false;
      }
    }
    writeFileSync(lockFile, String(process.pid));
    return true;
  } catch {
    return false;
  }
}

export function releaseLock(): void {
  try {
    if (existsSync(lockFile)) {
      unlinkSync(lockFile);
    }
  } catch {
    // best effort
  }
}

function isProcessAlive(pid: number): boolean {
  try {
    process.kill(pid, 0);
    return true;
  } catch {
    return false;
  }
}
