import { readFileSync, existsSync } from 'node:fs';
import { join } from 'node:path';
import type { AgentDefinition } from '@/modules/review-execution/entities/progress/agentDefinition.type.js';
import type { Language } from '@/modules/shared-kernel/entities/language/language.schema.js';
import type { RoutingPolicy } from '@/modules/review-execution/entities/modelRouting/modelRouting.schema.js';

export interface ProjectConfig {
  github: boolean;
  gitlab: boolean;
  defaultModel: 'haiku' | 'sonnet' | 'opus';
  reviewSkill: string;
  reviewFollowupSkill: string;
  language: Language;
  retentionDays: number;
  agents?: AgentDefinition[];
  followupAgents?: AgentDefinition[];
  routingPolicy?: RoutingPolicy;
}

/**
 * Validate agents array structure
 */
const DEFAULT_RETENTION_DAYS = 14;

function parseRetentionDays(value: unknown): number {
  if (typeof value === 'number' && Number.isInteger(value) && value >= 1) {
    return value;
  }
  return DEFAULT_RETENTION_DAYS;
}

function validateAgents(agents: unknown): agents is AgentDefinition[] {
  if (!Array.isArray(agents)) {
    return false;
  }

  return agents.every((agent) => {
    if (agent === null || typeof agent !== 'object') {
      return false;
    }
    const record = agent as Record<string, unknown>;
    const name = record.name;
    const displayName = record.displayName;
    return (
      typeof name === 'string' &&
      typeof displayName === 'string' &&
      name.length > 0 &&
      displayName.length > 0
    );
  });
}

function parseRoutingPolicy(value: unknown): RoutingPolicy | undefined {
  if (value === null || value === undefined || typeof value !== 'object') {
    return undefined;
  }
  const record = value as Record<string, unknown>;
  const haikuMaxLines = record.haikuMaxLines;
  const sonnetMaxLines = record.sonnetMaxLines;
  if (
    typeof haikuMaxLines === 'number' &&
    Number.isInteger(haikuMaxLines) &&
    haikuMaxLines > 0 &&
    typeof sonnetMaxLines === 'number' &&
    Number.isInteger(sonnetMaxLines) &&
    sonnetMaxLines > 0
  ) {
    return { haikuMaxLines, sonnetMaxLines };
  }
  return undefined;
}

/**
 * Load project configuration from .claude/reviews/config.json
 * @param localPath - Path to the project root directory
 * @returns ProjectConfig or undefined if file doesn't exist
 * @throws Error if file exists but is invalid
 */
export function loadProjectConfig(localPath: string): ProjectConfig | undefined {
  const configPath = join(localPath, '.claude', 'reviews', 'config.json');

  if (!existsSync(configPath)) {
    return undefined;
  }

  const rawContent = readFileSync(configPath, 'utf-8');
  const parsed = JSON.parse(rawContent) as Record<string, unknown>;

  // Validate required fields
  const requiredFields = ['github', 'gitlab', 'defaultModel', 'reviewSkill', 'reviewFollowupSkill'];
  for (const field of requiredFields) {
    if (!(field in parsed)) {
      throw new Error(`Project config missing required field: ${field}`);
    }
  }

  // Validate agents if present
  if ('agents' in parsed && parsed.agents !== undefined) {
    if (!validateAgents(parsed.agents)) {
      throw new Error(
        'Invalid agents format: must be array of { name: string, displayName: string }'
      );
    }
  }

  // Validate followupAgents if present
  if ('followupAgents' in parsed && parsed.followupAgents !== undefined) {
    if (!validateAgents(parsed.followupAgents)) {
      throw new Error(
        'Invalid followupAgents format: must be array of { name: string, displayName: string }'
      );
    }
  }

  return {
    github: Boolean(parsed.github),
    gitlab: Boolean(parsed.gitlab),
    defaultModel: parsed.defaultModel === 'opus' ? 'opus' : parsed.defaultModel === 'haiku' ? 'haiku' : 'sonnet',
    reviewSkill: String(parsed.reviewSkill),
    reviewFollowupSkill: String(parsed.reviewFollowupSkill),
    language: parsed.language === 'fr' ? 'fr' : 'en',
    retentionDays: parseRetentionDays(parsed.retentionDays),
    agents: parsed.agents as AgentDefinition[] | undefined,
    followupAgents: parsed.followupAgents as AgentDefinition[] | undefined,
    routingPolicy: parseRoutingPolicy(parsed.routingPolicy),
  };
}

/**
 * Get agents from project config or undefined for defaults
 */
export function getProjectAgents(localPath: string): AgentDefinition[] | undefined {
  try {
    const config = loadProjectConfig(localPath);
    return config?.agents;
  } catch {
    return undefined;
  }
}

/**
 * Get language from project config, defaulting to 'en'
 */
export function getProjectLanguage(localPath: string): Language {
  try {
    const config = loadProjectConfig(localPath);
    return config?.language ?? 'en';
  } catch {
    return 'en';
  }
}

/**
 * Get followup agents from project config or undefined for defaults
 */
export function getProjectRetentionDays(localPath: string): number {
  try {
    const config = loadProjectConfig(localPath);
    return config?.retentionDays ?? DEFAULT_RETENTION_DAYS;
  } catch {
    return DEFAULT_RETENTION_DAYS;
  }
}

export function getFollowupAgents(localPath: string): AgentDefinition[] | undefined {
  try {
    const config = loadProjectConfig(localPath);
    return config?.followupAgents;
  } catch {
    return undefined;
  }
}
