const fs = require("fs");
const path = require("path");
const os = require("os");

const CONFIG_VERSION = 1;

// Default values
const DEFAULT_CONFIG = {
  configVersion: CONFIG_VERSION,
  onboarded: false,
  layout: "normal",
};

const DEFAULT_CREDENTIALS = {
  apiKey: "",
  groqApiKey: "",
  openaiCompatibleApiKey: "",
  openaiCompatibleBaseUrl: "",
  openaiCompatibleModel: "",
};

const DEFAULT_PREFERENCES = {
  customPrompt: "",
  selectedProfile: "interview",
  selectedLanguage: "en-US",
  selectedScreenshotInterval: "5",
  selectedImageQuality: "medium",
  advancedMode: false,
  audioMode: "speaker_only",
  fontSize: "medium",
  backgroundTransparency: 0.8,
  googleSearchEnabled: false,
  providerMode: "local",
  responseProvider: "gemini",
  llmProvider: "lmstudio",
  sttProvider: "nemotron-sidecar",
  localLlmBaseUrl: "http://127.0.0.1:1234/v1",
  localLlmModel: "",
  localLlmApiKey: "",
  localSttUrl: "ws://127.0.0.1:8765/v1/asr/stream",
  localSttLanguage: "en-US",
  ollamaHost: "http://127.0.0.1:11434",
  ollamaModel: "llama3.1",
  whisperModel: "Xenova/whisper-small",
  whisperDevice: "", // '' = auto-detect, 'cpu' = native, 'wasm' = compatible
};

const DEFAULT_KEYBINDS = null; // null means use system defaults

const DEFAULT_LIMITS = {
  data: [], // Array of { date: 'YYYY-MM-DD', flash: { count }, flashLite: { count }, groq: { 'qwen3-32b': { chars, limit }, 'gpt-oss-120b': { chars, limit }, 'gpt-oss-20b': { chars, limit } }, gemini: { 'gemma-3-27b-it': { chars } } }
};

// Get the config directory path based on OS
function getConfigDir() {
  const platform = os.platform();
  let configDir;

  if (platform === "win32") {
    configDir = path.join(
      os.homedir(),
      "AppData",
      "Roaming",
      "cheating-daddy-config",
    );
  } else if (platform === "darwin") {
    configDir = path.join(
      os.homedir(),
      "Library",
      "Application Support",
      "cheating-daddy-config",
    );
  } else {
    configDir = path.join(os.homedir(), ".config", "cheating-daddy-config");
  }

  return configDir;
}

// File paths
function getConfigPath() {
  return path.join(getConfigDir(), "config.json");
}

function getCredentialsPath() {
  return path.join(getConfigDir(), "credentials.json");
}

function getPreferencesPath() {
  return path.join(getConfigDir(), "preferences.json");
}

function getKeybindsPath() {
  return path.join(getConfigDir(), "keybinds.json");
}

function getLimitsPath() {
  return path.join(getConfigDir(), "limits.json");
}

function getHistoryDir() {
  return path.join(getConfigDir(), "history");
}

// Helper to read JSON file safely
function readJsonFile(filePath, defaultValue) {
  try {
    if (fs.existsSync(filePath)) {
      const data = fs.readFileSync(filePath, "utf8");
      return JSON.parse(data);
    }
  } catch (error) {
    console.warn(`Error reading ${filePath}:`, error.message);
  }
  return defaultValue;
}

// Helper to write JSON file safely
function writeJsonFile(filePath, data) {
  try {
    const dir = path.dirname(filePath);
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true });
    }
    fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf8");
    return true;
  } catch (error) {
    console.error(`Error writing ${filePath}:`, error.message);
    return false;
  }
}

// Check if we need to reset (no configVersion or wrong version)
function needsReset() {
  const configPath = getConfigPath();
  if (!fs.existsSync(configPath)) {
    return true;
  }

  try {
    const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
    return !config.configVersion || config.configVersion !== CONFIG_VERSION;
  } catch {
    return true;
  }
}

// Wipe and reinitialize the config directory
function resetConfigDir() {
  const configDir = getConfigDir();

  console.log("Resetting config directory...");

  // Remove existing directory if it exists
  if (fs.existsSync(configDir)) {
    fs.rmSync(configDir, { recursive: true, force: true });
  }

  // Create fresh directory structure
  fs.mkdirSync(configDir, { recursive: true });
  fs.mkdirSync(getHistoryDir(), { recursive: true });

  // Initialize with defaults
  writeJsonFile(getConfigPath(), DEFAULT_CONFIG);
  writeJsonFile(getCredentialsPath(), DEFAULT_CREDENTIALS);
  writeJsonFile(getPreferencesPath(), DEFAULT_PREFERENCES);

  console.log("Config directory initialized with defaults");
}

// Initialize storage - call this on app startup
function initializeStorage() {
  if (needsReset()) {
    resetConfigDir();
  } else {
    // Ensure history directory exists
    const historyDir = getHistoryDir();
    if (!fs.existsSync(historyDir)) {
      fs.mkdirSync(historyDir, { recursive: true });
    }
  }
}

// ============ CONFIG ============

function getConfig() {
  return readJsonFile(getConfigPath(), DEFAULT_CONFIG);
}

function setConfig(config) {
  const current = getConfig();
  const updated = { ...current, ...config, configVersion: CONFIG_VERSION };
  return writeJsonFile(getConfigPath(), updated);
}

function updateConfig(key, value) {
  const config = getConfig();
  config[key] = value;
  return writeJsonFile(getConfigPath(), config);
}

// ============ CREDENTIALS ============

function getCredentials() {
  return readJsonFile(getCredentialsPath(), DEFAULT_CREDENTIALS);
}

function setCredentials(credentials) {
  const current = getCredentials();
  const updated = { ...current, ...credentials };
  return writeJsonFile(getCredentialsPath(), updated);
}

function getApiKey() {
  return getCredentials().apiKey || "";
}

function setApiKey(apiKey) {
  return setCredentials({ apiKey });
}

function getGroqApiKey() {
  return getCredentials().groqApiKey || "";
}

function setGroqApiKey(groqApiKey) {
  return setCredentials({ groqApiKey });
}

function getOpenAICompatibleConfig() {
  const creds = getCredentials();
  return {
    apiKey: creds.openaiCompatibleApiKey || "",
    baseUrl: creds.openaiCompatibleBaseUrl || "",
    model: creds.openaiCompatibleModel || "",
  };
}

function setOpenAICompatibleConfig(apiKey, baseUrl, model) {
  return setCredentials({
    openaiCompatibleApiKey: apiKey,
    openaiCompatibleBaseUrl: baseUrl,
    openaiCompatibleModel: model,
  });
}

// ============ PREFERENCES ============

function getPreferences() {
  const saved = readJsonFile(getPreferencesPath(), {});
  return { ...DEFAULT_PREFERENCES, ...saved };
}

function setPreferences(preferences) {
  const current = getPreferences();
  const updated = { ...current, ...preferences };
  return writeJsonFile(getPreferencesPath(), updated);
}

function updatePreference(key, value) {
  const preferences = getPreferences();
  preferences[key] = value;
  return writeJsonFile(getPreferencesPath(), preferences);
}

// ============ KEYBINDS ============

function getKeybinds() {
  return readJsonFile(getKeybindsPath(), DEFAULT_KEYBINDS);
}

function setKeybinds(keybinds) {
  return writeJsonFile(getKeybindsPath(), keybinds);
}

// ============ LIMITS (Rate Limiting) ============

function getLimits() {
  return readJsonFile(getLimitsPath(), DEFAULT_LIMITS);
}

function setLimits(limits) {
  return writeJsonFile(getLimitsPath(), limits);
}

function getTodayDateString() {
  const now = new Date();
  return now.toISOString().split("T")[0]; // YYYY-MM-DD
}

function getTodayLimits() {
  const limits = getLimits();
  const today = getTodayDateString();

  // Find today's entry
  const todayEntry = limits.data.find((entry) => entry.date === today);

  if (todayEntry) {
    // ensure new fields exist
    if (!todayEntry.groq) {
      todayEntry.groq = {
        "qwen3-32b": { chars: 0, limit: 1500000 },
        "gpt-oss-120b": { chars: 0, limit: 600000 },
        "gpt-oss-20b": { chars: 0, limit: 600000 },
        "kimi-k2-instruct": { chars: 0, limit: 600000 },
      };
    }
    if (!todayEntry.gemini) {
      todayEntry.gemini = {
        "gemma-3-27b-it": { chars: 0 },
      };
    }
    setLimits(limits);
    return todayEntry;
  }

  // No entry for today - clean old entries and create new one
  limits.data = limits.data.filter((entry) => entry.date === today);
  const newEntry = {
    date: today,
    flash: { count: 0 },
    flashLite: { count: 0 },
    groq: {
      "qwen3-32b": { chars: 0, limit: 1500000 },
      "gpt-oss-120b": { chars: 0, limit: 600000 },
      "gpt-oss-20b": { chars: 0, limit: 600000 },
      "kimi-k2-instruct": { chars: 0, limit: 600000 },
    },
    gemini: {
      "gemma-3-27b-it": { chars: 0 },
    },
  };
  limits.data.push(newEntry);
  setLimits(limits);

  return newEntry;
}

function incrementLimitCount(model) {
  const limits = getLimits();
  const today = getTodayDateString();

  // Find or create today's entry
  let todayEntry = limits.data.find((entry) => entry.date === today);

  if (!todayEntry) {
    // Clean old entries and create new one
    limits.data = [];
    todayEntry = {
      date: today,
      flash: { count: 0 },
      flashLite: { count: 0 },
    };
    limits.data.push(todayEntry);
  } else {
    // Clean old entries, keep only today
    limits.data = limits.data.filter((entry) => entry.date === today);
  }

  // Increment the appropriate model count
  if (model === "gemini-2.5-flash") {
    todayEntry.flash.count++;
  } else if (model === "gemini-2.5-flash-lite") {
    todayEntry.flashLite.count++;
  }

  setLimits(limits);
  return todayEntry;
}

function incrementCharUsage(provider, model, charCount) {
  getTodayLimits();

  const limits = getLimits();
  const today = getTodayDateString();
  const todayEntry = limits.data.find((entry) => entry.date === today);

  if (todayEntry[provider] && todayEntry[provider][model]) {
    todayEntry[provider][model].chars += charCount;
    setLimits(limits);
  }

  return todayEntry;
}

function getAvailableModel() {
  const todayLimits = getTodayLimits();

  // RPD limits: flash = 20, flash-lite = 20
  // After both exhausted, fall back to flash (for paid API users)
  if (todayLimits.flash.count < 20) {
    return "gemini-2.5-flash";
  } else if (todayLimits.flashLite.count < 20) {
    return "gemini-2.5-flash-lite";
  }

  return "gemini-2.5-flash"; // Default to flash for paid API users
}

function getModelForToday() {
  const todayEntry = getTodayLimits();
  const groq = todayEntry.groq;

  if (groq["qwen3-32b"].chars < groq["qwen3-32b"].limit) {
    return "qwen/qwen3-32b";
  }
  if (groq["gpt-oss-120b"].chars < groq["gpt-oss-120b"].limit) {
    return "openai/gpt-oss-120b";
  }
  if (groq["gpt-oss-20b"].chars < groq["gpt-oss-20b"].limit) {
    return "openai/gpt-oss-20b";
  }
  if (groq["kimi-k2-instruct"].chars < groq["kimi-k2-instruct"].limit) {
    return "moonshotai/kimi-k2-instruct";
  }

  // All limits exhausted
  return null;
}

// ============ HISTORY ============

function getSessionPath(sessionId) {
  return path.join(getHistoryDir(), `${sessionId}.json`);
}

function saveSession(sessionId, data) {
  const sessionPath = getSessionPath(sessionId);

  // Load existing session to preserve metadata
  const existingSession = readJsonFile(sessionPath, null);

  const sessionData = {
    sessionId,
    createdAt: existingSession?.createdAt || parseInt(sessionId),
    lastUpdated: Date.now(),
    // Profile context - set once when session starts
    profile: data.profile || existingSession?.profile || null,
    customPrompt: data.customPrompt || existingSession?.customPrompt || null,
    // Conversation data
    conversationHistory:
      data.conversationHistory || existingSession?.conversationHistory || [],
    screenAnalysisHistory:
      data.screenAnalysisHistory ||
      existingSession?.screenAnalysisHistory ||
      [],
  };
  return writeJsonFile(sessionPath, sessionData);
}

function getSession(sessionId) {
  return readJsonFile(getSessionPath(sessionId), null);
}

function getAllSessions() {
  const historyDir = getHistoryDir();

  try {
    if (!fs.existsSync(historyDir)) {
      return [];
    }

    const files = fs
      .readdirSync(historyDir)
      .filter((f) => f.endsWith(".json"))
      .sort((a, b) => {
        // Sort by timestamp descending (newest first)
        const tsA = parseInt(a.replace(".json", ""));
        const tsB = parseInt(b.replace(".json", ""));
        return tsB - tsA;
      });

    return files
      .map((file) => {
        const sessionId = file.replace(".json", "");
        const data = readJsonFile(path.join(historyDir, file), null);
        if (data) {
          return {
            sessionId,
            createdAt: data.createdAt,
            lastUpdated: data.lastUpdated,
            messageCount: data.conversationHistory?.length || 0,
            screenAnalysisCount: data.screenAnalysisHistory?.length || 0,
            profile: data.profile || null,
            customPrompt: data.customPrompt || null,
          };
        }
        return null;
      })
      .filter(Boolean);
  } catch (error) {
    console.error("Error reading sessions:", error.message);
    return [];
  }
}

function deleteSession(sessionId) {
  const sessionPath = getSessionPath(sessionId);
  try {
    if (fs.existsSync(sessionPath)) {
      fs.unlinkSync(sessionPath);
      return true;
    }
  } catch (error) {
    console.error("Error deleting session:", error.message);
  }
  return false;
}

function deleteAllSessions() {
  const historyDir = getHistoryDir();
  try {
    if (fs.existsSync(historyDir)) {
      const files = fs
        .readdirSync(historyDir)
        .filter((f) => f.endsWith(".json"));
      files.forEach((file) => {
        fs.unlinkSync(path.join(historyDir, file));
      });
    }
    return true;
  } catch (error) {
    console.error("Error deleting all sessions:", error.message);
    return false;
  }
}

// ============ CLEAR ALL DATA ============

function clearAllData() {
  resetConfigDir();
  return true;
}

module.exports = {
  // Initialization
  initializeStorage,
  getConfigDir,

  // Config
  getConfig,
  setConfig,
  updateConfig,

  // Credentials
  getCredentials,
  setCredentials,
  getApiKey,
  setApiKey,
  getGroqApiKey,
  setGroqApiKey,
  getOpenAICompatibleConfig,
  setOpenAICompatibleConfig,

  // Preferences
  getPreferences,
  setPreferences,
  updatePreference,

  // Keybinds
  getKeybinds,
  setKeybinds,

  // Limits (Rate Limiting)
  getLimits,
  setLimits,
  getTodayLimits,
  incrementLimitCount,
  getAvailableModel,
  incrementCharUsage,
  getModelForToday,

  // History
  saveSession,
  getSession,
  getAllSessions,
  deleteSession,
  deleteAllSessions,

  // Clear all
  clearAllData,
};
