import fsPromises from 'fs/promises';
import os from 'os';
import path from 'path';

const DEFAULT_MCP_CONFIG = {
  mcpServers: {},
};

function pilotHome() {
  return process.env.PILOT_HOME || path.join(os.homedir(), '.pilotdeck');
}

export function getGlobalMcpConfigPath() {
  return path.join(pilotHome(), 'mcp.json');
}

export function getProjectMcpConfigPath(projectPath) {
  return path.join(projectPath || process.cwd(), '.pilotdeck', 'mcp.json');
}

export function normalizeMcpConfig(input) {
  if (!input || typeof input !== 'object' || Array.isArray(input)) {
    throw new Error('MCP config root must be an object.');
  }
  if (input.mcpServers === undefined) {
    return { ...input, mcpServers: {} };
  }
  if (!input.mcpServers || typeof input.mcpServers !== 'object' || Array.isArray(input.mcpServers)) {
    throw new Error('mcpServers must be an object.');
  }
  for (const [name, server] of Object.entries(input.mcpServers)) {
    if (!name || !server || typeof server !== 'object' || Array.isArray(server)) {
      throw new Error(`Server "${name}" must be an object.`);
    }
    if (typeof server.command !== 'string' && typeof server.url !== 'string' && typeof server.httpUrl !== 'string') {
      throw new Error(`Server "${name}" must define command, url, or httpUrl.`);
    }
    if (server.args !== undefined && (!Array.isArray(server.args) || !server.args.every((arg) => typeof arg === 'string'))) {
      throw new Error(`Server "${name}" args must be an array of strings.`);
    }
    if (server.env !== undefined && !isStringRecord(server.env)) {
      throw new Error(`Server "${name}" env must be an object with string values.`);
    }
    if (server.headers !== undefined && !isStringRecord(server.headers)) {
      throw new Error(`Server "${name}" headers must be an object with string values.`);
    }
  }
  return input;
}

export async function readMcpConfigFile(scope, projectPath) {
  const filePath = scope === 'project' ? getProjectMcpConfigPath(projectPath) : getGlobalMcpConfigPath();
  try {
    const raw = await fsPromises.readFile(filePath, 'utf8');
    const parsed = normalizeMcpConfig(JSON.parse(raw));
    return {
      exists: true,
      path: filePath,
      raw: JSON.stringify(parsed, null, 2),
      config: parsed,
    };
  } catch (error) {
    if (error?.code === 'ENOENT') {
      return {
        exists: false,
        path: filePath,
        raw: JSON.stringify(DEFAULT_MCP_CONFIG, null, 2),
        config: DEFAULT_MCP_CONFIG,
      };
    }
    throw error;
  }
}

export async function writeMcpConfigFile(scope, raw, projectPath) {
  const parsed = normalizeMcpConfig(JSON.parse(raw));
  const filePath = scope === 'project' ? getProjectMcpConfigPath(projectPath) : getGlobalMcpConfigPath();
  await fsPromises.mkdir(path.dirname(filePath), { recursive: true, mode: 0o700 });
  await fsPromises.writeFile(filePath, JSON.stringify(parsed, null, 2) + '\n', { mode: 0o600 });
  return readMcpConfigFile(scope, projectPath);
}

export async function listMcpConfigFiles(projectPath) {
  const [globalConfig, projectConfig] = await Promise.all([
    readMcpConfigFile('global', projectPath),
    readMcpConfigFile('project', projectPath),
  ]);
  return {
    global: globalConfig,
    project: projectConfig,
  };
}

function isStringRecord(value) {
  return value && typeof value === 'object' && !Array.isArray(value) && Object.values(value).every((entry) => typeof entry === 'string');
}
