/**
 * GitFlow Config — Read/write .claude/gitflow/config.json v2.1.0.
 * Self-contained: imports only from local lib + node built-ins.
 */

import { readFile, writeFile, mkdir } from 'fs/promises';
import { existsSync } from 'fs';
import { join, dirname } from 'path';
import type { GitFlowConfig, WorktreeMode } from './types.js';
import { normalizeForPlatform, normalizeForStorage } from './paths.js';
import { detectPlatform } from './platform.js';
import { execGit } from './git.js';

const CONFIG_RELATIVE = '.claude/gitflow/config.json';

export async function resolveConfigPath(startDir?: string): Promise<string | null> {
  const cwd = startDir || process.cwd();

  const local = join(cwd, CONFIG_RELATIVE);
  if (existsSync(local)) return local;

  const wtResult = await execGit(['worktree', 'list', '--porcelain'], cwd);
  if (wtResult.exitCode === 0) {
    const lines = wtResult.stdout.split('\n');
    let currentPath = '';
    for (const line of lines) {
      if (line.startsWith('worktree ')) {
        currentPath = line.slice(9);
      }
      if (line.includes('branch refs/heads/develop') && currentPath) {
        const devConfig = join(currentPath, CONFIG_RELATIVE);
        if (existsSync(devConfig)) return devConfig;
      }
    }
  }

  const rootResult = await execGit(['rev-parse', '--show-toplevel'], cwd);
  if (rootResult.exitCode === 0) {
    const rootConfig = join(rootResult.stdout, CONFIG_RELATIVE);
    if (existsSync(rootConfig)) return rootConfig;
  }

  return null;
}

export async function readConfig(configPath?: string): Promise<GitFlowConfig> {
  const path = configPath || await resolveConfigPath();
  if (!path) {
    throw new Error('GitFlow config not found. Run gitflow init first.');
  }

  const content = await readFile(path, 'utf-8');
  const raw = JSON.parse(content);
  return applyDefaults(raw);
}

export async function writeConfig(config: GitFlowConfig, configPath: string): Promise<void> {
  const stored = structuredClone(config);

  stored.repository.rootFolder = normalizeForStorage(stored.repository.rootFolder);
  if (stored.worktrees.structure) {
    const s = stored.worktrees.structure;
    s.main = normalizeForStorage(s.main);
    s.develop = normalizeForStorage(s.develop);
    s.features = normalizeForStorage(s.features);
    s.releases = normalizeForStorage(s.releases);
    s.hotfixes = normalizeForStorage(s.hotfixes);
  }
  if (stored.workspace?.path) {
    stored.workspace.path = normalizeForStorage(stored.workspace.path);
  }

  await mkdir(dirname(configPath), { recursive: true });
  await writeFile(configPath, JSON.stringify(stored, null, 2) + '\n');
}

export async function readConfigForPlatform(configPath?: string): Promise<GitFlowConfig> {
  const config = await readConfig(configPath);
  const { platform } = detectPlatform();

  config.repository.rootFolder = normalizeForPlatform(config.repository.rootFolder, platform);
  if (config.worktrees.structure) {
    const s = config.worktrees.structure;
    s.main = normalizeForPlatform(s.main, platform);
    s.develop = normalizeForPlatform(s.develop, platform);
    s.features = normalizeForPlatform(s.features, platform);
    s.releases = normalizeForPlatform(s.releases, platform);
    s.hotfixes = normalizeForPlatform(s.hotfixes, platform);
  }
  if (config.workspace?.path) {
    config.workspace.path = normalizeForPlatform(config.workspace.path, platform);
  }

  return config;
}

export function createDefaultConfig(overrides?: Partial<GitFlowConfig>): GitFlowConfig {
  const { platform, shell } = detectPlatform();
  const base: GitFlowConfig = {
    version: '2.1.0',
    platform: { detected: platform, shell, detectedAt: new Date().toISOString() },
    workspace: { path: '', name: '' },
    repository: {
      name: '',
      rootFolder: '',
      nameVariants: { pascalCaseDot: '', pascalCase: '', kebabCase: '', snakeCase: '', displayName: '' },
      defaultBranch: 'main',
      remoteUrl: '',
    },
    git: {
      provider: 'unknown',
      branches: { main: 'main', develop: 'develop' },
      prefixes: { feature: 'feature/', release: 'release/', hotfix: 'hotfix/' },
    },
    worktrees: {
      enabled: true,
      mode: 'organized' as WorktreeMode,
      structure: { main: '', develop: '', features: '', releases: '', hotfixes: '' },
    },
    versioning: { strategy: 'semver', current: '0.0.0', tagPrefix: 'v', sources: ['package.json'] },
    efcore: { enabled: false, validateOnCommit: false, blockDestructive: false },
    workflow: { push: { afterCommit: 'worktree' }, pr: { autoLabels: true, requireReview: true } },
    language: { code: 'en' },
  };

  if (overrides) {
    return deepMerge(base as unknown as Record<string, unknown>, overrides as unknown as Record<string, unknown>) as unknown as GitFlowConfig;
  }
  return base;
}

function applyDefaults(raw: Record<string, unknown>): GitFlowConfig {
  const defaults = createDefaultConfig();
  return deepMerge(defaults as unknown as Record<string, unknown>, raw) as unknown as GitFlowConfig;
}

function deepMerge(target: Record<string, unknown>, source: Record<string, unknown>): Record<string, unknown> {
  const result = { ...target };
  for (const key of Object.keys(source)) {
    const sVal = source[key];
    const tVal = target[key];
    if (sVal && typeof sVal === 'object' && !Array.isArray(sVal) && tVal && typeof tVal === 'object' && !Array.isArray(tVal)) {
      result[key] = deepMerge(tVal as Record<string, unknown>, sVal as Record<string, unknown>);
    } else if (sVal !== undefined) {
      result[key] = sVal;
    }
  }
  return result;
}
