import { Injectable, Inject, Logger, OnModuleInit } from '@nestjs/common';
import { KafkaService, PrismaService } from '../infrastructure';
import { EventAckPublisher } from '../infrastructure/kafka/event-ack.publisher';
import {
  REFERRAL_RELATIONSHIP_REPOSITORY,
  IReferralRelationshipRepository,
  TEAM_STATISTICS_REPOSITORY,
  ITeamStatisticsRepository,
} from '../domain';
import { TeamStatisticsService } from '../application/services';
import { UpdateTeamStatisticsCommand } from '../application/commands';

// ============================================
// 预种购买事件结构
// ============================================
interface PrePlantingPurchasedEvent {
  eventName: string;
  data: {
    orderNo: string;
    userId: string;
    accountSequence: string;
    portionCount: number;
    totalAmount: number;
    provinceCode: string;
    cityCode: string;
    totalPortionsAfter: number;
    availablePortionsAfter: number;
  };
  _outbox?: {
    id: string;
    aggregateId: string;
    eventType: string;
  };
}

// ============================================
// 预种合并事件结构
// ============================================
interface PrePlantingMergedEvent {
  eventName: string;
  data: {
    mergeNo: string;
    userId: string;
    accountSequence: string;
    sourceOrderNos: string[];
    treeCount: number;
    provinceCode: string;
    cityCode: string;
    totalTreesMergedAfter: number;
  };
  _outbox?: {
    id: string;
    aggregateId: string;
    eventType: string;
  };
}

/**
 * 预种事件处理器
 *
 * 消费 planting-service 发出的预种事件，更新团队统计
 *
 * 处理两类事件：
 * 1. pre-planting.portion.purchased — 更新预种份数统计（新增字段）
 * 2. pre-planting.merged — 5 份合并成树后，更新树级统计（复用现有 handlePlantingEvent）
 */
@Injectable()
export class PrePlantingPurchasedHandler implements OnModuleInit {
  private readonly logger = new Logger(PrePlantingPurchasedHandler.name);

  constructor(
    private readonly kafkaService: KafkaService,
    private readonly prisma: PrismaService,
    private readonly eventAckPublisher: EventAckPublisher,
    private readonly teamStatisticsService: TeamStatisticsService,
    @Inject(REFERRAL_RELATIONSHIP_REPOSITORY)
    private readonly referralRepo: IReferralRelationshipRepository,
    @Inject(TEAM_STATISTICS_REPOSITORY)
    private readonly teamStatsRepo: ITeamStatisticsRepository,
  ) {}

  async onModuleInit() {
    // 订阅预种购买事件
    await this.kafkaService.subscribe(
      'referral-service-pre-planting-purchased',
      ['pre-planting.portion.purchased'],
      this.handlePurchased.bind(this),
    );

    // 订阅预种合并事件
    await this.kafkaService.subscribe(
      'referral-service-pre-planting-merged',
      ['pre-planting.merged'],
      this.handleMerged.bind(this),
    );

    this.logger.log('Subscribed to pre-planting events (purchased + merged)');
  }

  // ============================================
  // 处理预种购买事件
  // 更新用户和所有上级的预种份数统计
  // ============================================
  private async handlePurchased(
    topic: string,
    message: Record<string, unknown>,
  ): Promise<void> {
    const event = message as unknown as PrePlantingPurchasedEvent;

    if (event.eventName !== 'pre-planting.portion.purchased') {
      return;
    }

    const outboxInfo = event._outbox;
    const eventId = outboxInfo?.aggregateId || 'unknown';

    // 幂等性检查
    if (eventId !== 'unknown') {
      const existing = await this.prisma.processedEvent.findUnique({
        where: { eventId },
      });
      if (existing) {
        this.logger.log(`[PRE-PLANTING] Event ${eventId} already processed, skipping`);
        if (outboxInfo) {
          await this.eventAckPublisher.sendSuccess(eventId, outboxInfo.eventType);
        }
        return;
      }
    }

    try {
      const { accountSequence, portionCount } = event.data;

      // 1. 查找用户推荐关系
      const relationship = await this.referralRepo.findByAccountSequence(accountSequence);
      if (!relationship) {
        this.logger.warn(
          `[PRE-PLANTING] User ${accountSequence} has no referral relationship`,
        );
        // 仍然发送确认，避免无限重试
        if (outboxInfo) {
          await this.eventAckPublisher.sendSuccess(eventId, outboxInfo.eventType);
        }
        return;
      }

      const userId = relationship.userId;

      // 2. 更新用户自己的预种份数
      await this.prisma.teamStatistics.updateMany({
        where: { userId },
        data: {
          selfPrePlantingPortions: { increment: portionCount },
          teamPrePlantingPortions: { increment: portionCount },
        },
      });

      // 3. 获取所有上级并更新团队预种份数
      const ancestors = relationship.getAllAncestorIds();
      if (ancestors.length > 0) {
        await this.prisma.teamStatistics.updateMany({
          where: { userId: { in: ancestors } },
          data: {
            teamPrePlantingPortions: { increment: portionCount },
          },
        });
      }

      this.logger.log(
        `[PRE-PLANTING] Updated pre-planting portions: user=${accountSequence}, ` +
        `portions=${portionCount}, ancestors=${ancestors.length}`,
      );

      // 4. 记录已处理
      if (eventId !== 'unknown') {
        await this.prisma.processedEvent.create({
          data: {
            eventId,
            eventType: outboxInfo?.eventType || 'pre-planting.portion.purchased',
          },
        });
      }

      // 5. 发送确认
      if (outboxInfo) {
        await this.eventAckPublisher.sendSuccess(eventId, outboxInfo.eventType);
      }
    } catch (error) {
      this.logger.error(
        `[PRE-PLANTING] Failed to process purchase event for ${event.data.accountSequence}:`,
        error,
      );
      if (outboxInfo) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        await this.eventAckPublisher.sendFailure(eventId, outboxInfo.eventType, errorMessage);
      }
    }
  }

  // ============================================
  // 处理预种合并事件
  // 5 份合并成 1 棵树 → 更新树级团队统计（复用现有流程）
  // ============================================
  private async handleMerged(
    topic: string,
    message: Record<string, unknown>,
  ): Promise<void> {
    const event = message as unknown as PrePlantingMergedEvent;

    if (event.eventName !== 'pre-planting.merged') {
      return;
    }

    const outboxInfo = event._outbox;
    const eventId = outboxInfo?.aggregateId || 'unknown';

    // 幂等性检查
    if (eventId !== 'unknown') {
      const existing = await this.prisma.processedEvent.findUnique({
        where: { eventId },
      });
      if (existing) {
        this.logger.log(`[PRE-PLANTING] Merge event ${eventId} already processed, skipping`);
        if (outboxInfo) {
          await this.eventAckPublisher.sendSuccess(eventId, outboxInfo.eventType);
        }
        return;
      }
    }

    try {
      const { accountSequence, treeCount, provinceCode, cityCode } = event.data;

      // 复用现有 TeamStatisticsService 更新树级统计
      // 这会更新 selfPlantingCount, totalTeamPlantingCount, leaderboard, 省市分布等
      const command = new UpdateTeamStatisticsCommand(
        accountSequence,
        treeCount,
        provinceCode,
        cityCode,
      );

      await this.teamStatisticsService.handlePlantingEvent(command);

      this.logger.log(
        `[PRE-PLANTING] Merge event processed: mergeNo=${event.data.mergeNo}, ` +
        `trees=${treeCount}, accountSequence=${accountSequence}`,
      );

      // 记录已处理
      if (eventId !== 'unknown') {
        await this.prisma.processedEvent.create({
          data: {
            eventId,
            eventType: outboxInfo?.eventType || 'pre-planting.merged',
          },
        });
      }

      // 发送确认
      if (outboxInfo) {
        await this.eventAckPublisher.sendSuccess(eventId, outboxInfo.eventType);
      }
    } catch (error) {
      this.logger.error(
        `[PRE-PLANTING] Failed to process merge event for ${event.data.accountSequence}:`,
        error,
      );
      if (outboxInfo) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        await this.eventAckPublisher.sendFailure(eventId, outboxInfo.eventType, errorMessage);
      }
    }
  }
}
