import { createDbService } from '@/server/services/db.js';
import { decryptChannelSecret } from '@/server/db/queries/alert-channels.js';
import { assertSafeFetchUrl, UnsafeFetchUrlError } from '@/server/security/safe-fetch-url';
import { buildAlertText } from '../render.js';
import { redactError } from '../redact.js';
import type {
  ChannelAdapter,
  AlertPayload,
  AlertChannelRow,
  MonitorEnv,
  ChannelSendResult,
} from '../types.js';

type ChannelWithSecret = AlertChannelRow & { __decryptedSecret?: string | null };

interface BotmasterConfig {
  baseUrl?: string; // e.g. https://botmaster.<host>/api
  sendPath?: string; // e.g. /messages/send  (default '/send')
  chatId?: string; // target chat/route id Botmaster understands
  authHeader?: string; // header name carrying the credential (default 'Authorization')
  authScheme?: string; // e.g. 'Bearer' (default 'Bearer')
  format?: string; // payload format the gateway expects (default 'text')
}

export const botmaster: ChannelAdapter = {
  kind: 'botmaster',
  async send(
    payload: AlertPayload,
    channel: ChannelWithSecret,
    env: MonitorEnv,
  ): Promise<ChannelSendResult> {
    let credential: string | null = null;
    let url: string | null = null;
    try {
      const cfg = (channel.config ?? {}) as BotmasterConfig;
      if (!cfg.baseUrl) return { ok: false, error: 'botmaster channel missing baseUrl' };
      if (!cfg.chatId) return { ok: false, error: 'botmaster channel missing chatId' };

      url = `${cfg.baseUrl.replace(/\/$/, '')}${cfg.sendPath ?? '/send'}`;
      try {
        assertSafeFetchUrl(url);
      } catch (err) {
        if (err instanceof UnsafeFetchUrlError)
          return { ok: false, error: 'botmaster channel target rejected' };
        throw err;
      }

      credential = channel.__decryptedSecret ?? null;
      if (credential == null) {
        const db = createDbService({ DATABASE_URL: env.DATABASE_URL });
        credential = await decryptChannelSecret(db, channel.id, env.PII_KEY);
      }
      if (!credential) return { ok: false, error: 'botmaster channel has no credential' };
      const headerName = cfg.authHeader ?? 'Authorization';
      const headerValue = `${cfg.authScheme ?? 'Bearer'} ${credential}`.trim();
      const text = buildAlertText(payload);
      const resp = await fetch(url, {
        method: 'POST',
        redirect: 'manual',
        headers: { 'Content-Type': 'application/json', [headerName]: headerValue },
        body: JSON.stringify({ chatId: cfg.chatId, text, format: cfg.format ?? 'text' }),
      });
      if (resp.status >= 300 && resp.status < 400) {
        return { ok: false, error: 'botmaster channel target returned a redirect' };
      }
      if (!resp.ok) return { ok: false, error: `botmaster HTTP ${resp.status}` };
      return { ok: true };
    } catch (err) {
      return { ok: false, error: redactError(err, 'botmaster send failed', credential, url) };
    }
  },
};
