import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';
import { randomBytes } from 'crypto';

const __dirname = dirname(fileURLToPath(import.meta.url));
const DATA_DIR = process.env.AGENT_DATA_DIR || __dirname;
const IS_PACKAGED = !!process.env.AGENT_DATA_DIR;
const CONFIG_PATH = join(DATA_DIR, 'config.json');

// Ensure data directory exists on first boot (critical for packaged Electron
// where AGENT_DATA_DIR may point to a not-yet-created userData path)
try { mkdirSync(DATA_DIR, { recursive: true }); } catch {}

const DEFAULTS = {
  // Packaged Electron apps use gergy adapter (API/worker proxy, no CLI needed)
  // Dev/CLI installs default to claude CLI
  cli: IS_PACKAGED ? 'gergy' : 'claude',
  port: 4000,
  loopMinutes: 5,
  compactThreshold: 40,
  compactKeepRecent: 10,
  agentName: 'AI-Do',
  workspaceRoot: join(DATA_DIR, 'workspaces'),
  models: {},
  maxUserTaskConcurrency: 2,
  autonomyActiveChatPauseMs: 180000,
  desktopHotkey: 'CommandOrControl+Shift+A',
  dailyBudget: null,
  authToken: null,

  // v3.0 — Workspace management
  activeWorkspace: 'default',
  workspaces: {},

  // v3.0 — Ingestion engine
  ingestion: { enabled: true, maxConcurrent: 2, watchFolders: [] },

  // v3.0 — Cognitive reasoning modules
  cognitive: {
    plannerEnabled: true,
    reflectorEnabled: true,
    reflectorInterval: 6,
    thinkerDepth: 'balanced',
    dailyReflection: true
  },

  // v3.0 — Multimodal I/O
  multimodal: { sttEnabled: false, ttsEnabled: false, visionEnabled: false },

  // v3.0 — Knowledge graph
  kgEnabled: true,

  // v3.1 — Voice activation (openWakeWord + ONNX Runtime)
  voice: {
    enabled: false,
    wakeWordModel: 'hey_jarvis_v0.1',
    detectionThreshold: 0.5,
    modelsPath: null,
    nativeMode: true,
    browserMode: true,
    transcriptionProvider: 'whisper',
    autoInjectToChat: true,
    feedbackSound: true,
    listenHotkey: 'CommandOrControl+Shift+Space',
    ringBufferSeconds: 15,
    provider: 'xai',
    xaiApiKey: null,
    xaiVoice: 'Sal',
    openaiApiKey: null
  },

  // v5.1 — Cloudflare Worker proxy (out-of-box AI access)
  worker: {
    url: 'https://ai-do-site.pages.dev',
    token: 'ado_Ppfxy5MHLsVLWgWG6uLhua_03dJtwWyL',
    dailyLimit: 100,
    voiceLimit: 30
  },

  // v4.0 — Persona system
  persona: {
    name: 'AI-Do',
    greeting: 'Hello! I\'m AI-Do, your personal AI.',
    avatarStyle: 'default',
    traits: { creativity: 0.7, verbosity: 0.5, formality: 0.3, humor: 0.5 }
  },

  // v4.0 — Vector embedding cache (optional, degrades gracefully)
  vector: {
    enabled: true,
    embeddingModel: 'nomic-embed-text',
    embeddingEndpoint: 'http://localhost:11434/api/embeddings',
    dimensions: 768
  },

  // v4.2 — Gergy agentic adapter (native API, multi-provider)
  agentic: {
    provider: null,
    apiKey: null,
    baseUrl: null,
    maxTurns: 50,
    maxTokens: 8192
  },

  // v4.3 — Autonomous creative loop
  autonomy: {
    enabled: true,
    intervalMinutes: 30,
    budgetPerDay: 1.00
  },

  // v4.4 — Scheduled recurring tasks
  schedules: [],

  // v4.5 — Desktop and browser notifications
  notifications: { enabled: true },

  // Logging
  logLevel: 'info'
};

let _config = null;

// Keys that are nested objects requiring deep merge (not replacement)
const NESTED_KEYS = ['models', 'workspaces', 'ingestion', 'cognitive', 'multimodal', 'voice', 'persona', 'vector', 'agentic', 'autonomy', 'notifications', 'worker'];

function mergeConfig(userConfig) {
  const merged = { ...DEFAULTS, ...userConfig };
  for (const key of NESTED_KEYS) {
    if (typeof DEFAULTS[key] === 'object' && DEFAULTS[key] !== null) {
      merged[key] = { ...DEFAULTS[key], ...(userConfig[key] || {}) };
    }
  }
  return merged;
}

function tryRepairMalformedWorkspacePath(raw) {
  const repairedRaw = raw.replace(
    /("workspaceRoot"\s*:\s*")([^"]*)(")/,
    (_, prefix, value, suffix) => `${prefix}${value.replace(/\\/g, '\\\\')}${suffix}`
  );
  if (repairedRaw === raw) return null;
  try {
    const parsed = JSON.parse(repairedRaw);
    return { parsed, repairedRaw };
  } catch {
    return null;
  }
}

export function loadConfig() {
  if (existsSync(CONFIG_PATH)) {
    const raw = readFileSync(CONFIG_PATH, 'utf-8');
    try {
      const userConfig = JSON.parse(raw);
      _config = mergeConfig(userConfig);
    } catch (err) {
      const repaired = tryRepairMalformedWorkspacePath(raw);
      if (repaired) {
        _config = mergeConfig(repaired.parsed);
        try {
          writeFileSync(CONFIG_PATH, JSON.stringify(_config, null, 2) + '\n', 'utf-8');
          console.log('[config] Repaired malformed workspaceRoot path in config.json');
        } catch (writeErr) {
          console.error(`[config] Repaired config in memory but could not save: ${writeErr.message}`);
        }
      } else {
        console.error(`[config] Failed to parse config.json: ${err.message}. Using defaults.`);
        _config = { ...DEFAULTS };
      }
    }
  } else {
    _config = { ...DEFAULTS };
  }

  // Migrate workspaceRoot if it points inside a .app bundle (macOS) or the
  // source tree of a packaged Electron app — these paths are destroyed on update.
  if (IS_PACKAGED && _config.workspaceRoot) {
    const wsRoot = _config.workspaceRoot;
    const needsMigration = wsRoot.includes('.app/') || wsRoot.includes('.app\\')
      || (wsRoot.startsWith(__dirname) && __dirname !== DATA_DIR);
    if (needsMigration) {
      const newRoot = join(DATA_DIR, 'workspaces');
      console.log(`[config] Migrating workspaceRoot from app bundle to ${newRoot}`);
      _config.workspaceRoot = newRoot;
    }
  }

  // Auto-generate auth token if not set
  if (!_config.authToken) {
    _config.authToken = randomBytes(24).toString('hex');
    console.log(`[config] Generated auth token. Access UI at: http://localhost:${_config.port}?token=${_config.authToken}`);
  }

  // Always write merged config back to disk so new defaults are persisted
  // (ensures adapters that read config.json directly see new fields like worker)
  try {
    writeFileSync(CONFIG_PATH, JSON.stringify(_config, null, 2) + '\n', 'utf-8');
  } catch (err) {
    console.error(`[config] Could not save config: ${err.message}`);
  }

  return _config;
}

export function getConfig() {
  if (!_config) loadConfig();
  return _config;
}

export function updateConfig(updates) {
  const current = getConfig();
  const merged = { ...current, ...updates };
  for (const key of NESTED_KEYS) {
    if (updates[key] && typeof updates[key] === 'object') {
      merged[key] = { ...current[key], ...updates[key] };
    }
  }
  writeFileSync(CONFIG_PATH, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
  _config = merged;
  return merged;
}

export function getDbPath() {
  return process.env.AGENT_DB_PATH || join(DATA_DIR, 'agent.db');
}

export function getAgentRoot() {
  return __dirname;
}

export { DEFAULTS };
