import { Injectable, Logger } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { Prisma } from '@prisma/client';
import {
  CreateTicketDto,
  UpdateTicketDto,
  UpdateTicketStatusDto,
  AssignTicketDto,
  QueryTicketDto,
  CreateCommentDto,
  QueryCommentDto,
  CreateSatisfactionDto,
  QueryActivityDto,
  TicketStatus,
  CommentType,
  VisibilityScope,
} from './dto';
import {
  PaginatedResponse,
  TicketDetailResponse,
  TicketListItemResponse,
  CommentResponse,
  ActivityResponse,
  isValidStatusTransition,
} from './entities';
import {
  TicketNotFoundException,
  TicketAccessDeniedException,
  TicketInvalidStatusTransitionException,
  TicketCategoryNotFoundException,
  TicketCategoryInactiveException,
  TicketAttachmentLimitExceededException,
  TicketCommentNotFoundException,
  TicketNotResolvedForRatingException,
  TicketAlreadyRatedException,
  TicketRatingNotCreatorException,
} from './exceptions';
import { CategoryService } from './services/category.service';
import { AssignService } from './services/assign.service';

@Injectable()
export class TicketsService {
  private readonly logger = new Logger(TicketsService.name);
  private ticketCounter: Map<string, number> = new Map(); // 简单的内存计数器，生产环境应使用 Redis

  constructor(
    private readonly prisma: PrismaService,
    private readonly categoryService: CategoryService,
    private readonly assignService: AssignService,
  ) {}

  // ==================== 工单编号生成 ====================

  /**
   * 生成工单编号
   * 格式: TK-{YYYYMMDD}-{序号}
   * 
   * 生产环境应使用 Redis 计数器保证唯一性
   */
  private async generateTicketNo(): Promise<string> {
    const today = new Date();
    const dateStr = today.toISOString().slice(0, 10).replace(/-/g, '');
    const key = `ticket:${dateStr}`;

    // 从数据库获取当日最大序号
    const lastTicket = await this.prisma.ticket.findFirst({
      where: {
        ticketNo: {
          startsWith: `TK-${dateStr}-`,
        },
      },
      orderBy: {
        ticketNo: 'desc',
      },
      select: {
        ticketNo: true,
      },
    });

    let counter = 0;
    if (lastTicket) {
      // 解析现有最大序号
      const parts = lastTicket.ticketNo.split('-');
      if (parts.length === 3) {
        counter = parseInt(parts[2], 10) || 0;
      }
    }

    counter += 1;
    const seq = counter.toString().padStart(4, '0');
    return `TK-${dateStr}-${seq}`;
  }

  // ==================== 工单 CRUD ====================

  /**
   * 创建工单
   */
  async create(
    createTicketDto: CreateTicketDto,
    creatorId: string,
    region: string = 'CN',
    tenantId?: string,
  ) {
    const { categoryId, attachments, ...ticketData } = createTicketDto;

    // 验证分类
    const category = await this.categoryService.findOne(categoryId);
    if (!category) {
      throw new TicketCategoryNotFoundException(categoryId);
    }
    if (!category.isActive) {
      throw new TicketCategoryInactiveException();
    }

    // 验证附件数量
    if (attachments && attachments.length > 10) {
      throw new TicketAttachmentLimitExceededException(10);
    }

    // 生成工单编号
    const ticketNo = await this.generateTicketNo();

    // 获取默认优先级
    const priority = ticketData.priority || category.defaultPriority;

    // 获取默认处理组
    const assigneeGroupId = category.defaultAssigneeGroupId;

    // 获取 SLA
    const slaId = category.slaId;

    // 创建工单
    const ticket = await this.prisma.ticket.create({
      data: {
        ticketNo,
        title: ticketData.title,
        description: ticketData.description,
        categoryId,
        priority,
        tags: ticketData.tags || [],
        status: 'OPEN',
        creatorId,
        assigneeGroupId,
        slaId,
        source: ticketData.source || 'WEB',
        channelMetadata: ticketData.channelMetadata || Prisma.JsonNull,
        language: ticketData.language,
        region,
        tenantId,
        // 创建附件
        attachments: attachments
          ? {
              create: attachments.map((att) => ({
                fileName: att.fileName,
                fileUrl: att.fileUrl,
                fileSize: att.fileSize,
                mimeType: att.mimeType,
                uploadedBy: creatorId,
              })),
            }
          : undefined,
      },
      include: {
        category: true,
        attachments: true,
      },
    });

    // 记录活动日志
    await this.createActivity(ticket.id, 'CREATED', {}, creatorId);

    // 自动分配（如果配置了默认处理组）
    if (assigneeGroupId) {
      await this.assignService.autoAssign(ticket.id, assigneeGroupId);
    }

    this.logger.log(`工单创建成功: ${ticketNo}`);

    return this.formatTicketDetail(ticket);
  }

  /**
   * 获取工单列表
   */
  async findAll(
    query: QueryTicketDto,
    userId: string,
    userGroupIds: string[] = [],
    isAdmin: boolean = false,
  ): Promise<PaginatedResponse<TicketListItemResponse>> {
    const {
      page = 1,
      limit = 20,
      status,
      statuses,
      priority,
      categoryId,
      assigneeId,
      creatorId,
      keyword,
      startDate,
      endDate,
      slaBreached,
      view,
      sortBy = 'createdAt',
      sortOrder = 'desc',
    } = query;

    // 构建查询条件
    const where: Prisma.TicketWhereInput = {
      deletedAt: null,
    };

    // 视图过滤
    if (view === 'my_created') {
      where.creatorId = userId;
    } else if (view === 'my_assigned') {
      where.assigneeId = userId;
    } else if (view === 'my_group') {
      where.assigneeGroupId = { in: userGroupIds };
    } else if (!isAdmin) {
      // 非管理员只能看自己创建的、分配给自己的、或自己组内的工单
      where.OR = [
        { creatorId: userId },
        { assigneeId: userId },
        { assigneeGroupId: { in: userGroupIds } },
        { watcherIds: { has: userId } },
      ];
    }

    // 状态筛选
    if (status) {
      where.status = status;
    } else if (statuses && statuses.length > 0) {
      where.status = { in: statuses };
    }

    // 优先级筛选
    if (priority) {
      where.priority = priority;
    }

    // 分类筛选
    if (categoryId) {
      where.categoryId = categoryId;
    }

    // 处理人筛选
    if (assigneeId) {
      where.assigneeId = assigneeId;
    }

    // 创建人筛选
    if (creatorId) {
      where.creatorId = creatorId;
    }

    // 关键词搜索
    if (keyword) {
      where.OR = [
        { title: { contains: keyword, mode: 'insensitive' } },
        { ticketNo: { contains: keyword, mode: 'insensitive' } },
      ];
    }

    // 时间范围筛选
    if (startDate || endDate) {
      where.createdAt = {};
      if (startDate) {
        where.createdAt.gte = new Date(startDate);
      }
      if (endDate) {
        where.createdAt.lte = new Date(endDate);
      }
    }

    // SLA 超时筛选
    if (slaBreached !== undefined) {
      where.slaBreached = slaBreached;
    }

    // 排序
    const orderBy: Prisma.TicketOrderByWithRelationInput = {
      [sortBy]: sortOrder,
    };

    // 查询总数
    const total = await this.prisma.ticket.count({ where });

    // 查询数据
    const tickets = await this.prisma.ticket.findMany({
      where,
      orderBy,
      skip: (page - 1) * limit,
      take: limit,
      include: {
        category: {
          select: { id: true, name: true, code: true },
        },
      },
    });

    const totalPages = Math.ceil(total / limit);

    return {
      items: tickets.map((ticket) => this.formatTicketListItem(ticket)),
      total,
      page,
      limit,
      totalPages,
      hasNext: page < totalPages,
      hasPrev: page > 1,
    };
  }

  /**
   * 获取工单详情
   */
  async findOne(
    id: string,
    userId: string,
    userGroupIds: string[] = [],
    isAdmin: boolean = false,
  ): Promise<TicketDetailResponse> {
    const ticket = await this.prisma.ticket.findFirst({
      where: {
        id,
        deletedAt: null,
      },
      include: {
        category: true,
        attachments: true,
        sla: true,
      },
    });

    if (!ticket) {
      throw new TicketNotFoundException(id);
    }

    // 权限检查
    if (!isAdmin) {
      const hasAccess =
        ticket.creatorId === userId ||
        ticket.assigneeId === userId ||
        (ticket.assigneeGroupId && userGroupIds.includes(ticket.assigneeGroupId)) ||
        ticket.watcherIds.includes(userId);

      if (!hasAccess) {
        throw new TicketAccessDeniedException();
      }
    }

    return this.formatTicketDetail(ticket);
  }

  /**
   * 更新工单
   */
  async update(
    id: string,
    updateTicketDto: UpdateTicketDto,
    userId: string,
  ) {
    const ticket = await this.prisma.ticket.findFirst({
      where: { id, deletedAt: null },
    });

    if (!ticket) {
      throw new TicketNotFoundException(id);
    }

    // 验证分类（如果更新了分类）
    if (updateTicketDto.categoryId && updateTicketDto.categoryId !== ticket.categoryId) {
      const category = await this.categoryService.findOne(updateTicketDto.categoryId);
      if (!category || !category.isActive) {
        throw new TicketCategoryNotFoundException(updateTicketDto.categoryId);
      }
    }

    const updatedTicket = await this.prisma.ticket.update({
      where: { id },
      data: updateTicketDto,
      include: {
        category: true,
        attachments: true,
      },
    });

    // 记录优先级变更
    if (updateTicketDto.priority && updateTicketDto.priority !== ticket.priority) {
      await this.createActivity(id, 'PRIORITY_CHANGED', {
        oldPriority: ticket.priority,
        newPriority: updateTicketDto.priority,
      }, userId);
    }

    return this.formatTicketDetail(updatedTicket);
  }

  /**
   * 更新工单状态
   */
  async updateStatus(
    id: string,
    updateStatusDto: UpdateTicketStatusDto,
    userId: string,
  ) {
    const ticket = await this.prisma.ticket.findFirst({
      where: { id, deletedAt: null },
    });

    if (!ticket) {
      throw new TicketNotFoundException(id);
    }

    const { status: newStatus, comment, resolution } = updateStatusDto;
    const oldStatus = ticket.status as TicketStatus;

    // 验证状态转换是否合法
    if (!isValidStatusTransition(oldStatus, newStatus)) {
      throw new TicketInvalidStatusTransitionException(oldStatus, newStatus);
    }

    // 构建更新数据
    const updateData: Prisma.TicketUpdateInput = {
      status: newStatus,
    };

    // 特殊状态处理
    if (newStatus === TicketStatus.IN_PROGRESS && !ticket.firstResponseAt) {
      updateData.firstResponseAt = new Date();
    }

    if (newStatus === TicketStatus.RESOLVED) {
      updateData.resolvedAt = new Date();
      if (resolution) {
        updateData.resolution = resolution;
      }
    }

    if (newStatus === TicketStatus.CLOSED) {
      updateData.closedAt = new Date();
    }

    if (newStatus === TicketStatus.PENDING) {
      updateData.slaPausedAt = new Date();
    }

    // 从 PENDING 恢复时，计算暂停时长
    if (oldStatus === TicketStatus.PENDING && ticket.slaPausedAt) {
      const pausedDuration = Math.floor(
        (Date.now() - ticket.slaPausedAt.getTime()) / 1000
      );
      updateData.slaPausedDuration = ticket.slaPausedDuration + pausedDuration;
      updateData.slaPausedAt = null;
    }

    const updatedTicket = await this.prisma.ticket.update({
      where: { id },
      data: updateData,
      include: {
        category: true,
        attachments: true,
      },
    });

    // 记录活动日志
    await this.createActivity(id, 'STATUS_CHANGED', {
      oldStatus,
      newStatus,
    }, userId);

    // 添加状态变更评论
    if (comment) {
      await this.addComment(id, {
        content: comment,
        type: CommentType.STATUS_CHANGE,
      }, userId);
    }

    return this.formatTicketDetail(updatedTicket);
  }

  /**
   * 分配工单
   */
  async assign(
    id: string,
    assignDto: AssignTicketDto,
    userId: string,
  ) {
    const ticket = await this.prisma.ticket.findFirst({
      where: { id, deletedAt: null },
    });

    if (!ticket) {
      throw new TicketNotFoundException(id);
    }

    const oldAssigneeId = ticket.assigneeId;
    const oldAssigneeGroupId = ticket.assigneeGroupId;

    const updateData: any = {};

    if (assignDto.assigneeId !== undefined) {
      updateData.assigneeId = assignDto.assigneeId;
    }

    if (assignDto.assigneeGroupId !== undefined) {
      updateData.assigneeGroupId = assignDto.assigneeGroupId;
    }

    // 如果分配了处理人，更新状态为 ASSIGNED
    if (assignDto.assigneeId && ticket.status === 'OPEN') {
      updateData.status = 'ASSIGNED';
    }

    const updatedTicket = await this.prisma.ticket.update({
      where: { id },
      data: updateData,
      include: {
        category: true,
        attachments: true,
      },
    });

    // 记录活动日志
    const activityType = oldAssigneeId ? 'REASSIGNED' : 'ASSIGNED';
    await this.createActivity(id, activityType, {
      oldAssigneeId,
      newAssigneeId: assignDto.assigneeId,
      oldAssigneeGroupId,
      newAssigneeGroupId: assignDto.assigneeGroupId,
    }, userId);

    // 添加分配评论
    if (assignDto.comment) {
      await this.addComment(id, {
        content: assignDto.comment,
        type: CommentType.ASSIGNMENT,
      }, userId);
    }

    return this.formatTicketDetail(updatedTicket);
  }

  /**
   * 软删除工单
   */
  async remove(id: string, userId: string) {
    const ticket = await this.prisma.ticket.findFirst({
      where: { id, deletedAt: null },
    });

    if (!ticket) {
      throw new TicketNotFoundException(id);
    }

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

    this.logger.log(`工单删除成功: ${ticket.ticketNo}`);

    return { success: true };
  }

  // ==================== 评论管理 ====================

  /**
   * 获取工单评论列表
   */
  async getComments(
    ticketId: string,
    query: QueryCommentDto,
    userId: string,
    isAgent: boolean = false,
  ): Promise<PaginatedResponse<CommentResponse>> {
    const { page = 1, limit = 20 } = query;

    // 构建查询条件
    const where: Prisma.TicketCommentWhereInput = {
      ticketId,
      deletedAt: null,
    };

    // 非处理人不能看到内部评论
    if (!isAgent) {
      where.OR = [
        { isInternal: false, visibilityScope: 'ALL' },
        { authorId: userId },
      ];
    }

    const total = await this.prisma.ticketComment.count({ where });

    const comments = await this.prisma.ticketComment.findMany({
      where,
      orderBy: { createdAt: 'asc' },
      skip: (page - 1) * limit,
      take: limit,
      include: {
        attachments: true,
      },
    });

    const totalPages = Math.ceil(total / limit);

    return {
      items: comments.map((comment) => this.formatComment(comment)),
      total,
      page,
      limit,
      totalPages,
      hasNext: page < totalPages,
      hasPrev: page > 1,
    };
  }

  /**
   * 添加评论
   */
  async addComment(
    ticketId: string,
    createCommentDto: CreateCommentDto,
    userId: string,
  ): Promise<CommentResponse> {
    const ticket = await this.prisma.ticket.findFirst({
      where: { id: ticketId, deletedAt: null },
    });

    if (!ticket) {
      throw new TicketNotFoundException(ticketId);
    }

    const { attachments, ...commentData } = createCommentDto;

    const comment = await this.prisma.ticketComment.create({
      data: {
        ticketId,
        content: commentData.content,
        type: commentData.type || 'COMMENT',
        isInternal: commentData.isInternal || false,
        visibilityScope: commentData.visibilityScope || 'ALL',
        authorId: userId,
        mentionedUserIds: commentData.mentionedUserIds || [],
        attachments: attachments
          ? {
              create: attachments.map((att) => ({
                ticketId,
                fileName: att.fileName,
                fileUrl: att.fileUrl,
                fileSize: att.fileSize,
                mimeType: att.mimeType,
                uploadedBy: userId,
              })),
            }
          : undefined,
      },
      include: {
        attachments: true,
      },
    });

    // 记录活动日志
    await this.createActivity(ticketId, 'COMMENTED', {
      commentId: comment.id,
      isInternal: comment.isInternal,
    }, userId);

    return this.formatComment(comment);
  }

  /**
   * 删除评论
   */
  async deleteComment(
    ticketId: string,
    commentId: string,
    userId: string,
  ) {
    const comment = await this.prisma.ticketComment.findFirst({
      where: {
        id: commentId,
        ticketId,
        deletedAt: null,
      },
    });

    if (!comment) {
      throw new TicketCommentNotFoundException(commentId);
    }

    // 只能删除自己的评论
    if (comment.authorId !== userId) {
      throw new TicketAccessDeniedException();
    }

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

    return { success: true };
  }

  // ==================== 满意度评价 ====================

  /**
   * 提交满意度评价
   */
  async submitSatisfaction(
    ticketId: string,
    satisfactionDto: CreateSatisfactionDto,
    userId: string,
  ) {
    const ticket = await this.prisma.ticket.findFirst({
      where: { id: ticketId, deletedAt: null },
    });

    if (!ticket) {
      throw new TicketNotFoundException(ticketId);
    }

    // 只有创建人可以评价
    if (ticket.creatorId !== userId) {
      throw new TicketRatingNotCreatorException();
    }

    // 工单必须已解决或已关闭
    if (!['RESOLVED', 'CLOSED'].includes(ticket.status)) {
      throw new TicketNotResolvedForRatingException();
    }

    // 检查是否已评价
    if (ticket.satisfactionRating !== null) {
      throw new TicketAlreadyRatedException();
    }

    const updatedTicket = await this.prisma.ticket.update({
      where: { id: ticketId },
      data: {
        satisfactionRating: satisfactionDto.rating,
        satisfactionComment: satisfactionDto.comment,
        satisfactionRatedAt: new Date(),
      },
      include: {
        category: true,
        attachments: true,
      },
    });

    return this.formatTicketDetail(updatedTicket);
  }

  // ==================== 关注者管理 ====================

  /**
   * 添加关注者
   */
  async addWatcher(ticketId: string, watcherId: string, userId: string) {
    const ticket = await this.prisma.ticket.findFirst({
      where: { id: ticketId, deletedAt: null },
    });

    if (!ticket) {
      throw new TicketNotFoundException(ticketId);
    }

    if (ticket.watcherIds.includes(watcherId)) {
      return { success: true, message: '已关注' };
    }

    await this.prisma.ticket.update({
      where: { id: ticketId },
      data: {
        watcherIds: [...ticket.watcherIds, watcherId],
      },
    });

    return { success: true };
  }

  /**
   * 移除关注者
   */
  async removeWatcher(ticketId: string, watcherId: string, userId: string) {
    const ticket = await this.prisma.ticket.findFirst({
      where: { id: ticketId, deletedAt: null },
    });

    if (!ticket) {
      throw new TicketNotFoundException(ticketId);
    }

    await this.prisma.ticket.update({
      where: { id: ticketId },
      data: {
        watcherIds: ticket.watcherIds.filter((id) => id !== watcherId),
      },
    });

    return { success: true };
  }

  // ==================== 活动日志 ====================

  /**
   * 获取活动日志
   */
  async getActivities(
    ticketId: string,
    query: QueryActivityDto,
  ): Promise<PaginatedResponse<ActivityResponse>> {
    const { page = 1, limit = 50 } = query;

    const total = await this.prisma.ticketActivity.count({
      where: { ticketId },
    });

    const activities = await this.prisma.ticketActivity.findMany({
      where: { ticketId },
      orderBy: { createdAt: 'desc' },
      skip: (page - 1) * limit,
      take: limit,
    });

    const totalPages = Math.ceil(total / limit);

    return {
      items: activities.map((activity) => this.formatActivity(activity)),
      total,
      page,
      limit,
      totalPages,
      hasNext: page < totalPages,
      hasPrev: page > 1,
    };
  }

  /**
   * 创建活动日志
   */
  private async createActivity(
    ticketId: string,
    type: string,
    content: Record<string, any>,
    operatorId: string,
  ) {
    return this.prisma.ticketActivity.create({
      data: {
        ticketId,
        type: type as any,
        content,
        operatorId,
      },
    });
  }

  // ==================== 数据格式化 ====================

  private formatTicketDetail(ticket: any): TicketDetailResponse {
    return {
      id: ticket.id,
      ticketNo: ticket.ticketNo,
      title: ticket.title,
      description: ticket.description,
      category: {
        id: ticket.category.id,
        name: ticket.category.name,
        code: ticket.category.code,
      },
      priority: ticket.priority,
      status: ticket.status,
      creator: {
        id: ticket.creatorId,
        name: '', // TODO: 从用户服务获取
        email: '',
      },
      assignee: ticket.assigneeId
        ? {
            id: ticket.assigneeId,
            name: '', // TODO: 从用户服务获取
            email: '',
          }
        : null,
      assigneeGroup: ticket.assigneeGroupId
        ? {
            id: ticket.assigneeGroupId,
            name: '', // TODO: 从处理组服务获取
          }
        : null,
      watchers: [], // TODO: 从用户服务获取
      tags: ticket.tags,
      source: ticket.source,
      channelMetadata: ticket.channelMetadata,
      language: ticket.language,
      region: ticket.region,
      tenantId: ticket.tenantId,
      resolution: ticket.resolution,
      rootCause: ticket.rootCause,
      sla: ticket.sla
        ? {
            id: ticket.sla.id,
            name: ticket.sla.name,
            firstResponseDue: ticket.dueAt, // 简化处理
            resolutionDue: ticket.dueAt,
            firstResponseAt: ticket.firstResponseAt,
            isBreached: ticket.slaBreached,
            isPaused: ticket.slaPausedAt !== null,
          }
        : null,
      createdAt: ticket.createdAt,
      updatedAt: ticket.updatedAt,
      firstResponseAt: ticket.firstResponseAt,
      resolvedAt: ticket.resolvedAt,
      closedAt: ticket.closedAt,
      attachments: ticket.attachments?.map((att: any) => ({
        id: att.id,
        fileName: att.fileName,
        fileUrl: att.fileUrl,
        fileSize: att.fileSize,
        mimeType: att.mimeType,
        uploadedBy: att.uploadedBy,
        createdAt: att.createdAt,
      })) || [],
    };
  }

  private formatTicketListItem(ticket: any): TicketListItemResponse {
    return {
      id: ticket.id,
      ticketNo: ticket.ticketNo,
      title: ticket.title,
      priority: ticket.priority,
      status: ticket.status,
      category: {
        id: ticket.category.id,
        name: ticket.category.name,
        code: ticket.category.code,
      },
      creator: {
        id: ticket.creatorId,
        name: '', // TODO: 从用户服务获取
      },
      assignee: ticket.assigneeId
        ? {
            id: ticket.assigneeId,
            name: '', // TODO: 从用户服务获取
          }
        : null,
      createdAt: ticket.createdAt,
      updatedAt: ticket.updatedAt,
      dueAt: ticket.dueAt,
      slaBreached: ticket.slaBreached,
    };
  }

  private formatComment(comment: any): CommentResponse {
    return {
      id: comment.id,
      content: comment.content,
      type: comment.type,
      isInternal: comment.isInternal,
      visibilityScope: comment.visibilityScope,
      author: {
        id: comment.authorId,
        name: '', // TODO: 从用户服务获取
      },
      attachments: comment.attachments?.map((att: any) => ({
        id: att.id,
        fileName: att.fileName,
        fileUrl: att.fileUrl,
        fileSize: att.fileSize,
        mimeType: att.mimeType,
        uploadedBy: att.uploadedBy,
        createdAt: att.createdAt,
      })) || [],
      mentionedUsers: [], // TODO: 从用户服务获取
      createdAt: comment.createdAt,
    };
  }

  private formatActivity(activity: any): ActivityResponse {
    return {
      id: activity.id,
      type: activity.type,
      content: activity.content as Record<string, any>,
      operator: {
        id: activity.operatorId,
        name: '', // TODO: 从用户服务获取
      },
      createdAt: activity.createdAt,
    };
  }
}
