/**
 * Server-side eTerra session store (global singleton).
 *
 * Holds one shared session for the whole app. Multiple browser clients
 * see the same connection state. The EterraClient already caches sessions
 * by credential hash, so we just store which credentials are active +
 * metadata (who connected, when, running jobs).
 */

import { getProgress } from "./progress-store";

/* ------------------------------------------------------------------ */
/*  Types                                                              */
/* ------------------------------------------------------------------ */

export type EterraSession = {
  /** Username used to connect */
  username: string;
  /** Password (kept in memory only, never sent to clients) */
  password: string;
  /** ISO timestamp of connection */
  connectedAt: string;
  /** Running job IDs — tracked so we can warn before disconnect */
  activeJobs: Set<string>;
};

export type SessionStatus = {
  connected: boolean;
  username?: string;
  connectedAt?: string;
  /** How many jobs are currently running */
  activeJobCount: number;
  /** First running job's phase (for UI hint) */
  activeJobPhase?: string;
  /** eTerra platform health */
  eterraAvailable?: boolean;
  /** True if eTerra is detected as being in maintenance */
  eterraMaintenance?: boolean;
  /** Human-readable health message */
  eterraHealthMessage?: string;
};

/* ------------------------------------------------------------------ */
/*  Global store                                                       */
/* ------------------------------------------------------------------ */

const g = globalThis as { __eterraSessionStore?: EterraSession | null };

function getSession(): EterraSession | null {
  return g.__eterraSessionStore ?? null;
}

function setSession(session: EterraSession | null) {
  g.__eterraSessionStore = session;
}

/* ------------------------------------------------------------------ */
/*  Public API                                                         */
/* ------------------------------------------------------------------ */

export function createSession(username: string, password: string): void {
  setSession({
    username,
    password,
    connectedAt: new Date().toISOString(),
    activeJobs: new Set(),
  });
}

export function destroySession(): { destroyed: boolean; reason?: string } {
  const session = getSession();
  if (!session) return { destroyed: true };

  // Check for running jobs
  const running = getRunningJobs(session);
  if (running.length > 0) {
    return {
      destroyed: false,
      reason: `Există ${running.length} job(uri) active. Așteaptă finalizarea lor înainte de deconectare.`,
    };
  }

  setSession(null);
  return { destroyed: true };
}

export function forceDestroySession(): void {
  setSession(null);
}

export function getSessionCredentials(): {
  username: string;
  password: string;
} | null {
  const session = getSession();
  if (!session) return null;
  return { username: session.username, password: session.password };
}

export function registerJob(jobId: string): void {
  const session = getSession();
  if (session) session.activeJobs.add(jobId);
}

export function unregisterJob(jobId: string): void {
  const session = getSession();
  if (session) session.activeJobs.delete(jobId);
}

export function getSessionStatus(): SessionStatus {
  const session = getSession();
  if (!session) {
    return { connected: false, activeJobCount: 0 };
  }

  const running = getRunningJobs(session);

  // Find one running job's phase for a UI hint
  let activeJobPhase: string | undefined;
  for (const jid of running) {
    const p = getProgress(jid);
    if (p?.phase) {
      activeJobPhase = p.phase;
      break;
    }
  }

  return {
    connected: true,
    username: session.username,
    connectedAt: session.connectedAt,
    activeJobCount: running.length,
    activeJobPhase,
  };
}

/* ------------------------------------------------------------------ */
/*  Helpers                                                            */
/* ------------------------------------------------------------------ */

function getRunningJobs(session: EterraSession): string[] {
  // Guard: ensure activeJobs is iterable (Set). Containers may restart
  // with stale globalThis where the Set was serialized as plain object.
  if (!(session.activeJobs instanceof Set)) {
    session.activeJobs = new Set();
    return [];
  }
  const running: string[] = [];
  for (const jid of session.activeJobs) {
    const p = getProgress(jid);
    if (p && p.status === "running") {
      running.push(jid);
    } else {
      session.activeJobs.delete(jid);
    }
  }
  return running;
}
