package service

import (
	"errors"
	"narasi-ahli-be/app/module/ai_chat/mapper"
	"narasi-ahli-be/app/module/ai_chat/repository"
	"narasi-ahli-be/app/module/ai_chat/request"
	"narasi-ahli-be/app/module/ai_chat/response"
	usersRepository "narasi-ahli-be/app/module/users/repository"
	"narasi-ahli-be/utils/paginator"
	utilSvc "narasi-ahli-be/utils/service"

	"github.com/rs/zerolog"
)

type aiChatService struct {
	Repo      repository.AIChatRepository
	UsersRepo usersRepository.UsersRepository
	Log       zerolog.Logger
}

type AIChatService interface {
	// Sessions
	GetUserSessions(authToken string, req request.AIChatSessionsQueryRequest) (sessions []*response.AIChatSessionsResponse, paging paginator.Pagination, err error)
	GetSession(authToken string, id uint) (session *response.AIChatSessionsResponse, err error)
	CreateSession(authToken string, req request.AIChatSessionsCreateRequest) (session *response.AIChatSessionsResponse, err error)
	UpdateSession(authToken string, id uint, req request.AIChatSessionsUpdateRequest) (err error)
	DeleteSession(authToken string, id uint) error
	ArchiveSession(authToken string, id uint) error

	// Messages
	GetSessionMessages(authToken string, sessionId uint, req request.AIChatMessagesQueryRequest) (messages []*response.AIChatMessagesResponse, paging paginator.Pagination, err error)
	SendMessage(authToken string, req request.AIChatMessagesCreateRequest) (message *response.AIChatMessagesResponse, err error)
	UpdateMessage(authToken string, messageId uint, req request.AIChatMessagesUpdateRequest) (err error)
	DeleteMessage(authToken string, messageId uint) error

	// Logs
	GetUserLogs(authToken string, req request.AIChatLogsQueryRequest) (logs []*response.AIChatLogsResponse, paging paginator.Pagination, err error)
	GetLog(authToken string, logId uint) (log *response.AIChatLogsResponse, err error)
}

func NewAIChatService(repo repository.AIChatRepository, usersRepo usersRepository.UsersRepository, log zerolog.Logger) AIChatService {
	return &aiChatService{
		Repo:      repo,
		UsersRepo: usersRepo,
		Log:       log,
	}
}

// Sessions methods
func (_i *aiChatService) GetUserSessions(authToken string, req request.AIChatSessionsQueryRequest) (sessions []*response.AIChatSessionsResponse, paging paginator.Pagination, err error) {
	userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)

	results, paging, err := _i.Repo.GetUserSessions(userInfo.ID, req)
	if err != nil {
		return
	}

	for _, result := range results {
		sessions = append(sessions, mapper.AIChatSessionsResponseMapper(result))
	}

	return
}

func (_i *aiChatService) GetSession(authToken string, id uint) (session *response.AIChatSessionsResponse, err error) {
	userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)

	result, err := _i.Repo.FindSessionByUserAndId(userInfo.ID, id)
	if err != nil {
		return nil, err
	}

	return mapper.AIChatSessionsResponseMapper(result), nil
}

func (_i *aiChatService) CreateSession(authToken string, req request.AIChatSessionsCreateRequest) (session *response.AIChatSessionsResponse, err error) {
	userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)

	entity := req.ToEntity()
	entity.UserID = userInfo.ID

	_i.Log.Info().Interface("data", entity).Msg("Create AI chat session")

	result, err := _i.Repo.CreateSession(entity)
	if err != nil {
		return nil, err
	}

	return mapper.AIChatSessionsResponseMapper(result), nil
}

func (_i *aiChatService) UpdateSession(authToken string, id uint, req request.AIChatSessionsUpdateRequest) (err error) {
	userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
	_i.Log.Info().Interface("data", req).Msg("Updating AI chat session")

	// Check if session exists and belongs to user
	existing, err := _i.Repo.FindSessionByUserAndId(userInfo.ID, id)
	if err != nil {
		return err
	}
	if existing == nil {
		return errors.New("AI chat session not found")
	}

	entity := req.ToEntity()
	return _i.Repo.UpdateSession(userInfo.ID, id, entity)
}

func (_i *aiChatService) DeleteSession(authToken string, id uint) error {
	userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)

	// Check if session exists and belongs to user
	existing, err := _i.Repo.FindSessionByUserAndId(userInfo.ID, id)
	if err != nil {
		return err
	}
	if existing == nil {
		return errors.New("AI chat session not found")
	}

	return _i.Repo.DeleteSession(userInfo.ID, id)
}

func (_i *aiChatService) ArchiveSession(authToken string, id uint) error {
	userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)

	// Check if session exists and belongs to user
	existing, err := _i.Repo.FindSessionByUserAndId(userInfo.ID, id)
	if err != nil {
		return err
	}
	if existing == nil {
		return errors.New("AI chat session not found")
	}

	// Update status to archived
	existing.IsActive = false
	return _i.Repo.UpdateSession(userInfo.ID, id, existing)
}

// Messages methods
func (_i *aiChatService) GetSessionMessages(authToken string, sessionId uint, req request.AIChatMessagesQueryRequest) (messages []*response.AIChatMessagesResponse, paging paginator.Pagination, err error) {
	userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)

	// Verify session belongs to user
	session, err := _i.Repo.FindSessionByUserAndId(userInfo.ID, sessionId)
	if err != nil {
		return nil, paginator.Pagination{}, err
	}

	results, paging, err := _i.Repo.GetSessionMessages(session.SessionID, req)
	if err != nil {
		return
	}

	for _, result := range results {
		messages = append(messages, mapper.AIChatMessagesResponseMapper(result))
	}

	return
}

func (_i *aiChatService) SendMessage(authToken string, req request.AIChatMessagesCreateRequest) (message *response.AIChatMessagesResponse, err error) {
	// userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)

	// Verify session exists
	session, err := _i.Repo.FindSessionBySessionId(req.SessionID)
	if err != nil {
		return nil, err
	}

	entity := req.ToEntity()

	result, err := _i.Repo.CreateMessage(entity)
	if err != nil {
		return nil, err
	}

	// Increment message count in session
	err = _i.Repo.IncrementMessageCount(session.ID)
	if err != nil {
		_i.Log.Error().Err(err).Msg("Failed to increment message count")
	}

	return mapper.AIChatMessagesResponseMapper(result), nil
}

// Update Message
func (_i *aiChatService) UpdateMessage(authToken string, messageId uint, req request.AIChatMessagesUpdateRequest) (err error) {
	// userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)

	entity := req.ToEntity()
	return _i.Repo.UpdateMessage(messageId, entity)
}

// Delete Message
func (_i *aiChatService) DeleteMessage(authToken string, messageId uint) error {
	// userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)

	return _i.Repo.DeleteMessage(messageId)
}

// Logs methods
func (_i *aiChatService) GetUserLogs(authToken string, req request.AIChatLogsQueryRequest) (logs []*response.AIChatLogsResponse, paging paginator.Pagination, err error) {
	userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)

	results, paging, err := _i.Repo.GetUserLogs(userInfo.ID, req)
	if err != nil {
		return
	}

	for _, result := range results {
		logs = append(logs, mapper.AIChatLogsResponseMapper(result))
	}

	return
}

func (_i *aiChatService) GetLog(authToken string, logId uint) (log *response.AIChatLogsResponse, err error) {
	userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)

	result, err := _i.Repo.FindLogByUserAndId(userInfo.ID, logId)
	if err != nil {
		return nil, err
	}

	return mapper.AIChatLogsResponseMapper(result), nil
}
