import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { Prisma } from '@prisma/client';
import {
  CreateFeedbackDto,
  UpdateFeedbackDto,
  UpdateStatusDto,
  BatchUpdateStatusDto,
  FeedbackQueryDto,
  AdminFeedbackQueryDto,
  FeedbackStatsQueryDto,
  FeedbackStatus,
  FeedbackType,
  FeedbackPriority,
  BatchUpdateResultDto,
} from './dto/feedback.dto';
import {
  FeedbackNotFoundException,
  FeedbackAccessDeniedException,
  FeedbackInvalidStatusTransitionException,
  FeedbackAttachmentsExceedLimitException,
  FeedbackBatchLimitExceededException,
} from './feedback.exceptions';
import { UserNotFoundException } from '@common/exceptions/business.exception';

// ============================================================================
// Constants
// ============================================================================

/**
 * 状态转换规则
 * 定义每个状态可以转换到哪些目标状态
 */
const STATUS_TRANSITIONS: Record<FeedbackStatus, FeedbackStatus[]> = {
  [FeedbackStatus.PENDING]: [FeedbackStatus.IN_PROGRESS, FeedbackStatus.CLOSED],
  [FeedbackStatus.IN_PROGRESS]: [
    FeedbackStatus.RESOLVED,
    FeedbackStatus.CLOSED,
    FeedbackStatus.PENDING,
  ],
  [FeedbackStatus.RESOLVED]: [
    FeedbackStatus.CLOSED,
    FeedbackStatus.IN_PROGRESS,
  ],
  [FeedbackStatus.CLOSED]: [FeedbackStatus.PENDING],
};

/**
 * 全局管理员角色代码列表
 */
const GLOBAL_ADMIN_ROLES = ['ADMINISTRATOR', 'FEEDBACK_ADMIN'];

/**
 * 区域管理员角色前缀
 */
const REGION_ADMIN_ROLE_PREFIX = 'FEEDBACK_ADMIN_';

// ============================================================================
// Service
// ============================================================================

@Injectable()
export class FeedbackService {
  private readonly logger = new Logger(FeedbackService.name);

  constructor(private readonly prisma: PrismaService) {}

  // ==========================================================================
  // User APIs
  // ==========================================================================

  /**
   * 创建反馈（用户端）
   */
  async create(userId: string, dto: CreateFeedbackDto) {
    if (dto.attachments && dto.attachments.length > 5) {
      throw new FeedbackAttachmentsExceedLimitException(5);
    }

    // 获取用户信息，包括 region
    const user = await this.prisma.user.findUnique({
      where: { id: userId },
      select: {
        id: true,
        metadata: true,
      },
    });

    if (!user) {
      throw new UserNotFoundException(userId);
    }

    // 从用户元数据中获取 region，默认为 'CN'
    const metadata = user.metadata as Record<string, any> || {};
    const region = metadata.region || 'CN';

    // 创建反馈
    const feedback = await this.prisma.feedback.create({
      data: {
        type: dto.type,
        title: dto.title,
        content: dto.content,
        attachments: dto.attachments || [],
        pageUrl: dto.pageUrl,
        userAgent: dto.userAgent,
        status: FeedbackStatus.PENDING,
        userId,
        region,
      },
      include: this.getUserFeedbackInclude(),
    });

    return this.formatUserFeedback(feedback);
  }

  /**
   * 获取当前用户的反馈列表
   */
  async findMyFeedbacks(userId: string, query: FeedbackQueryDto) {
    const { page = 1, pageSize = 20, status, type, sortBy, sortOrder } = query;
    const skip = (page - 1) * pageSize;

    const where: Prisma.FeedbackWhereInput = {
      userId,
      deletedAt: null,
      ...(status && { status }),
      ...(type && { type }),
    };

    const orderBy: Prisma.FeedbackOrderByWithRelationInput = {
      [sortBy || 'createdAt']: sortOrder || 'desc',
    };

    const [items, total] = await Promise.all([
      this.prisma.feedback.findMany({
        where,
        orderBy,
        skip,
        take: pageSize,
        include: this.getUserFeedbackInclude(),
      }),
      this.prisma.feedback.count({ where }),
    ]);

    return {
      items: items.map((item) => this.formatUserFeedback(item)),
      total,
      page,
      limit: pageSize,
      totalPages: Math.ceil(total / pageSize),
      hasNext: page * pageSize < total,
      hasPrev: page > 1,
    };
  }

  /**
   * 获取当前用户的单条反馈详情
   */
  async findMyFeedbackById(userId: string, feedbackId: string) {
    const feedback = await this.prisma.feedback.findFirst({
      where: {
        id: feedbackId,
        deletedAt: null,
      },
      include: this.getUserFeedbackInclude(),
    });

    if (!feedback) {
      throw new FeedbackNotFoundException(feedbackId);
    }

    if (feedback.userId !== userId) {
      throw new FeedbackAccessDeniedException(
        '无权查看该反馈（非本人提交）',
      );
    }

    return this.formatUserFeedback(feedback);
  }

  // ==========================================================================
  // Admin APIs
  // ==========================================================================

  /**
   * 获取反馈列表（管理员）
   */
  async findAll(
    adminUserId: string,
    query: AdminFeedbackQueryDto,
  ) {
    const {
      page = 1,
      pageSize = 20,
      keyword,
      status,
      type,
      priority,
      region,
      userId,
      assigneeId,
      startDate,
      endDate,
      sortBy,
      sortOrder,
    } = query;

    const skip = (page - 1) * pageSize;

    // 获取管理员的区域权限
    const regionFilter = await this.getRegionFilter(adminUserId, region);

    const where: Prisma.FeedbackWhereInput = {
      deletedAt: null,
      ...regionFilter,
      ...(status && { status }),
      ...(type && { type }),
      ...(priority && { priority }),
      ...(userId && { userId }),
      ...(assigneeId && { assigneeId }),
      ...(startDate && {
        createdAt: {
          gte: new Date(startDate),
          ...(endDate && { lte: new Date(endDate) }),
        },
      }),
      ...(endDate &&
        !startDate && {
          createdAt: { lte: new Date(endDate) },
        }),
      ...(keyword && {
        OR: [
          { title: { contains: keyword, mode: 'insensitive' } },
          { content: { contains: keyword, mode: 'insensitive' } },
        ],
      }),
    };

    const orderBy: Prisma.FeedbackOrderByWithRelationInput = {
      [sortBy || 'createdAt']: sortOrder || 'desc',
    };

    const [items, total] = await Promise.all([
      this.prisma.feedback.findMany({
        where,
        orderBy,
        skip,
        take: pageSize,
        include: this.getAdminFeedbackInclude(),
      }),
      this.prisma.feedback.count({ where }),
    ]);

    return {
      items: items.map((item) => this.formatAdminFeedback(item)),
      total,
      page,
      limit: pageSize,
      totalPages: Math.ceil(total / pageSize),
      hasNext: page * pageSize < total,
      hasPrev: page > 1,
    };
  }

  /**
   * 获取反馈详情（管理员）
   */
  async findById(adminUserId: string, feedbackId: string) {
    const feedback = await this.prisma.feedback.findFirst({
      where: {
        id: feedbackId,
        deletedAt: null,
      },
      include: this.getAdminFeedbackInclude(),
    });

    if (!feedback) {
      throw new FeedbackNotFoundException(feedbackId);
    }

    // 检查区域权限
    await this.checkRegionAccess(adminUserId, feedback.region);

    return this.formatAdminFeedback(feedback);
  }

  /**
   * 更新反馈状态
   */
  async updateStatus(
    adminUserId: string,
    feedbackId: string,
    dto: UpdateStatusDto,
  ) {
    const feedback = await this.prisma.feedback.findFirst({
      where: {
        id: feedbackId,
        deletedAt: null,
      },
    });

    if (!feedback) {
      throw new FeedbackNotFoundException(feedbackId);
    }

    // 检查区域权限
    await this.checkRegionAccess(adminUserId, feedback.region);

    // 验证状态转换是否合法
    this.validateStatusTransition(
      feedback.status as FeedbackStatus,
      dto.status,
    );

    // 准备更新数据
    const updateData: Prisma.FeedbackUpdateInput = {
      status: dto.status,
    };

    // 如果变更为 RESOLVED，设置 resolvedAt
    if (dto.status === FeedbackStatus.RESOLVED && !feedback.resolvedAt) {
      updateData.resolvedAt = new Date();
    }

    // 如果从 RESOLVED 变更为其他状态，清空 resolvedAt
    if (
      feedback.status === FeedbackStatus.RESOLVED &&
      dto.status !== FeedbackStatus.RESOLVED
    ) {
      updateData.resolvedAt = null;
    }

    const updated = await this.prisma.feedback.update({
      where: { id: feedbackId },
      data: updateData,
      select: {
        id: true,
        status: true,
        updatedAt: true,
      },
    });

    return updated;
  }

  /**
   * 更新反馈信息（管理员）
   */
  async update(
    adminUserId: string,
    feedbackId: string,
    dto: UpdateFeedbackDto,
  ) {
    const feedback = await this.prisma.feedback.findFirst({
      where: {
        id: feedbackId,
        deletedAt: null,
      },
    });

    if (!feedback) {
      throw new FeedbackNotFoundException(feedbackId);
    }

    // 检查区域权限
    await this.checkRegionAccess(adminUserId, feedback.region);

    // 如果指定了 assigneeId，验证用户存在
    if (dto.assigneeId) {
      const assignee = await this.prisma.user.findUnique({
        where: { id: dto.assigneeId },
      });
      if (!assignee) {
        throw new UserNotFoundException(dto.assigneeId);
      }
    }

    const updated = await this.prisma.feedback.update({
      where: { id: feedbackId },
      data: {
        ...(dto.priority !== undefined && { priority: dto.priority }),
        ...(dto.adminNote !== undefined && { adminNote: dto.adminNote }),
        ...(dto.adminReply !== undefined && { adminReply: dto.adminReply }),
        ...(dto.assigneeId !== undefined && { assigneeId: dto.assigneeId }),
      },
      include: {
        assignee: {
          select: {
            id: true,
            displayName: true,
          },
        },
      },
    });

    return {
      id: updated.id,
      priority: updated.priority,
      adminNote: updated.adminNote,
      adminReply: updated.adminReply,
      assignee: updated.assignee
        ? {
            id: updated.assignee.id,
            displayName: updated.assignee.displayName,
          }
        : null,
      updatedAt: updated.updatedAt,
    };
  }

  /**
   * 删除反馈（软删除）
   */
  async delete(adminUserId: string, feedbackId: string) {
    const feedback = await this.prisma.feedback.findFirst({
      where: {
        id: feedbackId,
        deletedAt: null,
      },
    });

    if (!feedback) {
      throw new FeedbackNotFoundException(feedbackId);
    }

    // 检查区域权限
    await this.checkRegionAccess(adminUserId, feedback.region);

    await this.prisma.feedback.update({
      where: { id: feedbackId },
      data: { deletedAt: new Date() },
    });

    return null;
  }

  /**
   * 批量更新状态
   */
  async batchUpdateStatus(
    adminUserId: string,
    dto: BatchUpdateStatusDto,
  ): Promise<BatchUpdateResultDto> {
    if (dto.ids.length > 100) {
      throw new FeedbackBatchLimitExceededException(100);
    }

    const results: BatchUpdateResultDto = {
      total: dto.ids.length,
      updated: 0,
      failed: 0,
      failures: [],
    };

    // 获取所有反馈
    const feedbacks = await this.prisma.feedback.findMany({
      where: {
        id: { in: dto.ids },
        deletedAt: null,
      },
      select: {
        id: true,
        status: true,
        region: true,
      },
    });

    const feedbackMap = new Map(feedbacks.map((f) => [f.id, f]));

    // 获取管理员区域权限
    const adminRegions = await this.getAdminRegions(adminUserId);
    const isGlobalAdmin = adminRegions === null;

    for (const id of dto.ids) {
      const feedback = feedbackMap.get(id);

      if (!feedback) {
        results.failed++;
        results.failures.push({ id, reason: 'FEEDBACK_NOT_FOUND' });
        continue;
      }

      // 检查区域权限
      if (!isGlobalAdmin && !adminRegions?.includes(feedback.region)) {
        results.failed++;
        results.failures.push({ id, reason: 'FEEDBACK_ACCESS_DENIED' });
        continue;
      }

      // 验证状态转换
      const allowedTransitions =
        STATUS_TRANSITIONS[feedback.status as FeedbackStatus];
      if (!allowedTransitions?.includes(dto.status)) {
        results.failed++;
        results.failures.push({
          id,
          reason: 'FEEDBACK_INVALID_STATUS_TRANSITION',
        });
        continue;
      }

      try {
        const updateData: Prisma.FeedbackUpdateInput = {
          status: dto.status,
        };

        if (dto.status === FeedbackStatus.RESOLVED) {
          updateData.resolvedAt = new Date();
        } else if (feedback.status === FeedbackStatus.RESOLVED) {
          updateData.resolvedAt = null;
        }

        await this.prisma.feedback.update({
          where: { id },
          data: updateData,
        });
        results.updated++;
      } catch (error) {
        this.logger.error(`Failed to update feedback ${id}:`, error);
        results.failed++;
        results.failures.push({ id, reason: 'INTERNAL_ERROR' });
      }
    }

    return results;
  }

  // ==========================================================================
  // Stats API
  // ==========================================================================

  /**
   * 获取反馈统计
   */
  async getStats(adminUserId: string, query: FeedbackStatsQueryDto) {
    const { region, startDate, endDate } = query;

    // 获取管理员区域权限
    const regionFilter = await this.getRegionFilter(adminUserId, region);
    const adminRegions = await this.getAdminRegions(adminUserId);
    const isGlobalAdmin = adminRegions === null;

    const baseWhere: Prisma.FeedbackWhereInput = {
      deletedAt: null,
      ...regionFilter,
      ...(startDate && {
        createdAt: {
          gte: new Date(startDate),
          ...(endDate && { lte: new Date(endDate) }),
        },
      }),
    };

    // 并行获取各类统计
    const now = new Date();
    const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
    const weekStart = new Date(todayStart);
    weekStart.setDate(weekStart.getDate() - weekStart.getDay());
    const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);

    const [
      total,
      byStatus,
      byType,
      byPriority,
      byRegion,
      todayNew,
      thisWeekNew,
      thisMonthNew,
      resolvedFeedbacks,
    ] = await Promise.all([
      // 总数
      this.prisma.feedback.count({ where: baseWhere }),
      
      // 按状态统计
      this.prisma.feedback.groupBy({
        by: ['status'],
        where: baseWhere,
        _count: true,
      }),
      
      // 按类型统计
      this.prisma.feedback.groupBy({
        by: ['type'],
        where: baseWhere,
        _count: true,
      }),
      
      // 按优先级统计
      this.prisma.feedback.groupBy({
        by: ['priority'],
        where: baseWhere,
        _count: true,
      }),
      
      // 按区域统计（仅全局管理员）
      isGlobalAdmin
        ? this.prisma.feedback.groupBy({
            by: ['region'],
            where: baseWhere,
            _count: true,
          })
        : Promise.resolve([]),
      
      // 今日新增
      this.prisma.feedback.count({
        where: {
          ...baseWhere,
          createdAt: { gte: todayStart },
        },
      }),
      
      // 本周新增
      this.prisma.feedback.count({
        where: {
          ...baseWhere,
          createdAt: { gte: weekStart },
        },
      }),
      
      // 本月新增
      this.prisma.feedback.count({
        where: {
          ...baseWhere,
          createdAt: { gte: monthStart },
        },
      }),
      
      // 已解决的反馈（用于计算平均解决时间）
      this.prisma.feedback.findMany({
        where: {
          ...baseWhere,
          status: FeedbackStatus.RESOLVED,
          resolvedAt: { not: null },
        },
        select: {
          createdAt: true,
          resolvedAt: true,
        },
        take: 1000, // 最多取 1000 条计算平均值
      }),
    ]);

    // 计算平均解决时间（小时）
    let avgResolutionTime = 0;
    if (resolvedFeedbacks.length > 0) {
      const totalTime = resolvedFeedbacks.reduce((sum, f) => {
        if (f.resolvedAt) {
          return sum + (f.resolvedAt.getTime() - f.createdAt.getTime());
        }
        return sum;
      }, 0);
      avgResolutionTime = Number(
        (totalTime / resolvedFeedbacks.length / (1000 * 60 * 60)).toFixed(1),
      );
    }

    // 格式化结果
    const formatGroupBy = <T extends string>(
      data: Array<{ _count: number } & Record<string, any>>,
      key: string,
      defaultKeys: T[],
    ): Record<T | string, number> => {
      const result: Record<string, number> = {};
      defaultKeys.forEach((k) => (result[k] = 0));
      data.forEach((item) => {
        const keyValue = item[key] || 'UNSET';
        result[keyValue] = item._count;
      });
      return result;
    };

    return {
      total,
      byStatus: formatGroupBy(byStatus, 'status', Object.values(FeedbackStatus)),
      byType: formatGroupBy(byType, 'type', Object.values(FeedbackType)),
      byPriority: {
        ...formatGroupBy(byPriority, 'priority', Object.values(FeedbackPriority)),
        UNSET: byPriority.find((p) => p.priority === null)?._count || 0,
      },
      ...(isGlobalAdmin && {
        byRegion: formatGroupBy(byRegion, 'region', ['CN', 'US', 'EU', 'APAC']),
      }),
      avgResolutionTime,
      todayNew,
      thisWeekNew,
      thisMonthNew,
    };
  }

  // ==========================================================================
  // Private Helper Methods
  // ==========================================================================

  /**
   * 验证状态转换是否合法
   */
  private validateStatusTransition(
    currentStatus: FeedbackStatus,
    newStatus: FeedbackStatus,
  ): void {
    const allowedTransitions = STATUS_TRANSITIONS[currentStatus];
    if (!allowedTransitions?.includes(newStatus)) {
      throw new FeedbackInvalidStatusTransitionException(
        currentStatus,
        newStatus,
      );
    }
  }

  /**
   * 获取管理员的区域列表
   * 返回 null 表示全局管理员（可以管理所有区域）
   */
  private async getAdminRegions(userId: string): Promise<string[] | null> {
    const userWithRoles = await this.prisma.user.findUnique({
      where: { id: userId },
      include: {
        roles: {
          include: {
            role: true,
          },
        },
      },
    });

    if (!userWithRoles) {
      return [];
    }

    const roleCodes = userWithRoles.roles.map((ur) =>
      ur.role.code.toUpperCase(),
    );

    // 检查是否是全局管理员
    if (
      roleCodes.some((code) =>
        GLOBAL_ADMIN_ROLES.map((r) => r.toUpperCase()).includes(code),
      )
    ) {
      return null; // 全局管理员
    }

    // 提取区域管理员角色对应的区域
    const regions: string[] = [];
    roleCodes.forEach((code) => {
      if (code.startsWith(REGION_ADMIN_ROLE_PREFIX)) {
        const region = code.substring(REGION_ADMIN_ROLE_PREFIX.length);
        if (region) {
          regions.push(region);
        }
      }
    });

    return regions;
  }

  /**
   * 获取区域过滤条件
   */
  private async getRegionFilter(
    userId: string,
    requestedRegion?: string,
  ): Promise<Prisma.FeedbackWhereInput> {
    const adminRegions = await this.getAdminRegions(userId);

    // 全局管理员
    if (adminRegions === null) {
      return requestedRegion ? { region: requestedRegion } : {};
    }

    // 区域管理员
    if (adminRegions.length === 0) {
      // 没有任何区域权限，返回空结果
      return { region: { in: [] } };
    }

    // 如果请求了特定区域，验证权限
    if (requestedRegion) {
      if (!adminRegions.includes(requestedRegion)) {
        throw new FeedbackAccessDeniedException(
          `无权访问区域 ${requestedRegion} 的反馈`,
        );
      }
      return { region: requestedRegion };
    }

    // 返回管理员有权限的区域
    return { region: { in: adminRegions } };
  }

  /**
   * 检查区域访问权限
   */
  private async checkRegionAccess(
    userId: string,
    feedbackRegion: string,
  ): Promise<void> {
    const adminRegions = await this.getAdminRegions(userId);

    // 全局管理员
    if (adminRegions === null) {
      return;
    }

    // 区域管理员
    if (!adminRegions.includes(feedbackRegion)) {
      throw new FeedbackAccessDeniedException(
        `该反馈属于区域 ${feedbackRegion}，您无权操作`,
      );
    }
  }

  /**
   * 用户端反馈 include 配置
   */
  private getUserFeedbackInclude() {
    return {
      user: {
        select: {
          id: true,
          displayName: true,
        },
      },
    };
  }

  /**
   * 管理端反馈 include 配置
   */
  private getAdminFeedbackInclude() {
    return {
      user: {
        select: {
          id: true,
          displayName: true,
          email: true,
          departmentMemberships: {
            orderBy: { isPrimary: Prisma.SortOrder.desc },
            take: 1,
            select: {
              department: {
                select: {
                  id: true,
                  name: true,
                },
              },
            },
          },
        },
      },
      assignee: {
        select: {
          id: true,
          displayName: true,
          email: true,
        },
      },
    };
  }

  /**
   * 格式化用户端反馈响应（隐藏 adminNote 等字段）
   */
  private formatUserFeedback(feedback: any) {
    return {
      id: feedback.id,
      type: feedback.type,
      title: feedback.title,
      content: feedback.content,
      attachments: feedback.attachments,
      status: feedback.status,
      priority: feedback.priority,
      adminReply: feedback.adminReply, // 用户可以看到管理员回复
      createdAt: feedback.createdAt,
      updatedAt: feedback.updatedAt,
    };
  }

  /**
   * 格式化管理端反馈响应
   */
  private formatAdminFeedback(feedback: any) {
    const primaryDepartment =
      feedback.user?.departmentMemberships?.[0]?.department || null;

    return {
      id: feedback.id,
      type: feedback.type,
      title: feedback.title,
      content: feedback.content,
      attachments: feedback.attachments,
      pageUrl: feedback.pageUrl,
      userAgent: feedback.userAgent,
      status: feedback.status,
      priority: feedback.priority,
      adminNote: feedback.adminNote,
      adminReply: feedback.adminReply,
      assignee: feedback.assignee
        ? {
            id: feedback.assignee.id,
            displayName: feedback.assignee.displayName,
            email: feedback.assignee.email,
          }
        : null,
      resolvedAt: feedback.resolvedAt,
      user: {
        id: feedback.user.id,
        displayName: feedback.user.displayName,
        email: feedback.user.email,
        department: primaryDepartment,
      },
      region: feedback.region,
      createdAt: feedback.createdAt,
      updatedAt: feedback.updatedAt,
    };
  }
}
