import fs from 'fs';
import { paths, DATA_DIR } from './paths.js';

export interface ChannelConfig {
  enabled: boolean;
  /** 'channel' = just talk to me (self-chat only), 'business' = admin/customer mode, 'assistant' = personal assistant in conversations */
  mode: 'channel' | 'business' | 'assistant';
  /** Phone numbers with admin access (owner, secretary, etc.) — business mode only */
  admins?: string[];
  /** Active skill for customer-facing mode (folder name in workspace/skills/) */
  skill?: string;
  /** Opt-in: process messages in group chats (default false). Channel mode ignores this. */
  allowGroups?: boolean;
  /** Assistant mode only. When false (default) ONLY the account owner can trigger the agent
   *  with `@botname`. When true, ANYONE who tags the bot (in a DM or group) can drive it.
   *  DANGER: the triggerer gains control of an agent that can run Bash, edit files, etc.
   *  Only enable for fully trusted shared use (e.g. a partner). See the WhatsApp SKILL.md. */
  allowOthersToTrigger?: boolean;
}

export interface AlexaChannelConfig {
  enabled: boolean;
  /** Per-user shared secret minted by the relay when the user first pairs an Alexa device.
   *  Used to verify that inbound /api/channels/alexa/handle calls actually came from the relay. */
  sharedSecret?: string;
}

export interface TelegramChannelConfig {
  enabled: boolean;
  /** Same semantics as WhatsApp: 'channel' = just talk to me (owner DM only), 'business' = admin/customer,
   *  'assistant' = personal assistant in conversations. */
  mode: 'channel' | 'business' | 'assistant';
  /** Telegram NUMERIC user IDs (not phone numbers) with admin access — business mode only. */
  admins?: string[];
  /** Active skill for customer-facing mode (folder name in workspace/skills/). */
  skill?: string;
  /** Opt-in: process messages in group chats (default false). Channel mode ignores this. */
  allowGroups?: boolean;
  /** Assistant mode only — see ChannelConfig.allowOthersToTrigger. DANGEROUS when true. */
  allowOthersToTrigger?: boolean;
  /** The bot's own access token (Bot API), from the user's own @BotFather bot (pasted at connect).
   *  Held locally — the Bloby long-polls Telegram DIRECTLY with this token; no relay is involved. */
  botToken?: string;
  /** The bot's @username (no @). For display + deep links. */
  botUsername?: string;
  /** Telegram user_id of the human who created/owns the bot. Treated as the admin/"self" identity:
   *  in channel mode only this user's 1:1 DMs reach the agent. */
  ownerUserId?: string;
}

export interface BotConfig {
  port: number;
  username: string;
  ai: {
    provider: 'openai' | 'anthropic' | 'ollama' | 'pi' | '';
    model: string;
    apiKey: string;
    baseUrl?: string;
  };
  tunnel: {
    mode: 'off' | 'quick' | 'named';
    name?: string;
    domain?: string;
    configPath?: string;
  };
  relay: {
    token: string;
    tier: string;
    url: string;
  };
  wallet?: {
    privateKey: string;
    address: string;
  };
  channels?: {
    whatsapp?: ChannelConfig;
    alexa?: AlexaChannelConfig;
    telegram?: TelegramChannelConfig;
  };
  tunnelUrl?: string;
}

const DEFAULTS: BotConfig = {
  port: 7400,
  username: '',
  ai: { provider: '', model: '', apiKey: '' },
  tunnel: { mode: 'quick' },
  relay: { token: '', tier: '', url: '' },
};

// One-shot model migrations: stored model id → replacement.
// Applied once on load; the rewritten config is persisted so each migration runs at most once per install.
const MODEL_MIGRATIONS: Record<string, string> = {
  'claude-opus-4-6': 'claude-opus-4-7[1m]',
  'claude-haiku-4-5-20251001': 'claude-haiku-4-5',
};

export function loadConfig(): BotConfig {
  if (!fs.existsSync(paths.config)) throw new Error('No config. Run `bloby init`.');
  const config = JSON.parse(fs.readFileSync(paths.config, 'utf-8'));
  let dirty = false;

  // Backward compat: migrate old { enabled: boolean } → { mode }
  if ('enabled' in config.tunnel && !('mode' in config.tunnel)) {
    config.tunnel = { mode: config.tunnel.enabled ? 'quick' : 'off' };
    dirty = true;
  }

  // Model migrations: bump stored model ids that were superseded by a newer release.
  const currentModel = config.ai?.model;
  if (currentModel && MODEL_MIGRATIONS[currentModel]) {
    config.ai.model = MODEL_MIGRATIONS[currentModel];
    dirty = true;
  }

  if (dirty) saveConfig(config);
  return config;
}

export function saveConfig(config: BotConfig): void {
  fs.mkdirSync(DATA_DIR, { recursive: true });
  fs.writeFileSync(paths.config, JSON.stringify(config, null, 2));
}