import { resolve } from "node:path";
import { z } from "zod";
import type { AdbConfig } from "./adb.js";

const booleanFromString = z
  .enum(["true", "false"])
  .default("false")
  .transform((value) => value === "true");

const schema = z.object({
  NODE_ENV: z.enum(["development", "test", "production"]).default("development"),
  HOST: z.string().default("127.0.0.1"),
  PORT: z.coerce.number().int().min(1).max(65_535).default(8787),
  DATABASE_PATH: z.string().default(resolve("data/companion.db")),
  SESSION_TTL_HOURS: z.coerce.number().positive().max(24 * 30).default(24),
  COOKIE_SECURE: booleanFromString,
  ALLOWED_ORIGINS: z.string().default("http://mg4pi.local:8787"),
  UPDATE_STATUS_PATH: z.string().default("/var/lib/pi-car-companion/update-status.json"),
  VERSION_FILE: z.string().default(resolve("REVISION")),
  NETWORK_MANAGER_ENABLED: booleanFromString,
  NETWORK_STATUS_PATH: z.string().default("/var/lib/pi-car-companion/network-status.json"),
  NETWORK_COMMAND_PATH: z.string().default("/var/lib/pi-car-companion/network-command.json"),
  NETWORK_CONFIGURATION_REQUEST_PATH: z.string().default("/var/lib/pi-car-companion/network-configuration-request.json"),
  NETWORK_ACTIVITY_PATH: z.string().default("/var/lib/pi-car-companion/network-activity.json"),
  ADB_ENABLED: booleanFromString,
  ADB_PATH: z.string().min(1).default("adb"),
  ADB_SERIAL: z.string().max(128).regex(/^[a-zA-Z0-9._:-]*$/).default(""),
  ADB_TIMEOUT_MS: z.coerce.number().int().min(500).max(15_000).default(3_000)
});

export type AppConfig = {
  nodeEnv: "development" | "test" | "production";
  host: string;
  port: number;
  databasePath: string;
  sessionTtlMs: number;
  cookieSecure: boolean;
  allowedOrigins: ReadonlySet<string>;
  updateStatusPath: string;
  versionFile: string;
  network: {
    enabled: boolean;
    statusPath: string;
    commandPath: string;
    configurationRequestPath: string;
    activityPath: string;
  };
  adb: AdbConfig;
};

export function loadConfig(environment: NodeJS.ProcessEnv = process.env): AppConfig {
  const parsed = schema.parse(environment);
  const allowedOrigins = new Set(
    parsed.ALLOWED_ORIGINS.split(",")
      .map((origin) => origin.trim())
      .filter(Boolean)
  );

  if (parsed.NODE_ENV === "development") {
    allowedOrigins.add("http://localhost:5173");
    allowedOrigins.add("http://127.0.0.1:5173");
  }

  const adbSerial = parsed.ADB_SERIAL.trim() || null;
  return {
    nodeEnv: parsed.NODE_ENV,
    host: parsed.HOST,
    port: parsed.PORT,
    databasePath: parsed.DATABASE_PATH,
    sessionTtlMs: parsed.SESSION_TTL_HOURS * 60 * 60 * 1000,
    cookieSecure: parsed.COOKIE_SECURE,
    allowedOrigins,
    updateStatusPath: parsed.UPDATE_STATUS_PATH,
    versionFile: parsed.VERSION_FILE,
    network: {
      enabled: parsed.NETWORK_MANAGER_ENABLED,
      statusPath: parsed.NETWORK_STATUS_PATH,
      commandPath: parsed.NETWORK_COMMAND_PATH,
      configurationRequestPath: parsed.NETWORK_CONFIGURATION_REQUEST_PATH,
      activityPath: parsed.NETWORK_ACTIVITY_PATH
    },
    adb: {
      enabled: parsed.ADB_ENABLED,
      executable: parsed.ADB_PATH,
      serial: adbSerial,
      timeoutMs: parsed.ADB_TIMEOUT_MS
    }
  };
}
