package repository

import (
	"campaign-pool-be/app/database/entity"
	"campaign-pool-be/app/module/communications/request"
	"campaign-pool-be/utils/paginator"
	"time"

	"gorm.io/gorm"
)

type communicationsRepository struct {
	DB *gorm.DB
}

type CommunicationsRepository interface {
	// Conversations
	GetUserConversations(userId uint, req request.ConversationsQueryRequest) (conversations []*entity.Conversations, paging paginator.Pagination, err error)
	FindConversationByParticipants(participant1ID, participant2ID uint) (conversation *entity.Conversations, err error)
	FindConversationByUserAndId(userId uint, conversationId uint) (conversation *entity.Conversations, err error)
	CreateConversation(conversation *entity.Conversations) (result *entity.Conversations, err error)
	UpdateConversationLastMessage(conversationId uint, lastMessageAt *time.Time) (err error)

	// Chat Messages
	GetConversationMessages(conversationId uint, req request.ChatMessagesQueryRequest) (messages []*entity.ChatMessages, paging paginator.Pagination, err error)
	CreateChatMessage(message *entity.ChatMessages) (result *entity.ChatMessages, err error)
	MarkMessageAsRead(messageId uint, userId uint) (err error)
	GetUnreadCount(conversationId uint, userId uint) (count int64, err error)
}

func NewCommunicationsRepository(db *gorm.DB) CommunicationsRepository {
	return &communicationsRepository{
		DB: db,
	}
}

// Conversations methods
func (_i *communicationsRepository) GetUserConversations(userId uint, req request.ConversationsQueryRequest) (conversations []*entity.Conversations, paging paginator.Pagination, err error) {
	query := _i.DB.Where("participant1_id = ? OR participant2_id = ?", userId, userId)

	// Include relationships
	query = query.Preload("Participant1").Preload("Participant2")

	// Order by last message time desc, then by created_at desc
	query = query.Order("last_message_at DESC NULLS LAST, created_at DESC")

	// Apply pagination
	var count int64
	query.Count(&count)
	req.Pagination.Count = count
	req.Pagination = paginator.Paging(req.Pagination)

	err = query.Offset(req.Pagination.Offset).Limit(req.Pagination.Limit).Find(&conversations).Error
	paging = *req.Pagination

	return
}

func (_i *communicationsRepository) FindConversationByParticipants(participant1ID, participant2ID uint) (conversation *entity.Conversations, err error) {
	err = _i.DB.Where(
		"(participant1_id = ? AND participant2_id = ?) OR (participant1_id = ? AND participant2_id = ?)",
		participant1ID, participant2ID, participant2ID, participant1ID).Preload("Participant1").Preload("Participant2").First(&conversation).Error
	return
}

func (_i *communicationsRepository) FindConversationByUserAndId(userId uint, conversationId uint) (conversation *entity.Conversations, err error) {
	err = _i.DB.Where(
		"id = ? AND (participant1_id = ? OR participant2_id = ?)",
		conversationId, userId, userId).Preload("Participant1").Preload("Participant2").First(&conversation).Error
	return
}

func (_i *communicationsRepository) CreateConversation(conversation *entity.Conversations) (result *entity.Conversations, err error) {
	err = _i.DB.Create(conversation).Error
	if err != nil {
		return nil, err
	}

	// Reload with relationships
	err = _i.DB.Preload("Participant1").Preload("Participant2").First(&result, conversation.ID).Error
	return
}

func (_i *communicationsRepository) UpdateConversationLastMessage(conversationId uint, lastMessageAt *time.Time) (err error) {
	err = _i.DB.Model(&entity.Conversations{}).Where("id = ?", conversationId).Update("last_message_at", lastMessageAt).Error
	return
}

// Chat Messages methods
func (_i *communicationsRepository) GetConversationMessages(conversationId uint, req request.ChatMessagesQueryRequest) (messages []*entity.ChatMessages, paging paginator.Pagination, err error) {
	query := _i.DB.Where("conversation_id = ?", conversationId)

	// Include sender relationship
	query = query.Preload("Sender")

	// Order by created_at asc (oldest first for chat)
	query = query.Order("created_at ASC")

	// Apply pagination
	var count int64
	query.Count(&count)
	req.Pagination.Count = count
	req.Pagination = paginator.Paging(req.Pagination)

	err = query.Offset(req.Pagination.Offset).Limit(req.Pagination.Limit).Find(&messages).Error
	paging = *req.Pagination

	return
}

func (_i *communicationsRepository) CreateChatMessage(message *entity.ChatMessages) (result *entity.ChatMessages, err error) {
	err = _i.DB.Create(message).Error
	if err != nil {
		return nil, err
	}

	// Reload with relationships
	err = _i.DB.Preload("Sender").First(&result, message.ID).Error
	return
}

func (_i *communicationsRepository) MarkMessageAsRead(messageId uint, userId uint) (err error) {
	err = _i.DB.Model(&entity.ChatMessages{}).Where("id = ? AND sender_id != ?", messageId, userId).Update("is_read", true).Error
	return
}

func (_i *communicationsRepository) GetUnreadCount(conversationId uint, userId uint) (count int64, err error) {
	err = _i.DB.Model(&entity.ChatMessages{}).Where("conversation_id = ? AND sender_id != ? AND is_read = false", conversationId, userId).Count(&count).Error
	return
}
