// config.js - Configuration handling
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import log4js from "log4js";
import { startWaiting, stopWaiting } from "./spinner.js";

// Determine environment
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const isPackaged = __dirname.includes("app.asar");

if (!process.env.NODE_ENV) {
  process.env.NODE_ENV = "production";
}
const NODE_ENV = process.env.NODE_ENV;

// Configure paths
function getProductionConfigPath() {
  const homeDir = process.env.HOME || process.env.USERPROFILE || "";
  switch (process.platform) {
    case "win32":
      return path.join(
        process.env.PROGRAMDATA || "C:\\ProgramData",
        "farmcontrol-server",
        "config.json",
      );
    case "darwin":
      return path.join(
        homeDir,
        "Library",
        "Application Support",
        "farmcontrol-server",
        "config.json",
      );
    case "linux":
    default:
      return "/etc/farmcontrol-server/config.json";
  }
}

function getDevelopmentConfigPath() {
  // If we're in a packaged app (asar), we can't write to the app directory.
  // We should use a writable user data directory instead.
  if (isPackaged) {
    const homeDir = process.env.HOME || process.env.USERPROFILE || "";
    switch (process.platform) {
      case "win32":
        return path.join(
          process.env.APPDATA || path.join(homeDir, "AppData", "Roaming"),
          "farmcontrol-server",
          "config.json",
        );
      case "darwin":
        return path.join(
          homeDir,
          "Library",
          "Application Support",
          "farmcontrol-server",
          "config.json",
        );
      default:
        return path.join(
          homeDir,
          ".config",
          "farmcontrol-server",
          "config.json",
        );
    }
  }
  return path.resolve(__dirname, "../config.json");
}

const CONFIG_PATH =
  NODE_ENV === "production"
    ? getProductionConfigPath()
    : getDevelopmentConfigPath();

const logger = log4js.getLogger("Config");
logger.level = "info";

function getDefaultProductionDataDir() {
  const homeDir = process.env.HOME || process.env.USERPROFILE || "";
  switch (process.platform) {
    case "win32":
      return path.join(
        process.env.PROGRAMDATA || "C:\\ProgramData",
        "farmcontrol-server",
        "data",
      );
    case "darwin":
      return path.join(
        homeDir,
        "Library",
        "Application Support",
        "farmcontrol-server",
        "data",
      );
    case "linux":
    default:
      return "/var/lib/farmcontrol-server";
  }
}

function getDefaultDevelopmentDataDir() {
  if (isPackaged) {
    return path.join(path.dirname(getDevelopmentConfigPath()), "data");
  }
  return path.resolve(__dirname, "../data");
}

function resolveDataDir(envConfig) {
  let dataDir = envConfig.dataDir;
  const wasMissing = !dataDir;

  if (!dataDir) {
    dataDir =
      NODE_ENV === "production"
        ? getDefaultProductionDataDir()
        : getDefaultDevelopmentDataDir();
  }

  dataDir = path.resolve(dataDir);

  if (!fs.existsSync(dataDir)) {
    fs.mkdirSync(dataDir, { recursive: true });
    logger.info(`Created data directory at ${dataDir}`);
  }

  return { dataDir, shouldPersist: wasMissing && NODE_ENV === "production" };
}

const DEFAULT_CONFIG = {
  development: {
    logLevel: "debug",
    url: "https://dev-wss.tombutcher.work",
    apiUrl: "https://dev.tombutcher.work/api",
    host: {
      id: "",
      authCode: "",
    },
  },
  production: {
    logLevel: "info",
    url: "https://ws.farmcontrol.app",
    apiUrl: "https://api.farmcontrol.app",
    host: {
      id: "",
      authCode: "",
    },
  },
};

// Load config file
export function loadConfig() {
  try {
    if (!fs.existsSync(CONFIG_PATH)) {
      logger.info(
        `Configuration file not found at ${CONFIG_PATH}. Creating a new one.`,
      );
      const configDir = path.dirname(CONFIG_PATH);
      if (!fs.existsSync(configDir)) {
        fs.mkdirSync(configDir, { recursive: true });
      }
      fs.writeFileSync(
        CONFIG_PATH,
        JSON.stringify(DEFAULT_CONFIG, null, 2),
        "utf8",
      );
    }

    const configData = fs.readFileSync(CONFIG_PATH, "utf8");
    const config = JSON.parse(configData);

    if (!config[NODE_ENV]) {
      throw new Error(
        `Configuration for environment '${NODE_ENV}' not found in config.json`,
      );
    }

    const { dataDir, shouldPersist } = resolveDataDir(config[NODE_ENV]);
    config[NODE_ENV] = { ...config[NODE_ENV], dataDir };

    if (shouldPersist) {
      fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), "utf8");
      logger.info(`Set data directory to ${dataDir} in config`);
    }

    return config[NODE_ENV];
  } catch (err) {
    logger.error("Error loading config:", err);
    throw err;
  }
}

// Save config file
export async function saveConfig(newConfig) {
  startWaiting("Saving...", logger);
  try {
    let config = {};
    if (fs.existsSync(CONFIG_PATH)) {
      const configData = fs.readFileSync(CONFIG_PATH, "utf8");
      config = JSON.parse(configData);
    } else {
      const configDir = path.dirname(CONFIG_PATH);
      if (!fs.existsSync(configDir)) {
        fs.mkdirSync(configDir, { recursive: true });
      }
    }

    // Update current environment
    config[NODE_ENV] = newConfig;

    // Write back to file with 2-space indentation
    fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), "utf8");
    await stopWaiting();
    logger.info(`Configuration for '${NODE_ENV}' saved successfully.`);
  } catch (err) {
    await stopWaiting();
    logger.error("Error saving config:", err);
    throw err;
  }
}

// Get current environment
export function getEnvironment() {
  return NODE_ENV;
}

// Get the path to the active config.json file
export function getConfigPath() {
  return CONFIG_PATH;
}

// Get the configured data directory, optionally with subpaths
export function getDataDir(...subpaths) {
  const config = loadConfig();
  return subpaths.length > 0
    ? path.join(config.dataDir, ...subpaths)
    : config.dataDir;
}

// Ensure a subdirectory exists within the data directory
export function ensureDataDir(...subpaths) {
  const dir = getDataDir(...subpaths);
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true });
  }
  return dir;
}
