import { stringify } from 'yaml';

interface ProviderConfig {
  provider: string;
  model: string;
  api_key?: string;
  auth_token?: string;
  endpoint?: string;
}

interface EmbeddingConfig {
  provider: string;
  api_key?: string;
  endpoint?: string;
}

export interface SetupConfig {
  log_level?: string;
  models: Record<string, ProviderConfig & Record<string, unknown>>;
  server: {
    port?: number;
    localhost?: boolean;
    token?: string;
    lock?: boolean;
    tailscale?: { serve?: boolean };
  } & Record<string, unknown>;
  hooks?: Record<string, unknown>;
  telegram?: { bot_token: string; allowed_chat_ids: number[] };
  discord?: { bot_token: string; allowed_guild_ids: string[] };
  slack?: { bot_token: string; app_token: string; signing_secret: string; allowed_channel_ids: string[] };
  whatsapp?: { allowed_numbers: string[] };
  memory?: { embedding?: { enabled?: boolean; provider?: string; api_key?: string; endpoint?: string } };
  sandbox?: { enabled?: boolean };
  pairing?: { enabled?: boolean };
  tools?: { profile?: string };
  agents?: {
    sensitive_mode?: 'deny_without_elevation' | 'confirm_without_elevation';
  };
  agent_configs?: Record<string, {
    model_tier?: 'fast' | 'default' | 'complex' | 'local';
    tool_profile?: string;
    system_prompt?: string;
  }>;
  intents?: {
    enabled?: boolean;
    match_threshold?: number;
    rules?: Array<Record<string, unknown>>;
  };
  automation?: {
    cron?: Array<Record<string, unknown>>;
    webhooks?: Array<Record<string, unknown>>;
    gmail?: { enabled?: boolean };
    gcal?: { enabled?: boolean };
    gdocs?: { enabled?: boolean };
    gdrive?: { enabled?: boolean };
    gtasks?: { enabled?: boolean };
    heartbeat?: { enabled?: boolean };
    daily_briefing?: { enabled?: boolean };
    minio_sync?: { enabled?: boolean };
  } & Record<string, unknown>;
  backup?: {
    enabled?: boolean;
    schedule?: string;
    run_on_start?: boolean;
    notify?: { channel: string; peer: string };
  } & Record<string, unknown>;
  [key: string]: unknown;
}

interface OperatorPackOptions {
  outputChannel: string;
  outputPeer: string;
  backupSchedule: string;
  dailyBriefingSchedule: string;
  enableMinioSync?: boolean;
}

interface ResearchAgentOptions {
  modelTier: 'fast' | 'default' | 'complex' | 'local';
}

export class ConfigBuilder {
  private config: SetupConfig;

  constructor() {
    this.config = {
      log_level: 'info',
      models: {},
      server: { port: 18800, localhost: false },
      hooks: {
        confirm: [
          'shell.*',
          'process.start',
          'process.kill',
          'browser.*',
          'message.send',
          'cron.create',
          'cron.delete',
          'file.write',
          'file.patch',
        ],
        log: ['web.*', 'file.read'],
        silent: ['notify'],
      },
      tools: { profile: 'full' },
      agents: { sensitive_mode: 'confirm_without_elevation' },
    };
  }

  static fromObject(obj: Record<string, unknown>): ConfigBuilder {
    const builder = new ConfigBuilder();
    builder.config = structuredClone(obj) as SetupConfig;
    return builder;
  }

  setProvider(tier: 'default' | 'fast' | 'complex' | 'local', cfg: ProviderConfig): void {
    const models = (this.config.models ?? {}) as SetupConfig['models'];
    const entry: ProviderConfig & Record<string, unknown> = { provider: cfg.provider, model: cfg.model };
    if (cfg.api_key) {entry.api_key = cfg.api_key;}
    if (cfg.auth_token) {entry.auth_token = cfg.auth_token;}
    if (cfg.endpoint) {entry.endpoint = cfg.endpoint;}
    models[tier] = entry;
    this.config.models = models;
  }

  setTelegram(botToken: string, chatIds: number[]): void {
    this.config.telegram = { bot_token: botToken, allowed_chat_ids: chatIds };
  }

  setDiscord(botToken: string, guildIds: string[]): void {
    this.config.discord = { bot_token: botToken, allowed_guild_ids: guildIds };
  }

  setSlack(botToken: string, appToken: string, signingSecret: string, channelIds: string[]): void {
    this.config.slack = { bot_token: botToken, app_token: appToken, signing_secret: signingSecret, allowed_channel_ids: channelIds };
  }

  setWhatsApp(allowedNumbers: string[]): void {
    this.config.whatsapp = { allowed_numbers: allowedNumbers };
  }

  setGatewayPort(port: number): void {
    const server = (this.config.server ?? {}) as Record<string, unknown>;
    server.port = port;
    this.config.server = server;
  }

  setGatewayToken(token: string): void {
    const server = (this.config.server ?? {}) as Record<string, unknown>;
    server.token = token;
    this.config.server = server;
  }

  setGatewayLock(enabled: boolean): void {
    const server = (this.config.server ?? {}) as Record<string, unknown>;
    server.lock = enabled;
    this.config.server = server;
  }

  setTailscaleServe(enabled: boolean): void {
    const server = (this.config.server ?? {}) as Record<string, unknown>;
    const tailscale = (server.tailscale ?? {}) as Record<string, unknown>;
    tailscale.serve = enabled;
    server.tailscale = tailscale;
    this.config.server = server;
  }

  setMemoryEmbedding(cfg: EmbeddingConfig): void {
    const memory = (this.config.memory ?? {}) as Record<string, unknown>;
    const embedding: Record<string, unknown> = { enabled: true, provider: cfg.provider };
    if (cfg.api_key) {embedding.api_key = cfg.api_key;}
    if (cfg.endpoint) {embedding.endpoint = cfg.endpoint;}
    memory.embedding = embedding;
    this.config.memory = memory;
  }

  setSandboxEnabled(enabled: boolean): void {
    this.config.sandbox = { enabled };
  }

  setPairingEnabled(enabled: boolean): void {
    this.config.pairing = { enabled };
  }

  setToolProfile(profile: string): void {
    this.config.tools = { profile };
  }

  setSensitiveMode(mode: 'deny_without_elevation' | 'confirm_without_elevation'): void {
    const agents = (this.config.agents ?? {}) as Record<string, unknown>;
    agents.sensitive_mode = mode;
    this.config.agents = agents as SetupConfig['agents'];
  }

  setResearchAgentEnabled(options: ResearchAgentOptions): void {
    const agentConfigs = (this.config.agent_configs ?? {}) as Record<string, Record<string, unknown>>;
    const existing = (agentConfigs.research ?? {}) as Record<string, unknown>;
    agentConfigs.research = {
      ...existing,
      model_tier: options.modelTier,
      tool_profile: 'messaging',
      system_prompt: [
        'You are a research agent. Find, verify, and synthesize information for the operator.',
        'Prefer primary sources and include concrete dates and links when available.',
        'Keep output structured and concise.',
      ].join(' '),
    };
    this.config.agent_configs = agentConfigs;
  }

  setWebhooksEnabled(secret?: string): void {
    const automation = (this.config.automation ?? {}) as Record<string, unknown>;
    if (secret) {
      automation.webhooks = [{ name: 'default', secret, message: '{{body}}', output: { channel: 'webchat', peer: 'webhook' }, enabled: true }];
    } else {
      automation.webhooks = automation.webhooks ?? [];
    }
    this.config.automation = automation;
  }

  setGmailEnabled(credentialsFile: string, outputChannel: string, outputPeer: string): void {
    const automation = (this.config.automation ?? {}) as Record<string, unknown>;
    automation.gmail = { enabled: true, credentials_file: credentialsFile, output: { channel: outputChannel, peer: outputPeer } };
    this.config.automation = automation;
  }

  setGcalEnabled(credentialsFile: string): void {
    const automation = (this.config.automation ?? {}) as Record<string, unknown>;
    automation.gcal = { enabled: true, credentials_file: credentialsFile };
    this.config.automation = automation;
  }

  setGdocsEnabled(credentialsFile: string): void {
    const automation = (this.config.automation ?? {}) as Record<string, unknown>;
    automation.gdocs = { enabled: true, credentials_file: credentialsFile };
    this.config.automation = automation;
  }

  setGdriveEnabled(credentialsFile: string): void {
    const automation = (this.config.automation ?? {}) as Record<string, unknown>;
    automation.gdrive = { enabled: true, credentials_file: credentialsFile };
    this.config.automation = automation;
  }

  setGtasksEnabled(credentialsFile: string): void {
    const automation = (this.config.automation ?? {}) as Record<string, unknown>;
    automation.gtasks = { enabled: true, credentials_file: credentialsFile };
    this.config.automation = automation;
  }

  setCronEnabled(): void {
    const automation = (this.config.automation ?? {}) as Record<string, unknown>;
    if (!automation.cron) {automation.cron = [];}
    this.config.automation = automation;
  }

  applyOperatorPack(options: OperatorPackOptions): void {
    const automation = (this.config.automation ?? {}) as Record<string, unknown>;
    const backup = (this.config.backup ?? {}) as Record<string, unknown>;
    const memory = (this.config.memory ?? {}) as Record<string, unknown>;

    backup.enabled = true;
    backup.schedule = options.backupSchedule;
    backup.run_on_start = true;
    backup.notify = { channel: options.outputChannel, peer: options.outputPeer };

    // Personal-assistant mode defaults: proactive push and continuity-first memory cadence.
    automation.delivery_mode = 'announce';

    automation.heartbeat = {
      enabled: true,
      notify: { channel: options.outputChannel, peer: options.outputPeer },
      interval: '5m',
      failure_threshold: 2,
      notify_cooldown: '30m',
    };

    automation.daily_briefing = {
      enabled: true,
      schedule: options.dailyBriefingSchedule,
      output: { channel: options.outputChannel, peer: options.outputPeer },
      dedupe_per_local_day: true,
      model_tier: 'fast',
    };

    if (options.enableMinioSync ?? true) {
      automation.minio_sync = {
        enabled: true,
        interval: '6h',
        run_on_start: true,
        notify: { channel: options.outputChannel, peer: options.outputPeer },
        tasks: [
          {
            prefix: 'knowledge/',
            namespace_base: 'global/knowledge/minio',
            mode: 'append',
            max_objects: 20,
            max_chars_per_object: 8000,
            force: false,
          },
        ],
      };
    }

    memory.daily_log = {
      enabled: true,
      namespace_prefix: 'daily',
    };
    memory.proactive_extract = {
      enabled: true,
      min_tool_calls: 1,
      namespace: 'global',
    };

    this.config.automation = automation;
    this.config.backup = backup;
    this.config.memory = memory;
  }

  build(): SetupConfig {
    return structuredClone(this.config) as SetupConfig;
  }

  toYaml(): string {
    return stringify(this.config, { lineWidth: 120 });
  }
}
