import type sql from "mssql";
import type {
  ISessionStore,
  ILeaderboardStore,
  IMetricsStore,
  IPlayerStore,
  IAnonymousTrialStore,
} from "./types";
import { JsonSessionStore } from "./json-session-store";
import { JsonLeaderboardStore } from "./json-leaderboard-store";
import { JsonMetricsStore } from "./json-metrics-store";
import { JsonPlayerStore } from "./json-player-store";
import { JsonAnonymousTrialStore } from "./json-anonymous-trial-store";

export type {
  ISessionStore,
  ILeaderboardStore,
  IMetricsStore,
  IPlayerStore,
  IAnonymousTrialStore,
  GameSession,
  GameplayRecord,
  CreateGameSessionInput,
  AnonymousTrialClaim,
  PlayerRecord,
} from "./types";

let sessionStore: ISessionStore;
let leaderboardStore: ILeaderboardStore;
let metricsStore: IMetricsStore;
let playerStore: IPlayerStore;
let anonymousTrialStore: IAnonymousTrialStore;
let mssqlPool: sql.ConnectionPool | undefined;

export type StorageBackend = "json" | "mssql";

export function getStorageBackend(): StorageBackend {
  const value = process.env.STORAGE_BACKEND ?? "json";
  if (value !== "json" && value !== "mssql") {
    throw new Error(`Invalid STORAGE_BACKEND: ${value}. Must be "json" or "mssql".`);
  }
  return value;
}

function isProductionLikeRuntime(): boolean {
  return process.env.NODE_ENV === "production" || Boolean(process.env.KUBERNETES_SERVICE_HOST);
}

function isDeployedJsonTestMode(): boolean {
  return (
    process.env.ALLOW_DEPLOYED_JSON_STORAGE_FOR_TESTS === "true" &&
    process.env.AI_MOCK_MODE === "true"
  );
}

function assertStorageBackendAllowed(backend: StorageBackend): void {
  if (
    backend === "json" &&
    isProductionLikeRuntime() &&
    !isDeployedJsonTestMode()
  ) {
    throw new Error(
      "Refusing to start with STORAGE_BACKEND=json in production or deployed mode. " +
      "Set STORAGE_BACKEND=mssql and DATABASE_URL."
    );
  }
}

export async function initStorage(): Promise<void> {
  const backend = getStorageBackend();
  assertStorageBackendAllowed(backend);

  if (backend === "mssql") {
    if (mssqlPool) return;

    const databaseUrl = process.env.DATABASE_URL?.trim();
    if (!databaseUrl) {
      throw new Error("DATABASE_URL is required when STORAGE_BACKEND=mssql");
    }

    const mssql = await import("mssql");
    const { runMigrations } = await import("./migrate");
    const { MssqlSessionStore } = await import("./mssql-session-store");
    const { MssqlLeaderboardStore } = await import("./mssql-leaderboard-store");
    const { MssqlMetricsStore } = await import("./mssql-metrics-store");

    const pool = new mssql.default.ConnectionPool(databaseUrl);
    try {
      await pool.connect();

      await pool.request().query("SELECT 1");
      console.log("[storage] Azure SQL connection verified");

      await runMigrations(pool);
      console.log("[storage] migrations complete");

      mssqlPool = pool;
      sessionStore = new MssqlSessionStore(pool);
      leaderboardStore = new MssqlLeaderboardStore(pool);
      metricsStore = new MssqlMetricsStore(pool);
      const { MssqlPlayerStore } = await import("./mssql-player-store");
      const { MssqlAnonymousTrialStore } = await import("./mssql-anonymous-trial-store");
      playerStore = new MssqlPlayerStore(pool);
      anonymousTrialStore = new MssqlAnonymousTrialStore(pool);
      console.log("[storage] backend=mssql ready");
    } catch (error) {
      try { await pool.close(); } catch { /* ignore close errors on failed pool */ }
      throw error;
    }
  } else {
    sessionStore = new JsonSessionStore();
    leaderboardStore = new JsonLeaderboardStore();
    metricsStore = new JsonMetricsStore();
    playerStore = new JsonPlayerStore();
    anonymousTrialStore = new JsonAnonymousTrialStore();
    console.log("[storage] backend=json ready");
  }
}

export function getSessionStore(): ISessionStore {
  if (!sessionStore) throw new Error("Storage not initialized. Call initStorage() first.");
  return sessionStore;
}

export function getLeaderboardStore(): ILeaderboardStore {
  if (!leaderboardStore) throw new Error("Storage not initialized. Call initStorage() first.");
  return leaderboardStore;
}

export function getMetricsStore(): IMetricsStore {
  if (!metricsStore) throw new Error("Storage not initialized. Call initStorage() first.");
  return metricsStore;
}

export function getPlayerStore(): IPlayerStore {
  if (!playerStore) throw new Error("Storage not initialized. Call initStorage() first.");
  return playerStore;
}

export function getAnonymousTrialStore(): IAnonymousTrialStore {
  if (!anonymousTrialStore) throw new Error("Storage not initialized. Call initStorage() first.");
  return anonymousTrialStore;
}

export async function shutdownStorage(): Promise<void> {
  if (mssqlPool) {
    await mssqlPool.close();
    mssqlPool = undefined;
    console.log("[storage] Azure SQL pool closed");
  }
}
