package mf_callback_ticket

import (
	"fmt"
	"time"

	"be.ems/lib/dborm"
	"gorm.io/gorm"
)

type CallbackTicketService struct {
	db *gorm.DB
}

// 构造函数示例
func NewCallbackTicketService() *CallbackTicketService {
	db := dborm.DefaultDB()
	return &CallbackTicketService{db: db}
}

// SelectCallbackTicket 根据条件分页查询回调工单
func (s *CallbackTicketService) SelectCallbackTicket(query CallbackTicketQuery) ([]CallbackTicket, int, error) {
	var tickets []CallbackTicket
	var total int64

	db := s.db.Table("mf_callback_ticket")

	if query.CallerNumber != "" {
		db = db.Where("caller_number = ?", query.CallerNumber)
	}
	if query.AgentName != "" {
		db = db.Where("agent_name = ?", query.AgentName)
	}
	if query.Status != "" {
		db = db.Where("status = ?", query.Status)
	}
	if query.StartTime != "" && query.EndTime != "" {
		db = db.Where("created_at BETWEEN ? AND ?", query.StartTime, query.EndTime)
	} else if query.StartTime != "" {
		db = db.Where("created_at >= ?", query.StartTime)
	} else if query.EndTime != "" {
		db = db.Where("created_at <= ?", query.EndTime)
	}

	// 统计总数
	if err := db.Count(&total).Error; err != nil {
		return nil, 0, fmt.Errorf("failed to count callback tickets: %w", err)
	}

	// 分页查询
	offset := (query.PageNum - 1) * query.PageSize
	if err := db.Limit(query.PageSize).Offset(offset).Order("created_at desc").Find(&tickets).Error; err != nil {
		return nil, 0, fmt.Errorf("failed to select callback tickets: %w", err)
	}

	return tickets, int(total), nil
}

// SelectCallbackTicketByPage 分页查询回调工单
// @Description 分页查询回调工单
// @param page 页码
// @param pageSize 每页大小
// @return []MfCallbackTicket 回调工单列表
// @return int 总记录数
// @return error 错误信息
// @example
// mfCallbackTicketService.SelectCallbackTicketByPage(1, 10)
func (s *CallbackTicketService) SelectCallbackTicketByPage(pageNum int, pageSize int) ([]CallbackTicket, int, error) {
	var tickets []CallbackTicket
	var total int64

	// 统计总数
	if err := s.db.Table("mf_callback_ticket").Count(&total).Error; err != nil {
		return nil, 0, fmt.Errorf("failed to count callback tickets: %w", err)
	}

	// 分页查询
	offset := (pageNum - 1) * pageSize
	if err := s.db.Table("mf_callback_ticket").
		Limit(pageSize).
		Offset(offset).
		Find(&tickets).Error; err != nil {
		return nil, 0, fmt.Errorf("failed to select callback tickets: %w", err)
	}

	return tickets, int(total), nil
}

func (s *CallbackTicketService) InsertCallbackTicket(ticket CallbackTicket) error {
	// 判断主叫号码是否已存在未处理完的工单
	var existingCount int64
	if err := s.db.Table("mf_callback_ticket").
		Where("caller_number = ? AND status IN ('NEW', 'PENDING', 'IN_PROGRESS')", ticket.CallerNumber).
		Count(&existingCount).Error; err != nil {
		return fmt.Errorf("failed to check existing tickets: %w", err)
	}
	// 如果存在未处理完的工单，返回错误
	if existingCount > 0 {
		return fmt.Errorf("caller %s already has a pending ticket", ticket.CallerNumber)
	}
	// 这里可以使用ORM或其他方式将ticket插入到数据库中
	if err := s.db.Table("mf_callback_ticket").Create(&ticket).Error; err != nil {
		return fmt.Errorf("failed to insert callback ticket: %w", err)
	}
	return nil
}

// SelectCallbackTicketById 根据工单ID查询回调工单
// @Description 根据工单ID查询回调工单
// @param ticketId 工单ID
// @return *CallbackTicket 回调工单对象
// @return error 错误信息
// @example
// mfCallbackTicketService.SelectCallbackTicketById(12345)
func (s *CallbackTicketService) SelectCallbackTicketById(ticketId int64) (*CallbackTicket, error) {
	var ticket CallbackTicket
	if err := s.db.Table("mf_callback_ticket").
		Where("ticket_id = ?", ticketId).
		First(&ticket).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, fmt.Errorf("callback ticket with ID %d not found", ticketId)
		}
		return nil, fmt.Errorf("failed to select callback ticket: %w", err)
	}
	return &ticket, nil
}

// UpdateCallbackTicket 更新回调工单
// @Description 更新回调工单
// @param ticket 回调工单对象
// @return error 错误信息
// @example
// mfCallbackTicketService.UpdateCallbackTicket(ticket)
func (s *CallbackTicketService) UpdateCallbackTicket(ticket CallbackTicket) error {
	if err := s.db.Table("mf_callback_ticket").
		Where("ticket_id = ?", ticket.TicketId).
		Updates(ticket).Error; err != nil {
		return fmt.Errorf("failed to update callback ticket: %w", err)
	}
	return nil
}

// DeleteCallbackTicket 删除回调工单
// @Description 删除回调工单
// @param ticketId 工单ID
// @return error 错误信息
// @example
// mfCallbackTicketService.DeleteCallbackTicket(12345)
func (s *CallbackTicketService) DeleteCallbackTicket(ticketId int64) error {
	if err := s.db.Table("mf_callback_ticket").
		Where("ticket_id = ?", ticketId).
		Delete(&CallbackTicket{}).Error; err != nil {
		return fmt.Errorf("failed to delete callback ticket: %w", err)
	}
	return nil
}

// GetLastAssignedAgent 获取最近一个分配的座席名称
// @Description 获取最近分配工单的座席名称
// @return string 座席名称
// @return error 错误信息
func (s *CallbackTicketService) GetLastAssignedAgent() (string, error) {
	var lastTicket CallbackTicket
	if err := s.db.Table("mf_callback_ticket").
		Where("agent_name <> ''").
		Order("created_at DESC").
		First(&lastTicket).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			// 没有记录属于正常情况，返回空字符串
			return "", nil
		}
		return "", fmt.Errorf("failed to query last ticket: %w", err)
	}

	return lastTicket.AgentName, nil
}

// SelectNextAgent 根据上一个座席和座席列表选择下一个座席
// @Description 选择下一个要分配的座席
// @param agents 座席列表
// @param lastAgentName 上一个座席名称
// @return string 下一个座席名称
func (s *CallbackTicketService) SelectNextAgent(agents []AgentInfo, lastAgentName string) string {
	if len(agents) == 0 {
		return ""
	}

	// 默认选第一个座席
	selectedAgent := agents[0].Name

	// 如果没有上一个座席，直接返回第一个
	if lastAgentName == "" {
		return selectedAgent
	}

	// 找到上一个座席的下一个
	foundLastAgent := false
	for i, agent := range agents {
		if foundLastAgent {
			// 找到上一个座席的下一个
			return agent.Name
		}
		if agent.Name == lastAgentName {
			foundLastAgent = true
			// 如果是最后一个座席，则循环回第一个
			if i == len(agents)-1 {
				return agents[0].Name
			}
		}
	}

	// 如果没找到上一个座席(可能被删除了)，使用第一个座席
	return selectedAgent
}

// FindCallbackTicketByAgentAndCaller 通过座席号码和主叫号码查找符合条件的工单
// @Description 通过座席号码和主叫号码查找符合条件的工单
// @param agentName 座席号码
// @param callerNumber 主叫号码
// @return *CallbackTicket 回调工单对象
// @return error 错误信息
func (s *CallbackTicketService) FindCallbackTicketByAgentAndCaller(agentName string, callerNumber string) (*CallbackTicket, error) {
	var ticket CallbackTicket

	if err := s.db.Table("mf_callback_ticket").
		Where("agent_name = ? AND caller_number = ? AND status IN ('NEW', 'PENDING', 'IN_PROGRESS', 'NO_ANSWER_1', 'NO_ANSWER_2')",
			agentName, callerNumber).
		Order("created_at DESC").
		First(&ticket).Error; err != nil {
		if err == gorm.ErrRecordNotFound {
			return nil, nil // 没有找到记录，返回nil, nil
		}
		return nil, fmt.Errorf("failed to find callback ticket: %w", err)
	}

	return &ticket, nil
}

// ProcessCallbackResult 处理回拨结果并更新工单
// @Description 处理回拨结果并更新工单状态
// @param ticket 要更新的工单
// @param callDuration 通话时长
// @param answerTime 应答时间
// @param releaseTime 释放时间
// @param cause 释放原因
// @return error 错误信息
func (s *CallbackTicketService) ProcessCallbackResult(ticket *CallbackTicket, callDuration float64, answerTime string, releaseTime string, cause string) error {
	if ticket == nil {
		return fmt.Errorf("ticket cannot be nil")
	}

	// 构建更新信息
	now := time.Now().UnixMicro()
	updatedTicket := CallbackTicket{
		TicketId:  ticket.TicketId,
		UpdatedAt: &now,
	}

	// 构建评论内容
	comment := fmt.Sprintf("回拨时间: %s, 释放时间: %s, 原因: %s", answerTime, releaseTime, cause)

	// 根据通话时长判断处理结果
	if callDuration > 0 {
		// 通话已接通，标记为已处理完毕
		updatedTicket.Status = TicketStatusClosed.Enum()
		updatedTicket.Comment = fmt.Sprintf("%s, 通话时长: %.1f秒, 状态: 已接通并完成", comment, callDuration)
	} else {
		// 通话未接通，根据当前状态修改为相应状态
		switch ticket.Status {
		case TicketStatusNew.Enum(), TicketStatusInProgress.Enum():
			// 第一次未接通
			updatedTicket.Status = TicketStatusNoAnswer1.Enum()
			updatedTicket.Comment = fmt.Sprintf("%s, 通话时长: %.1f秒, 状态: 第一次未接通", comment, callDuration)
		case TicketStatusNoAnswer1.Enum():
			// 第二次未接通
			updatedTicket.Status = TicketStatusNoAnswer2.Enum()
			updatedTicket.Comment = fmt.Sprintf("%s, 通话时长: %.1f秒, 状态: 第二次未接通", comment, callDuration)
		case TicketStatusNoAnswer2.Enum():
			// 第三次未接通，挂起
			updatedTicket.Status = TicketStatusPending.Enum()
			updatedTicket.Comment = fmt.Sprintf("%s, 通话时长: %.1f秒, 状态: 多次未接通，工单挂起", comment, callDuration)
		default:
			// 其他状态保持不变
			updatedTicket.Status = ticket.Status
			updatedTicket.Comment = fmt.Sprintf("%s, 通话时长: %.1f秒, 状态: 未知状态", comment, callDuration)
		}
	}

	// 更新工单
	if err := s.db.Table("mf_callback_ticket").
		Where("ticket_id = ?", ticket.TicketId).
		Updates(updatedTicket).Error; err != nil {
		return fmt.Errorf("failed to update callback ticket: %w", err)
	}

	return nil
}

// FindTimeoutTickets 查询指定状态的超时工单
// @Description 查询指定状态且超过指定时间未处理的工单
// @param status 工单状态
// @param timeoutMicros 超时时间(微秒)
// @return []CallbackTicket 超时工单列表
// @return error 错误信息
func (s *CallbackTicketService) FindTimeoutTickets(status string, timeoutMicros int64) ([]CallbackTicket, error) {
	// 计算超时时间点
	nowMicros := time.Now().UnixMicro()
	timeoutBeforeMicros := nowMicros - timeoutMicros

	// 查询超时的工单
	var tickets []CallbackTicket
	if err := s.db.Table("mf_callback_ticket").
		Where("status = ? AND created_at < ? AND (updated_at IS NULL OR updated_at < ?)",
			status, timeoutBeforeMicros, timeoutBeforeMicros).
		Find(&tickets).Error; err != nil {
		return nil, fmt.Errorf("查询超时工单失败: %w", err)
	}

	return tickets, nil
}

// UpdateTicketToTimeout 将工单状态更新为超时
// @Description 将指定工单更新为超时状态，并添加备注信息
// @param ticket 要更新的工单
// @param originalStatus 原工单状态
// @return error 错误信息
func (s *CallbackTicketService) UpdateTicketToTimeout(ticket *CallbackTicket, originalStatus string, agents []AgentInfo) error {
	if ticket == nil {
		return fmt.Errorf("ticket cannot be nil")
	}

	now := time.Now().UnixMicro()
	// 1. 更新原工单为超时
	updatedTicket := CallbackTicket{
		TicketId:  ticket.TicketId,
		Status:    TicketStatusTimeout.Enum(),
		Comment:   fmt.Sprintf("%s - 工单状态为 %s 处理超时，系统自动更新为超时状态", ticket.Comment, originalStatus),
		UpdatedAt: &now,
	}
	if err := s.db.Table("mf_callback_ticket").
		Where("ticket_id = ?", ticket.TicketId).
		Updates(updatedTicket).Error; err != nil {
		return fmt.Errorf("更新工单 %d 状态失败: %w", ticket.TicketId, err)
	}

	// 2. 选择新座席
	lastAgent := ticket.AgentName
	newAgent := s.SelectNextAgent(agents, lastAgent)

	// 3. 创建新工单
	newTicket := CallbackTicket{
		CallerNumber: ticket.CallerNumber,
		CalleeNumber: ticket.CalleeNumber,
		Status:       TicketStatusNew.Enum(),
		AgentName:    newAgent,
		Comment:      fmt.Sprintf("由超时工单 %d 自动重建", ticket.TicketId),
		MsdData:      ticket.MsdData,
		RmUid:        ticket.RmUid,
		CreatedAt:    now,
		UpdatedAt:    nil,
	}
	if err := s.db.Table("mf_callback_ticket").Create(&newTicket).Error; err != nil {
		return fmt.Errorf("创建新工单失败: %w", err)
	}

	return nil
}
