import { Injectable } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { PERFORMANCE_ERROR_CODES } from '../constants/error-codes';
import { BusinessException } from '@common/exceptions/business.exception';

/**
 * 等级配置定义
 */
export interface GradeDefinition {
  code: string;
  name: string;
  minScore: number;
  maxScore: number;
  color: string;
  order: number;
}

/**
 * 绩效等级配置服务
 * 负责可配置的绩效等级体系管理
 */
@Injectable()
export class GradeConfigService {
  constructor(private readonly prisma: PrismaService) {}

  /**
   * 默认五级制配置
   */
  static readonly DEFAULT_GRADES: GradeDefinition[] = [
    { code: 'S', name: '卓越', minScore: 90, maxScore: 100, color: '#52c41a', order: 1 },
    { code: 'A', name: '优秀', minScore: 80, maxScore: 89, color: '#1890ff', order: 2 },
    { code: 'B', name: '良好', minScore: 70, maxScore: 79, color: '#faad14', order: 3 },
    { code: 'C', name: '待改进', minScore: 60, maxScore: 69, color: '#ff7a45', order: 4 },
    { code: 'D', name: '不合格', minScore: 0, maxScore: 59, color: '#ff4d4f', order: 5 },
  ];

  // ==================== CRUD ====================

  async create(data: {
    name: string;
    description?: string;
    grades: GradeDefinition[];
    isDefault?: boolean;
    createdBy: string;
  }) {
    // 验证等级区间
    const validation = this.validateGrades(data.grades);
    if (!validation.valid) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.message,
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.code,
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.httpStatus,
        { error: validation.error },
      );
    }

    // 如果设为默认，先取消其他默认
    if (data.isDefault) {
      await this.prisma.gradeConfig.updateMany({
        where: { isDefault: true, deletedAt: null },
        data: { isDefault: false },
      });
    }

    return this.prisma.gradeConfig.create({
      data: {
        name: data.name,
        description: data.description,
        grades: data.grades as any,
        isDefault: data.isDefault ?? false,
        isActive: true,
        createdBy: data.createdBy,
      },
    });
  }

  async findAll(query?: { isActive?: boolean }) {
    const { isActive } = query || {};

    const where: any = { deletedAt: null };
    if (isActive !== undefined) where.isActive = isActive;

    const items = await this.prisma.gradeConfig.findMany({
      where,
      orderBy: [{ isDefault: 'desc' }, { createdAt: 'desc' }],
    });

    return { items };
  }

  async findById(id: string) {
    const config = await this.prisma.gradeConfig.findFirst({
      where: { id, deletedAt: null },
      include: {
        cycles: { where: { deletedAt: null }, select: { id: true, name: true, status: true }, take: 10 },
      },
    });

    if (!config) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.COMMON_NOT_FOUND.message,
        PERFORMANCE_ERROR_CODES.COMMON_NOT_FOUND.code,
        PERFORMANCE_ERROR_CODES.COMMON_NOT_FOUND.httpStatus,
      );
    }

    return config;
  }

  async findDefault() {
    const config = await this.prisma.gradeConfig.findFirst({
      where: { isDefault: true, isActive: true, deletedAt: null },
    });

    if (!config) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.COMMON_NOT_FOUND.message,
        PERFORMANCE_ERROR_CODES.COMMON_NOT_FOUND.code,
        PERFORMANCE_ERROR_CODES.COMMON_NOT_FOUND.httpStatus,
      );
    }

    return config;
  }

  async update(
    id: string,
    data: {
      name?: string;
      description?: string;
      grades?: GradeDefinition[];
      isActive?: boolean;
    },
  ) {
    const config = await this.findById(id);

    // 如果更新等级配置，需要验证
    if (data.grades) {
      const validation = this.validateGrades(data.grades);
      if (!validation.valid) {
        throw new BusinessException(
          PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.message,
          PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.code,
          PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.httpStatus,
          { error: validation.error },
        );
      }
    }

    // 检查是否有进行中的周期在使用此配置
    if (data.isActive === false) {
      const inUseCount = await this.prisma.performanceCycle.count({
        where: {
          gradeConfigId: id,
          deletedAt: null,
          status: { notIn: ['COMPLETED', 'ARCHIVED'] },
        },
      });
      if (inUseCount > 0) {
        throw new BusinessException(
          PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.message,
          PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.code,
          PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.httpStatus,
          { reason: 'grade_config_in_use' },
        );
      }
    }

    return this.prisma.gradeConfig.update({
      where: { id },
      data: {
        ...data,
        grades: data.grades as any,
      },
    });
  }

  async delete(id: string) {
    const config = await this.findById(id);

    // 检查是否在使用
    const usageCount = await this.prisma.performanceCycle.count({
      where: { gradeConfigId: id, deletedAt: null },
    });

    if (usageCount > 0) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.message,
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.code,
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.httpStatus,
        { reason: 'grade_config_in_use' },
      );
    }

    if (config.isDefault) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.message,
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.code,
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.httpStatus,
        { reason: 'grade_config_default' },
      );
    }

    await this.prisma.gradeConfig.update({
      where: { id },
      data: { deletedAt: new Date(), isActive: false },
    });
    return { success: true };
  }

  async setDefault(id: string) {
    const config = await this.findById(id);

    if (!config.isActive) {
      throw new BusinessException(
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.message,
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.code,
        PERFORMANCE_ERROR_CODES.COMMON_VALIDATION_FAILED.httpStatus,
        { reason: 'grade_config_inactive' },
      );
    }

    await this.prisma.$transaction([
      this.prisma.gradeConfig.updateMany({
        where: { isDefault: true, deletedAt: null },
        data: { isDefault: false },
      }),
      this.prisma.gradeConfig.update({
        where: { id },
        data: { isDefault: true },
      }),
    ]);

    return this.findById(id);
  }

  // ==================== 验证方法 ====================

  validateGrades(grades: GradeDefinition[]): {
    valid: boolean;
    error?: string;
  } {
    if (!grades || grades.length === 0) {
      return { valid: false, error: '至少需要一个等级' };
    }

    // 检查分数区间是否连续且不重叠，且覆盖 0-100
    const sorted = [...grades].sort((a, b) => a.minScore - b.minScore);

    // 检查是否从 0 开始
    if (sorted[0]?.minScore !== 0) {
      return { valid: false, error: '分数区间必须从 0 开始' };
    }

    // 检查是否到 100 结束
    if (sorted[sorted.length - 1]?.maxScore !== 100) {
      return { valid: false, error: '分数区间必须到 100 结束' };
    }

    // 检查是否连续无重叠
    for (let i = 0; i < sorted.length - 1; i++) {
      const current = sorted[i];
      const next = sorted[i + 1];
      if (current.maxScore + 1 !== next.minScore) {
        return { valid: false, error: '分数区间存在重叠或间隙' };
      }
    }

    // 检查 code 唯一性
    const codes = grades.map((g) => g.code);
    if (new Set(codes).size !== codes.length) {
      return { valid: false, error: '等级代码必须唯一' };
    }

    // 检查 order 唯一性
    const orders = grades.map((g) => g.order);
    if (new Set(orders).size !== orders.length) {
      return { valid: false, error: '等级排序必须唯一' };
    }

    return { valid: true };
  }

  /**
   * 根据分数获取等级
   */
  getGradeByScore(grades: GradeDefinition[], score: number): GradeDefinition | null {
    return grades.find((g) => score >= g.minScore && score <= g.maxScore) || null;
  }

  /**
   * 获取等级列表（用于下拉选择）
   */
  async getGradesForSelect(): Promise<{ id: string; name: string }[]> {
    const configs = await this.prisma.gradeConfig.findMany({
      where: { deletedAt: null },
      select: { id: true, name: true },
      orderBy: { createdAt: 'desc' },
    });
    return configs;
  }
}
