import { z } from 'zod';
import pino from 'pino';

const logger = pino({ name: 'notifications' });

export interface DriftNotification {
  tenantId: string;
  stackName: string;
  driftScore: number;
  criticalCount: number;
  highCount: number;
  totalDrifted: number;
  totalResources: number;
  reportUrl: string;
}

// --- Slack ---

const slackBlockKit = (n: DriftNotification) => ({
  blocks: [
    {
      type: 'header',
      text: { type: 'plain_text', text: `🔍 Drift Detected: ${n.stackName}` },
    },
    {
      type: 'section',
      fields: [
        { type: 'mrkdwn', text: `*Drift Score:* ${n.driftScore}/100` },
        { type: 'mrkdwn', text: `*Drifted:* ${n.totalDrifted}/${n.totalResources} resources` },
        { type: 'mrkdwn', text: `*Critical:* ${n.criticalCount}` },
        { type: 'mrkdwn', text: `*High:* ${n.highCount}` },
      ],
    },
    {
      type: 'actions',
      elements: [
        {
          type: 'button',
          text: { type: 'plain_text', text: '📋 View Report' },
          url: n.reportUrl,
          style: 'primary',
        },
        {
          type: 'button',
          text: { type: 'plain_text', text: '🔧 Remediate' },
          action_id: `remediate_${n.stackName}`,
          style: 'danger',
          confirm: {
            title: { type: 'plain_text', text: 'Generate Remediation Plan?' },
            text: { type: 'mrkdwn', text: `This will run \`terraform plan\` for *${n.stackName}*` },
            confirm: { type: 'plain_text', text: 'Yes, plan it' },
            deny: { type: 'plain_text', text: 'Cancel' },
          },
        },
        {
          type: 'button',
          text: { type: 'plain_text', text: '✅ Accept Drift' },
          action_id: `accept_${n.stackName}`,
        },
      ],
    },
  ],
});

export async function sendSlackNotification(webhookUrl: string, notification: DriftNotification): Promise<void> {
  const payload = slackBlockKit(notification);

  const resp = await fetch(webhookUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  });

  if (!resp.ok) {
    const text = await resp.text();
    // Slack 429 — respect retry-after
    if (resp.status === 429) {
      const retryAfter = parseInt(resp.headers.get('retry-after') ?? '5');
      logger.warn({ retryAfter }, 'Slack rate limited — backing off');
      throw new SlackRateLimitError(retryAfter);
    }
    throw new Error(`Slack webhook failed: ${resp.status} ${text}`);
  }
}

export class SlackRateLimitError extends Error {
  retryAfterSeconds: number;
  constructor(retryAfter: number) {
    super(`Slack rate limited, retry after ${retryAfter}s`);
    this.retryAfterSeconds = retryAfter;
  }
}

// --- Webhook ---

export async function sendWebhookNotification(url: string, notification: DriftNotification): Promise<void> {
  const resp = await fetch(url, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      event: 'drift.detected',
      ...notification,
      timestamp: new Date().toISOString(),
    }),
  });

  if (!resp.ok) {
    throw new Error(`Webhook delivery failed: ${resp.status}`);
  }
}

// --- Dispatcher ---

export interface NotificationChannel {
  channel: 'slack' | 'email' | 'webhook' | 'pagerduty';
  config: Record<string, string>;
  minSeverity: string;
  enabled: boolean;
}

const severityRank: Record<string, number> = {
  low: 1,
  medium: 2,
  high: 3,
  critical: 4,
};

export function shouldNotify(channel: NotificationChannel, driftScore: number, maxSeverity: string): boolean {
  if (!channel.enabled) return false;
  const channelRank = severityRank[channel.minSeverity] ?? 2;
  const eventRank = severityRank[maxSeverity] ?? 2;
  return eventRank >= channelRank;
}

export async function dispatchNotifications(
  channels: NotificationChannel[],
  notification: DriftNotification,
  maxSeverity: string,
): Promise<void> {
  for (const ch of channels) {
    if (!shouldNotify(ch, notification.driftScore, maxSeverity)) continue;

    try {
      switch (ch.channel) {
        case 'slack':
          await sendSlackNotification(ch.config.webhook_url!, notification);
          break;
        case 'webhook':
          await sendWebhookNotification(ch.config.url!, notification);
          break;
        case 'email':
          // TODO: Resend integration
          logger.info({ channel: 'email' }, 'Email notifications not yet implemented');
          break;
        case 'pagerduty':
          // TODO: PagerDuty Events API v2
          logger.info({ channel: 'pagerduty' }, 'PagerDuty notifications not yet implemented');
          break;
      }
    } catch (err) {
      if (err instanceof SlackRateLimitError) {
        // TODO: Queue for retry after backoff
        logger.warn({ retryAfter: err.retryAfterSeconds }, 'Slack notification queued for retry');
      } else {
        logger.error({ channel: ch.channel, error: (err as Error).message }, 'Notification delivery failed');
      }
    }
  }
}
