package chat

import (
	"context"
	"fmt"
	"gorm.io/gorm"
	"hfb_sys/backend/internal/model"
	"time"
)

func (r *Repository) TransferConversation(ctx context.Context, principal Principal, conversationID uint64, toAdminID uint64) error {
	return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		// 验证当前操作者是会话参与者
		if _, err := r.findParticipant(tx, principal, conversationID, false); err != nil {
			return err
		}
		// 验证目标客服存在、活跃且拥有客服角色，避免转接给超级管理员。
		if !adminIsSupport(tx, toAdminID) {
			return fmt.Errorf("目标客服不存在、已禁用或不是客服角色")
		}
		// 检查目标客服是否已有该会话
		var count int64
		if err := tx.Model(&model.ChatParticipant{}).
			Where("conversation_id = ? AND participant_type = ? AND participant_id = ?", conversationID, "admin", toAdminID).
			Count(&count).Error; err != nil {
			return err
		}
		if count > 0 {
			return fmt.Errorf("该客服已在会话中")
		}
		// 删除原客服参与者
		if err := tx.Where("conversation_id = ? AND participant_type = ? AND role = ?", conversationID, "admin", "support").
			Delete(&model.ChatParticipant{}).Error; err != nil {
			return err
		}
		// 添加新客服参与者
		participant := model.ChatParticipant{
			ConversationID:  conversationID,
			ParticipantType: "admin",
			ParticipantID:   toAdminID,
			Role:            "support",
			JoinedAt:        time.Now(),
		}
		if err := tx.Create(&participant).Error; err != nil {
			return err
		}
		// 添加系统消息记录转接
		message := model.ChatMessage{
			ConversationID: conversationID,
			SenderType:     "system",
			SenderRole:     "system",
			ContentType:    "system",
			Content:        "会话已转接给其他客服",
			AttachmentURLS: emptyJSONList(),
		}
		if err := tx.Create(&message).Error; err != nil {
			return err
		}
		return nil
	})
}
func (r *Repository) GetAvailableSupportAdmins(ctx context.Context) ([]SupportAdminDTO, error) {
	db := r.db.WithContext(ctx)
	// 仅展示客服角色管理员，超级管理员即使有 chat:view 权限也不作为客服候选。
	type adminRow struct {
		ID            uint64
		Nickname      string
		SupportStatus string
	}
	var admins []adminRow
	err := db.Table("admin_users AS au").
		Select("au.id, COALESCE(NULLIF(au.nickname, ''), au.username) AS nickname, au.support_status").
		Joins("JOIN admin_user_roles AS aur ON aur.admin_user_id = au.id").
		Joins("JOIN roles AS r ON r.id = aur.role_id").
		Where("au.status = ? AND r.code = ?", "active", defaultSupportRoleCode).
		Order("CASE au.support_status WHEN 'online' THEN 0 WHEN 'busy' THEN 1 ELSE 2 END, au.id ASC").
		Scan(&admins).Error
	if err != nil {
		return nil, err
	}

	// 统计每个客服的会话数
	type loadRow struct {
		AdminID uint64
		Count   int64
	}
	var loads []loadRow
	adminIDs := make([]uint64, len(admins))
	for i, a := range admins {
		adminIDs[i] = a.ID
	}
	if len(adminIDs) > 0 {
		db.Table("chat_participants").
			Select("participant_id AS admin_id, COUNT(*) AS count").
			Where("participant_type = ? AND role = ? AND participant_id IN ?", "admin", "support", adminIDs).
			Group("participant_id").
			Scan(&loads)
	}
	loadMap := make(map[uint64]int64)
	for _, l := range loads {
		loadMap[l.AdminID] = l.Count
	}

	result := make([]SupportAdminDTO, len(admins))
	for i, a := range admins {
		result[i] = SupportAdminDTO{
			ID:            a.ID,
			Nickname:      a.Nickname,
			SupportStatus: a.SupportStatus,
			ChatCount:     loadMap[a.ID],
		}
	}
	return result, nil
}
func (r *Repository) ListConversationsWithFilter(ctx context.Context, principal Principal, page, pageSize int, filter string) (*PaginatedResult, error) {
	page, pageSize = normalizePagination(page, pageSize)
	db := r.db.WithContext(ctx)

	// 管理员在"全部"模式下直接查询所有会话
	if principal.Type == "admin" && filter == "all" {
		var total int64
		if err := db.Model(&model.ChatConversation{}).Count(&total).Error; err != nil {
			return nil, err
		}

		var conversations []model.ChatConversation
		offset := (page - 1) * pageSize
		if err := db.Order("COALESCE(last_message_at, created_at) DESC, id DESC").
			Offset(offset).
			Limit(pageSize).
			Find(&conversations).Error; err != nil {
			return nil, err
		}

		items := make([]ConversationDTO, 0, len(conversations))
		for _, conv := range conversations {
			participants, err := r.participants(ctx, conv.ID)
			if err != nil {
				return nil, err
			}
			items = append(items, ConversationDTO{
				ID:                 conv.ID,
				OrderID:            conv.OrderID,
				Type:               conv.Type,
				Title:              conv.Title,
				Status:             conv.Status,
				Role:               "admin", // 管理员角色
				Participants:       participants,
				LastMessageID:      conv.LastMessageID,
				LastMessagePreview: conv.LastMessagePreview,
				LastMessageAt:      conv.LastMessageAt,
				UnreadCount:        0, // 管理员不计未读
				CreatedAt:          conv.CreatedAt,
				UpdatedAt:          conv.UpdatedAt,
			})
		}
		return &PaginatedResult{Items: items, Total: total, Page: page, PageSize: pageSize}, nil
	}

	// 其他情况使用原有逻辑
	var total int64
	countDB := db.Table("chat_conversations AS c").
		Joins("JOIN chat_participants AS cp ON cp.conversation_id = c.id")

	switch filter {
	case "mine":
		// 只看我的会话
		countDB = countDB.Where("cp.participant_type = ? AND cp.participant_id = ?", principal.Type, principal.ID)
	case "unassigned":
		// 未分配客服的会话
		countDB = countDB.Where("c.id NOT IN (?)",
			db.Table("chat_participants").Select("conversation_id").Where("participant_type = ? AND role = ?", "admin", "support"))
	default:
		// 普通用户的全部会话
		countDB = countDB.Where("cp.participant_type = ? AND cp.participant_id = ?", principal.Type, principal.ID)
	}

	if err := countDB.Count(&total).Error; err != nil {
		return nil, err
	}

	var rows []conversationRow
	offset := (page - 1) * pageSize

	queryDB := r.conversationQuery(ctx, principal)
	switch filter {
	case "mine":
		queryDB = queryDB.Where("cp.participant_type = ? AND cp.participant_id = ?", principal.Type, principal.ID)
	case "unassigned":
		queryDB = queryDB.Where("c.id NOT IN (?)",
			db.Table("chat_participants").Select("conversation_id").Where("participant_type = ? AND role = ?", "admin", "support"))
	default:
		// 普通用户的全部会话
		queryDB = queryDB.Where("cp.participant_type = ? AND cp.participant_id = ?", principal.Type, principal.ID)
	}

	err := queryDB.
		Order("COALESCE(c.last_message_at, c.created_at) DESC, c.id DESC").
		Offset(offset).
		Limit(pageSize).
		Scan(&rows).Error
	if err != nil {
		return nil, err
	}

	items := make([]ConversationDTO, 0, len(rows))
	for _, row := range rows {
		participants, err := r.participants(ctx, row.ID)
		if err != nil {
			return nil, err
		}
		items = append(items, row.toDTO(participants))
	}
	return &PaginatedResult{Items: items, Total: total, Page: page, PageSize: pageSize}, nil
}
