import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { GroupService } from './group.service';
import { TicketGroupNoAvailableMemberException } from '../exceptions';

/**
 * 分配策略接口
 */
interface AssignmentContext {
  ticketId: string;
  groupId: string;
  categoryId?: string;
  priority?: string;
}

@Injectable()
export class AssignService {
  private readonly logger = new Logger(AssignService.name);
  
  // 轮询状态缓存（生产环境应使用 Redis）
  private roundRobinIndex: Map<string, number> = new Map();

  constructor(
    private readonly prisma: PrismaService,
    private readonly groupService: GroupService,
  ) {}

  /**
   * 自动分配工单
   */
  async autoAssign(ticketId: string, groupId: string): Promise<string | null> {
    const group = await this.prisma.assignmentGroup.findUnique({
      where: { id: groupId },
    });

    if (!group || !group.isActive) {
      this.logger.warn(`处理组 ${groupId} 不存在或已停用`);
      return null;
    }

    const members = await this.groupService.getAvailableMembers(groupId);
    if (members.length === 0) {
      this.logger.warn(`处理组 ${groupId} 无可用成员`);
      return null;
    }

    let assigneeId: string | null = null;

    // 根据分配策略选择处理人
    switch (group.assignmentStrategy) {
      case 'ROUND_ROBIN':
        assigneeId = this.roundRobinAssign(groupId, members);
        break;
      case 'LOAD_BALANCE':
        assigneeId = await this.loadBalanceAssign(members);
        break;
      case 'SKILL_BASED':
        // Phase 3+ 实现
        assigneeId = this.roundRobinAssign(groupId, members);
        break;
      case 'MANUAL':
      default:
        // 手动分配不自动指定处理人
        return null;
    }

    if (assigneeId) {
      await this.prisma.ticket.update({
        where: { id: ticketId },
        data: {
          assigneeId,
          status: 'ASSIGNED',
        },
      });

      // 记录分配活动（null 表示系统自动分配）
      await this.prisma.ticketActivity.create({
        data: {
          ticketId,
          type: 'ASSIGNED',
          content: {
            assigneeId,
            groupId,
            strategy: group.assignmentStrategy,
            isAutoAssign: true,
          },
          operatorId: null,
        },
      });

      this.logger.log(`工单 ${ticketId} 自动分配给 ${assigneeId}`);
    }

    return assigneeId;
  }

  /**
   * 轮询分配策略
   */
  private roundRobinAssign(groupId: string, members: string[]): string {
    const currentIndex = this.roundRobinIndex.get(groupId) || 0;
    const assigneeId = members[currentIndex % members.length];
    this.roundRobinIndex.set(groupId, currentIndex + 1);
    return assigneeId;
  }

  /**
   * 负载均衡分配策略
   * Phase 3 实现更复杂的负载计算
   */
  private async loadBalanceAssign(members: string[]): Promise<string> {
    // 获取每个成员的未完成工单数
    const workloads = await Promise.all(
      members.map(async (memberId) => {
        const count = await this.prisma.ticket.count({
          where: {
            assigneeId: memberId,
            status: {
              in: ['ASSIGNED', 'IN_PROGRESS', 'PENDING'],
            },
          },
        });
        return { memberId, count };
      }),
    );

    // 选择工单数最少的成员
    workloads.sort((a, b) => a.count - b.count);
    return workloads[0].memberId;
  }

  /**
   * 重新分配工单
   */
  async reassign(
    ticketId: string,
    newAssigneeId: string,
    operatorId: string,
    comment?: string,
  ) {
    const ticket = await this.prisma.ticket.findUnique({
      where: { id: ticketId },
    });

    if (!ticket) {
      return null;
    }

    const oldAssigneeId = ticket.assigneeId;

    await this.prisma.ticket.update({
      where: { id: ticketId },
      data: {
        assigneeId: newAssigneeId,
        status: ticket.status === 'OPEN' ? 'ASSIGNED' : ticket.status,
      },
    });

    // 记录重新分配活动
    await this.prisma.ticketActivity.create({
      data: {
        ticketId,
        type: 'REASSIGNED',
        content: {
          oldAssigneeId,
          newAssigneeId,
          comment,
        },
        operatorId,
      },
    });

    this.logger.log(
      `工单 ${ticketId} 从 ${oldAssigneeId} 重新分配给 ${newAssigneeId}`,
    );

    return { oldAssigneeId, newAssigneeId };
  }

  /**
   * 取消分配
   */
  async unassign(ticketId: string, operatorId: string) {
    const ticket = await this.prisma.ticket.findUnique({
      where: { id: ticketId },
    });

    if (!ticket) {
      return null;
    }

    const oldAssigneeId = ticket.assigneeId;

    await this.prisma.ticket.update({
      where: { id: ticketId },
      data: {
        assigneeId: null,
        status: 'OPEN',
      },
    });

    // 记录取消分配活动
    await this.prisma.ticketActivity.create({
      data: {
        ticketId,
        type: 'REASSIGNED',
        content: {
          oldAssigneeId,
          newAssigneeId: null,
          isUnassign: true,
        },
        operatorId,
      },
    });

    this.logger.log(`工单 ${ticketId} 已取消分配`);

    return { oldAssigneeId };
  }

  /**
   * 批量自动分配（用于处理队列中的工单）
   */
  async batchAutoAssign(groupId: string, limit: number = 10): Promise<number> {
    // 获取待分配的工单
    const tickets = await this.prisma.ticket.findMany({
      where: {
        assigneeGroupId: groupId,
        assigneeId: null,
        status: 'OPEN',
      },
      take: limit,
      orderBy: [
        { priority: 'desc' }, // 高优先级优先
        { createdAt: 'asc' }, // 先创建的优先
      ],
    });

    let assignedCount = 0;

    for (const ticket of tickets) {
      const assigneeId = await this.autoAssign(ticket.id, groupId);
      if (assigneeId) {
        assignedCount++;
      }
    }

    return assignedCount;
  }
}
