package chat

import (
	"context"
	"errors"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"hfb_sys/backend/internal/model"
	"hfb_sys/backend/internal/modules/chathub"
	"time"
)

func (r *Repository) Messages(ctx context.Context, principal Principal, conversationID uint64, page, pageSize int) (*PaginatedResult, error) {
	page, pageSize = normalizePagination(page, pageSize)
	db := r.db.WithContext(ctx)

	// 管理员可以查看任意会话的消息，普通用户需要是 participant
	if principal.Type != "admin" {
		if _, err := r.findParticipant(db, principal, conversationID, false); err != nil {
			return nil, err
		}
	} else {
		// 管理员需要验证会话存在
		var count int64
		if err := db.Model(&model.ChatConversation{}).Where("id = ?", conversationID).Count(&count).Error; err != nil {
			return nil, err
		}
		if count == 0 {
			return nil, ErrConversationNotFound
		}
	}

	// 构建查询
	query := db.Model(&model.ChatMessage{}).Where("conversation_id = ?", conversationID)

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

	offset := (page - 1) * pageSize
	var rows []model.ChatMessage
	if err := query.Order("id ASC").
		Offset(offset).
		Limit(pageSize).
		Find(&rows).Error; err != nil {
		return nil, err
	}
	items, err := r.toMessageDTOs(ctx, principal, rows)
	if err != nil {
		return nil, err
	}
	return &PaginatedResult{Items: items, Total: total, Page: page, PageSize: pageSize}, nil
}
func (r *Repository) SendMessage(ctx context.Context, principal Principal, conversationID uint64, req SendMessageRequest) (*MessageDTO, error) {
	var messageID uint64
	err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		var conversation model.ChatConversation
		if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&conversation, conversationID).Error; err != nil {
			return err
		}
		if conversation.Status != "active" {
			return ErrPermissionDenied
		}

		var senderRole string
		var participant *model.ChatParticipant

		// 管理员可以在任意会话发送消息，无需是 participant
		if principal.Type == "admin" {
			// 尝试查找管理员的 participant 记录
			var p model.ChatParticipant
			err := tx.Where("conversation_id = ? AND participant_type = ? AND participant_id = ?",
				conversationID, principal.Type, principal.ID).First(&p).Error
			if err == nil {
				// 管理员是 participant，使用其角色
				participant = &p
				senderRole = p.Role
			} else if errors.Is(err, gorm.ErrRecordNotFound) {
				// 管理员不是 participant，使用特殊角色 "admin"
				senderRole = "admin"
			} else {
				return err
			}
		} else {
			// 普通用户必须是 participant
			p, err := r.findParticipant(tx, principal, conversationID, true)
			if err != nil {
				return err
			}
			participant = p
			senderRole = p.Role
		}

		message := model.ChatMessage{
			ConversationID: conversation.ID,
			SenderType:     principal.Type,
			SenderID:       principal.ID,
			SenderRole:     senderRole,
			ContentType:    "text",
			Content:        req.Content,
			AttachmentURLS: encodeStringList(req.AttachmentURLS),
		}
		if err := tx.Create(&message).Error; err != nil {
			return err
		}
		conversation.LastMessageID = &message.ID
		conversation.LastMessagePreview = messagePreview(message.Content, req.AttachmentURLS)
		conversation.LastMessageAt = &message.CreatedAt
		if err := tx.Save(&conversation).Error; err != nil {
			return err
		}

		// 更新 participant 的已读时间（仅当是 participant 时）
		if participant != nil {
			now := time.Now()
			if err := tx.Model(participant).Update("last_read_at", now).Error; err != nil {
				return err
			}
		}

		messageID = message.ID
		return nil
	})
	if err != nil {
		return nil, err
	}
	var message model.ChatMessage
	if err := r.db.WithContext(ctx).First(&message, messageID).Error; err != nil {
		return nil, err
	}
	items, err := r.toMessageDTOs(ctx, principal, []model.ChatMessage{message})
	if err != nil {
		return nil, err
	}
	if len(items) == 0 {
		return nil, ErrConversationNotFound
	}
	// 推送新消息事件给会话中的在线参与者
	if r.hub != nil {
		msg := items[0]
		event := &chathub.ChatEvent{
			Type:           "new_message",
			ConversationID: conversationID,
			Message: &chathub.MessageData{
				ID:             msg.ID,
				ConversationID: msg.ConversationID,
				SenderType:     msg.SenderType,
				SenderID:       msg.SenderID,
				SenderRole:     msg.SenderRole,
				SenderName:     msg.SenderName,
				ContentType:    msg.ContentType,
				Content:        msg.Content,
				AttachmentURLS: msg.AttachmentURLS,
				CreatedAt:      msg.CreatedAt.Format(time.RFC3339),
			},
		}
		r.hub.NotifyConversation(conversationID, event)
		// 同时广播给所有在线客服，使「未分配 / 全部」视图实时刷新；
		// 参与者客服会重复收到，由前端按消息 id 去重。
		r.hub.NotifyAllAdmins(event)
	}
	return &items[0], nil
}
func (r *Repository) MarkRead(ctx context.Context, principal Principal, conversationID uint64) error {
	now := time.Now()
	updated := false
	err := r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		// 管理员可以不是 participant，直接返回成功
		if principal.Type == "admin" {
			// 尝试查找 participant 记录，如果有就更新
			var participant model.ChatParticipant
			err := tx.Where("conversation_id = ? AND participant_type = ? AND participant_id = ?",
				conversationID, principal.Type, principal.ID).First(&participant).Error
			if err == nil {
				// 有 participant 记录，更新已读时间
				updated = true
				return tx.Model(&participant).Update("last_read_at", now).Error
			} else if errors.Is(err, gorm.ErrRecordNotFound) {
				// 没有 participant 记录，直接返回成功（管理员无需记录已读）
				return nil
			}
			return err
		}

		// 普通用户必须是 participant
		participant, err := r.findParticipant(tx, principal, conversationID, true)
		if err != nil {
			return err
		}
		updated = true
		return tx.Model(participant).Update("last_read_at", now).Error
	})
	if err != nil {
		return err
	}
	// 已读时间发生变化时，通知会话内其他参与者刷新「已读」状态。
	if updated && r.hub != nil {
		event := &chathub.ChatEvent{
			Type:           "conversation_read",
			ConversationID: conversationID,
			ReaderType:     principal.Type,
			ReaderID:       principal.ID,
			ReadAt:         now.Format(time.RFC3339),
		}
		r.hub.NotifyConversation(conversationID, event)
		// 同时广播给所有在线客服，覆盖未分配会话中非参与者客服的「已读」刷新。
		r.hub.NotifyAllAdmins(event)
	}
	return nil
}
