import { Injectable, OnApplicationBootstrap, OnApplicationShutdown, Logger } from '@nestjs/common';
import Redis from 'ioredis';
import { NotificationRepository } from '../../infrastructure/repositories/notification.repository';

/**
 * EventTriggerService — Redis Stream consumer for auto-triggered notifications.
 *
 * Listens to platform event streams and auto-creates/sends relevant notifications.
 *
 * Supported events:
 *   - events:billing.payment_failed  → BILLING notification to specific tenant
 *   - events:billing.quota_warning   → BILLING notification to specific tenant
 *   - events:tenant.registered       → SYSTEM welcome notification to new tenant
 *   - events:alert.fired             → SYSTEM ops alert notification to specific tenant
 */
@Injectable()
export class EventTriggerService implements OnApplicationBootstrap, OnApplicationShutdown {
  private readonly logger = new Logger(EventTriggerService.name);
  private redis: Redis;
  private running = false;

  private readonly GROUP = 'notification-service';
  private readonly CONSUMER = `notification-service-${process.pid}`;

  private readonly STREAMS = [
    'events:billing.payment_failed',
    'events:billing.quota_warning',
    'events:tenant.registered',
    'events:alert.fired',
  ];

  constructor(private readonly notificationRepo: NotificationRepository) {}

  onApplicationBootstrap() {
    const redisUrl = process.env.REDIS_URL || 'redis://redis:6379';
    this.redis = new Redis(redisUrl, { lazyConnect: true, enableOfflineQueue: false });
    this.redis.on('error', (err) => this.logger.warn(`Redis error: ${err.message}`));
    this.running = true;
    this.startConsuming();
  }

  onApplicationShutdown() {
    this.running = false;
    this.redis?.quit();
  }

  private async startConsuming() {
    // Ensure consumer groups exist
    for (const stream of this.STREAMS) {
      try {
        await this.redis.xgroup('CREATE', stream, this.GROUP, '$', 'MKSTREAM');
      } catch {
        // Group already exists — ok
      }
    }

    while (this.running) {
      try {
        const results = await this.redis.xreadgroup(
          'GROUP', this.GROUP, this.CONSUMER,
          'COUNT', '10',
          'BLOCK', '5000',
          'STREAMS', ...this.STREAMS, ...this.STREAMS.map(() => '>'),
        ) as [string, [string, string[]][]][] | null;

        if (!results) continue;

        for (const [stream, messages] of results) {
          for (const [id, fields] of messages) {
            try {
              const data = JSON.parse(fields[1]);
              await this.handleEvent(stream, data);
              await this.redis.xack(stream, this.GROUP, id);
            } catch (err) {
              this.logger.error(`Failed to process event ${id} on ${stream}: ${err}`);
            }
          }
        }
      } catch (err: any) {
        if (this.running) {
          this.logger.warn(`Redis stream error: ${err.message}`);
          await new Promise((r) => setTimeout(r, 2000));
        }
      }
    }
  }

  private async handleEvent(stream: string, event: any): Promise<void> {
    this.logger.debug(`Processing event from ${stream}: tenantId=${event.tenantId}`);

    switch (stream) {
      case 'events:billing.payment_failed':
        await this.notificationRepo.create({
          title: '支付失败提醒',
          content: `您的账单支付失败，金额 ${event.payload?.amountFormatted ?? ''}。请及时处理，避免服务中断。`,
          type: 'BILLING',
          priority: 'HIGH',
          targetType: 'SPECIFIC_TENANTS',
          tenantIds: [event.tenantId],
          requiresForceRead: false,
          isEnabled: true,
          channelKey: 'billing',
        });
        break;

      case 'events:billing.quota_warning':
        await this.notificationRepo.create({
          title: '用量配额预警',
          content: `您的账户 Token 用量已达到 ${event.payload?.usagePercent ?? 80}%，请关注用量或升级套餐。`,
          type: 'BILLING',
          priority: 'NORMAL',
          targetType: 'SPECIFIC_TENANTS',
          tenantIds: [event.tenantId],
          requiresForceRead: false,
          isEnabled: true,
          channelKey: 'billing',
        });
        break;

      case 'events:tenant.registered': {
        // Welcome notification to new tenant — target ALL initially,
        // but for welcome we use SPECIFIC_TENANTS
        await this.notificationRepo.create({
          title: '欢迎使用 iAgent！',
          content: '感谢您注册 iAgent 平台！您现在可以部署 AI 智能体来管理您的服务器集群。如需帮助，请查看文档或联系支持团队。',
          type: 'ANNOUNCEMENT',
          priority: 'NORMAL',
          targetType: 'SPECIFIC_TENANTS',
          tenantIds: [event.tenantId],
          requiresForceRead: false,
          isEnabled: true,
        });
        break;
      }

      case 'events:alert.fired': {
        const severity = event.payload?.severity ?? 'warning';
        const priority = severity === 'critical' || severity === 'fatal' ? 'URGENT' : 'HIGH';
        await this.notificationRepo.create({
          title: `运维告警：${severity.toUpperCase()}`,
          content: event.payload?.message ?? '服务器异常告警，请及时处理。',
          type: 'SYSTEM',
          priority,
          targetType: 'SPECIFIC_TENANTS',
          tenantIds: [event.tenantId],
          requiresForceRead: priority === 'URGENT',
          isEnabled: true,
          channelKey: 'ops',
        });
        break;
      }

      default:
        this.logger.warn(`Unhandled event stream: ${stream}`);
    }
  }
}
