import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";

export interface HarmonyConfig {
  apiKey: string | null;
  apiUrl: string;
  activeWorkspaceId: string | null;
  activeProjectId: string | null;
  userEmail: string | null;
  memoryDir: string | null;
}

/**
 * Local project-level config (stored in .harmony-mcp.json in project root).
 * Only contains context IDs - API key stays global for security.
 */
export interface LocalConfig {
  workspaceId: string | null;
  projectId: string | null;
}

const DEFAULT_API_URL = "https://app.gethmy.com/api";
const LOCAL_CONFIG_FILENAME = ".harmony-mcp.json";

export function getConfigDir(): string {
  return join(homedir(), ".harmony-mcp");
}

export function getConfigPath(): string {
  return join(getConfigDir(), "config.json");
}

export function getLocalConfigPath(cwd?: string): string {
  return join(cwd || process.cwd(), LOCAL_CONFIG_FILENAME);
}

export function loadConfig(): HarmonyConfig {
  const configPath = getConfigPath();

  if (!existsSync(configPath)) {
    return {
      apiKey: null,
      apiUrl: DEFAULT_API_URL,
      activeWorkspaceId: null,
      activeProjectId: null,
      userEmail: null,
      memoryDir: null,
    };
  }

  try {
    const data = readFileSync(configPath, "utf-8");
    const config = JSON.parse(data);
    return {
      apiKey: config.apiKey || null,
      apiUrl: config.apiUrl || DEFAULT_API_URL,
      activeWorkspaceId: config.activeWorkspaceId || null,
      activeProjectId: config.activeProjectId || null,
      userEmail: config.userEmail || null,
      memoryDir: config.memoryDir || null,
    };
  } catch {
    return {
      apiKey: null,
      apiUrl: DEFAULT_API_URL,
      activeWorkspaceId: null,
      activeProjectId: null,
      userEmail: null,
      memoryDir: null,
    };
  }
}

export function saveConfig(config: Partial<HarmonyConfig>): void {
  const configDir = getConfigDir();
  const configPath = getConfigPath();

  if (!existsSync(configDir)) {
    mkdirSync(configDir, { recursive: true, mode: 0o700 });
  }

  const existingConfig = loadConfig();
  const newConfig = { ...existingConfig, ...config };

  writeFileSync(configPath, JSON.stringify(newConfig, null, 2), {
    mode: 0o600,
  });
}

export function loadLocalConfig(cwd?: string): LocalConfig | null {
  const localConfigPath = getLocalConfigPath(cwd);

  if (!existsSync(localConfigPath)) {
    return null;
  }

  try {
    const data = readFileSync(localConfigPath, "utf-8");
    const config = JSON.parse(data);
    return {
      workspaceId: config.workspaceId || null,
      projectId: config.projectId || null,
    };
  } catch {
    return null;
  }
}

export function saveLocalConfig(
  config: Partial<LocalConfig>,
  cwd?: string,
): void {
  const localConfigPath = getLocalConfigPath(cwd);

  const existingConfig = loadLocalConfig(cwd) || {
    workspaceId: null,
    projectId: null,
  };
  const newConfig = { ...existingConfig, ...config };

  // Remove null values from the saved config for cleaner output
  const cleanConfig: Record<string, string> = {};
  if (newConfig.workspaceId) cleanConfig.workspaceId = newConfig.workspaceId;
  if (newConfig.projectId) cleanConfig.projectId = newConfig.projectId;

  writeFileSync(localConfigPath, JSON.stringify(cleanConfig, null, 2));
}

export function hasLocalConfig(cwd?: string): boolean {
  return existsSync(getLocalConfigPath(cwd));
}

export function getApiKey(): string {
  const config = loadConfig();
  if (!config.apiKey) {
    throw new Error(
      'Not configured. Run "npx @gethmy/mcp setup" to set your API key.\n' +
        "You can generate an API key at https://gethmy.com → Settings → API Keys.",
    );
  }
  return config.apiKey;
}

export function getApiUrl(): string {
  const config = loadConfig();
  return config.apiUrl;
}

export function getUserEmail(): string | null {
  const config = loadConfig();
  return config.userEmail;
}

export function setUserEmail(email: string | null): void {
  saveConfig({ userEmail: email });
}

export interface SetContextOptions {
  local?: boolean;
  cwd?: string;
}

export function setActiveWorkspace(
  workspaceId: string | null,
  options?: SetContextOptions,
): void {
  if (options?.local) {
    saveLocalConfig({ workspaceId }, options.cwd);
  } else {
    saveConfig({ activeWorkspaceId: workspaceId });
  }
}

export function setActiveProject(
  projectId: string | null,
  options?: SetContextOptions,
): void {
  if (options?.local) {
    saveLocalConfig({ projectId }, options.cwd);
  } else {
    saveConfig({ activeProjectId: projectId });
  }
}

export function getActiveWorkspaceId(cwd?: string): string | null {
  // Local config takes precedence over global
  const localConfig = loadLocalConfig(cwd);
  if (localConfig?.workspaceId) {
    return localConfig.workspaceId;
  }
  return loadConfig().activeWorkspaceId;
}

export function getActiveProjectId(cwd?: string): string | null {
  // Local config takes precedence over global
  const localConfig = loadLocalConfig(cwd);
  if (localConfig?.projectId) {
    return localConfig.projectId;
  }
  return loadConfig().activeProjectId;
}

export function isConfigured(): boolean {
  const config = loadConfig();
  return !!config.apiKey;
}

/**
 * Check if skills are already installed (globally or locally).
 * Returns installation status and location.
 */
export function areSkillsInstalled(cwd?: string): {
  installed: boolean;
  location: "global" | "local" | null;
  paths: string[];
} {
  const home = homedir();
  const workingDir = cwd || process.cwd();
  const foundPaths: string[] = [];

  // Check global skills directory
  const globalSkillsDir = join(home, ".agents", "skills");
  const globalSkillPath = join(globalSkillsDir, "hmy", "SKILL.md");
  if (existsSync(globalSkillPath)) {
    foundPaths.push(globalSkillPath);
    return { installed: true, location: "global", paths: foundPaths };
  }

  // Check Claude global skills (symlinked from global skills)
  const claudeGlobalSkill = join(home, ".claude", "skills", "hmy.md");
  if (existsSync(claudeGlobalSkill)) {
    foundPaths.push(claudeGlobalSkill);
    return { installed: true, location: "global", paths: foundPaths };
  }

  // Check Claude global skills (alternate SKILL.md format)
  const claudeGlobalSkillAlt = join(
    home,
    ".claude",
    "skills",
    "hmy",
    "SKILL.md",
  );
  if (existsSync(claudeGlobalSkillAlt)) {
    foundPaths.push(claudeGlobalSkillAlt);
    return { installed: true, location: "global", paths: foundPaths };
  }

  // Check local skills in project directory
  const localSkillPath = join(workingDir, ".claude", "skills", "hmy.md");
  if (existsSync(localSkillPath)) {
    foundPaths.push(localSkillPath);
    return { installed: true, location: "local", paths: foundPaths };
  }

  // Check local skills in project directory (alternate SKILL.md format)
  const localSkillPathAlt = join(
    workingDir,
    ".claude",
    "skills",
    "hmy",
    "SKILL.md",
  );
  if (existsSync(localSkillPathAlt)) {
    foundPaths.push(localSkillPathAlt);
    return { installed: true, location: "local", paths: foundPaths };
  }

  return { installed: false, location: null, paths: [] };
}

/**
 * Check if project context is configured in the local directory.
 */
export function hasProjectContext(cwd?: string): boolean {
  const localConfig = loadLocalConfig(cwd);
  return !!(localConfig?.workspaceId || localConfig?.projectId);
}

export function getMemoryDir(): string {
  const config = loadConfig();
  if (config.memoryDir) return config.memoryDir;
  return join(homedir(), ".harmony", "memory");
}
