package repository

import (
	"narasi-ahli-be/app/database"
	"narasi-ahli-be/app/database/entity"
	"narasi-ahli-be/app/module/chat/request"
	"narasi-ahli-be/utils/paginator"
)

type chatRepository struct {
	DB *database.Database
}

type ChatRepository interface {
	// Chat Session methods
	GetAllChatSessions(userId uint, req request.ChatSessionQueryRequest) (chatSessions []*entity.ChatSessions, paging paginator.Pagination, err error)
	FindChatSessionByID(id uint) (chatSession *entity.ChatSessions, err error)
	FindChatSessionByUserAndID(userId uint, id uint) (chatSession *entity.ChatSessions, err error)
	CreateChatSession(chatSession *entity.ChatSessions) (result *entity.ChatSessions, err error)
	UpdateChatSession(id uint, chatSession *entity.ChatSessions) (err error)
	DeleteChatSession(id uint) (err error)

	// Chat Message methods
	GetAllChatMessages(req request.ChatMessageQueryRequest) (chatMessages []*entity.ChatMessages, paging paginator.Pagination, err error)
	FindChatMessageByID(id uint) (chatMessage *entity.ChatMessages, err error)
	FindChatMessageByUserAndID(userId uint, id uint) (chatMessage *entity.ChatMessages, err error)
	CreateChatMessage(chatMessage *entity.ChatMessages) (result *entity.ChatMessages, err error)
	UpdateChatMessage(id uint, chatMessage *entity.ChatMessages) (err error)
	DeleteChatMessage(id uint) (err error)

	// Chat Participant methods
	CreateChatParticipant(chatParticipant *entity.ChatParticipants) (result *entity.ChatParticipants, err error)
	FindChatParticipantsBySessionID(chatSessionID uint) (participants []*entity.ChatParticipants, err error)
	UpdateChatParticipant(id uint, chatParticipant *entity.ChatParticipants) (err error)
	DeleteChatParticipant(id uint) (err error)

	// Utility methods
	FindPersonalChatSession(userId1 uint, userId2 uint) (chatSession *entity.ChatSessions, err error)
	CheckUserInChatSession(userId uint, chatSessionID uint) (isParticipant bool, err error)
}

func NewChatRepository(db *database.Database) ChatRepository {
	return &chatRepository{
		DB: db,
	}
}

// Chat Session Repository Methods
func (_i *chatRepository) GetAllChatSessions(userId uint, req request.ChatSessionQueryRequest) (chatSessions []*entity.ChatSessions, paging paginator.Pagination, err error) {
	// Get chat sessions where user is a participant
	query := _i.DB.DB.Model(&entity.ChatSessions{}).
		Joins("INNER JOIN chat_participants cp ON chat_sessions.id = cp.chat_session_id").
		Where("cp.user_id = ? AND cp.is_active = true", userId)

	// Apply filters
	if req.Type != nil {
		query = query.Where("chat_sessions.type = ?", *req.Type)
	}

	// Include relationships
	query = query.Preload("Creator").
		Preload("Participants", "is_active = true").
		Preload("Participants.User").
		Preload("Messages", "is_deleted = false").
		Preload("Messages.Sender")

	// Order by updated_at desc (most recent first)
	query = query.Order("chat_sessions.updated_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(&chatSessions).Error
	paging = *req.Pagination

	return
}

func (_i *chatRepository) FindChatSessionByID(id uint) (chatSession *entity.ChatSessions, err error) {
	err = _i.DB.DB.Preload("Creator").
		Preload("Participants", "is_active = true").
		Preload("Participants.User").
		Preload("Messages", "is_deleted = false").
		Preload("Messages.Sender").
		First(&chatSession, id).Error
	return
}

func (_i *chatRepository) FindChatSessionByUserAndID(userId uint, id uint) (chatSession *entity.ChatSessions, err error) {
	// Check if user is participant in this chat session
	var isParticipant bool
	err = _i.DB.DB.Table("chat_participants").
		Select("COUNT(*) > 0").
		Where("chat_session_id = ? AND user_id = ? AND is_active = true", id, userId).
		Scan(&isParticipant).Error

	if err != nil {
		return nil, err
	}

	if !isParticipant {
		return nil, nil
	}

	err = _i.DB.DB.Preload("Creator").
		Preload("Participants", "is_active = true").
		Preload("Participants.User").
		Preload("Messages", "is_deleted = false").
		Preload("Messages.Sender").
		First(&chatSession, id).Error
	return
}

func (_i *chatRepository) CreateChatSession(chatSession *entity.ChatSessions) (result *entity.ChatSessions, err error) {
	err = _i.DB.DB.Create(chatSession).Error
	if err != nil {
		return nil, err
	}

	// Reload with relationships
	err = _i.DB.DB.Preload("Creator").
		Preload("Participants", "is_active = true").
		Preload("Participants.User").
		First(&result, chatSession.ID).Error
	return
}

func (_i *chatRepository) UpdateChatSession(id uint, chatSession *entity.ChatSessions) (err error) {
	err = _i.DB.DB.Model(&entity.ChatSessions{}).Where("id = ?", id).Updates(chatSession).Error
	return
}

func (_i *chatRepository) DeleteChatSession(id uint) (err error) {
	err = _i.DB.DB.Delete(&entity.ChatSessions{}, id).Error
	return
}

// Chat Message Repository Methods
func (_i *chatRepository) GetAllChatMessages(req request.ChatMessageQueryRequest) (chatMessages []*entity.ChatMessages, paging paginator.Pagination, err error) {
	// Check if user is participant in this chat session
	var isParticipant bool
	err = _i.DB.DB.Table("chat_participants").
		Select("COUNT(*) > 0").
		Where("chat_session_id = ? AND user_id = ? AND is_active = true", req.ChatSessionID, req.UserID).
		Scan(&isParticipant).Error

	if err != nil {
		return nil, paginator.Pagination{}, err
	}

	if !isParticipant {
		return nil, paginator.Pagination{}, nil
	}

	query := _i.DB.DB.Model(&entity.ChatMessages{}).Where("chat_session_id = ? AND is_deleted = false", req.ChatSessionID)

	// Include relationships
	query = query.Preload("Sender")

	// Order by created_at desc (most recent first)
	query = query.Order("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(&chatMessages).Error
	paging = *req.Pagination

	return
}

func (_i *chatRepository) FindChatMessageByID(id uint) (chatMessage *entity.ChatMessages, err error) {
	err = _i.DB.DB.Preload("Sender").First(&chatMessage, id).Error
	return
}

func (_i *chatRepository) FindChatMessageByUserAndID(userId uint, id uint) (chatMessage *entity.ChatMessages, err error) {
	// Check if user is participant in the chat session of this message
	var isParticipant bool
	err = _i.DB.DB.Table("chat_messages cm").
		Joins("INNER JOIN chat_participants cp ON cm.chat_session_id = cp.chat_session_id").
		Select("COUNT(*) > 0").
		Where("cm.id = ? AND cp.user_id = ? AND cp.is_active = true", id, userId).
		Scan(&isParticipant).Error

	if err != nil {
		return nil, err
	}

	if !isParticipant {
		return nil, nil
	}

	err = _i.DB.DB.Preload("Sender").First(&chatMessage, id).Error
	return
}

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

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

func (_i *chatRepository) UpdateChatMessage(id uint, chatMessage *entity.ChatMessages) (err error) {
	err = _i.DB.DB.Model(&entity.ChatMessages{}).Where("id = ?", id).Updates(chatMessage).Error
	return
}

func (_i *chatRepository) DeleteChatMessage(id uint) (err error) {
	err = _i.DB.DB.Delete(&entity.ChatMessages{}, id).Error
	return
}

// Chat Participant Repository Methods
func (_i *chatRepository) CreateChatParticipant(chatParticipant *entity.ChatParticipants) (result *entity.ChatParticipants, err error) {
	err = _i.DB.DB.Create(chatParticipant).Error
	if err != nil {
		return nil, err
	}

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

func (_i *chatRepository) FindChatParticipantsBySessionID(chatSessionID uint) (participants []*entity.ChatParticipants, err error) {
	err = _i.DB.DB.Model(&entity.ChatParticipants{}).Where("chat_session_id = ? AND is_active = true", chatSessionID).
		Preload("User").Find(&participants).Error
	return
}

func (_i *chatRepository) UpdateChatParticipant(id uint, chatParticipant *entity.ChatParticipants) (err error) {
	err = _i.DB.DB.Model(&entity.ChatParticipants{}).Where("id = ?", id).Updates(chatParticipant).Error
	return
}

func (_i *chatRepository) DeleteChatParticipant(id uint) (err error) {
	err = _i.DB.DB.Delete(&entity.ChatParticipants{}, id).Error
	return
}

// Utility Methods
func (_i *chatRepository) FindPersonalChatSession(userId1 uint, userId2 uint) (chatSession *entity.ChatSessions, err error) {
	err = _i.DB.DB.Model(&entity.ChatSessions{}).
		Joins("INNER JOIN chat_participants cp1 ON chat_sessions.id = cp1.chat_session_id").
		Joins("INNER JOIN chat_participants cp2 ON chat_sessions.id = cp2.chat_session_id").
		Where("chat_sessions.type = 'personal' AND cp1.user_id = ? AND cp2.user_id = ? AND cp1.is_active = true AND cp2.is_active = true", userId1, userId2).
		Preload("Creator").
		Preload("Participants", "is_active = true").
		Preload("Participants.User").
		First(&chatSession).Error
	return
}

func (_i *chatRepository) CheckUserInChatSession(userId uint, chatSessionID uint) (isParticipant bool, err error) {
	err = _i.DB.DB.Table("chat_participants").
		Select("COUNT(*) > 0").
		Where("chat_session_id = ? AND user_id = ? AND is_active = true", chatSessionID, userId).
		Scan(&isParticipant).Error
	return
}
