package processor

import (
	"context"
	"eslogad-be/internal/appcontext"
	"time"

	"eslogad-be/internal/entities"
	"eslogad-be/internal/repository"

	"github.com/google/uuid"
)

type RecipientProcessor interface {
	CreateDefaultRecipients(ctx context.Context, letterID uuid.UUID) ([]entities.LetterIncomingRecipient, error)
	CreateRecipients(ctx context.Context, letterID uuid.UUID, departmentIDs []uuid.UUID) ([]entities.LetterIncomingRecipient, error)
	CreateSingleRecipient(ctx context.Context, recipient *entities.LetterIncomingRecipient) error
}

type RecipientProcessorImpl struct {
	recipientRepo  *repository.LetterIncomingRecipientRepository
	settingRepo    *repository.AppSettingRepository
	departmentRepo *repository.DepartmentRepository
	userDeptRepo   *repository.UserDepartmentRepository
}

func NewRecipientProcessor(
	recipientRepo *repository.LetterIncomingRecipientRepository,
	settingRepo *repository.AppSettingRepository,
	departmentRepo *repository.DepartmentRepository,
	userDeptRepo *repository.UserDepartmentRepository,
) *RecipientProcessorImpl {
	return &RecipientProcessorImpl{
		recipientRepo:  recipientRepo,
		settingRepo:    settingRepo,
		departmentRepo: departmentRepo,
		userDeptRepo:   userDeptRepo,
	}
}

func (p *RecipientProcessorImpl) CreateDefaultRecipients(ctx context.Context, letterID uuid.UUID) ([]entities.LetterIncomingRecipient, error) {
	departmentIDs, err := p.settingRepo.GetDepartmentRecipients(ctx)
	if err != nil {
		return []entities.LetterIncomingRecipient{}, nil
	}

	if len(departmentIDs) == 0 {
		return []entities.LetterIncomingRecipient{}, nil
	}

	return p.CreateRecipients(ctx, letterID, departmentIDs)
}

func (p *RecipientProcessorImpl) CreateRecipients(ctx context.Context, letterID uuid.UUID, departmentIDs []uuid.UUID) ([]entities.LetterIncomingRecipient, error) {
	userCreatorDepartment := appcontext.FromGinContext(ctx).DepartmentID
	departmentIDs = append(departmentIDs, userCreatorDepartment)

	userMemberships, err := p.userDeptRepo.ListActiveByDepartmentIDs(ctx, departmentIDs)
	if err != nil {
		return nil, err
	}

	recipients := p.buildUniqueRecipients(letterID, userMemberships, userCreatorDepartment)

	if err := p.recipientRepo.CreateBulk(ctx, recipients); err != nil {
		return nil, err
	}

	return recipients, nil
}

func (p *RecipientProcessorImpl) buildUniqueRecipients(letterID uuid.UUID, userMemberships []repository.UserDepartmentRow, userCreatorDepartment uuid.UUID) []entities.LetterIncomingRecipient {
	var recipients []entities.LetterIncomingRecipient
	userMap := make(map[string]bool)
	now := time.Now()

	for _, membership := range userMemberships {
		userIDStr := membership.UserID.String()

		if !userMap[userIDStr] {
			userID := membership.UserID
			departmentID := membership.DepartmentID

			if userCreatorDepartment == membership.DepartmentID {
				recipients = append(recipients, entities.LetterIncomingRecipient{
					LetterID:              letterID,
					RecipientUserID:       &userID,
					RecipientDepartmentID: &departmentID,
					Status:                entities.RecipientStatusCompleted,
					ReadAt:                &now,
					CompletedAt:           &now,
				})
			} else {
				recipients = append(recipients, entities.LetterIncomingRecipient{
					LetterID:              letterID,
					RecipientUserID:       &userID,
					RecipientDepartmentID: &departmentID,
					Status:                entities.RecipientStatusNew,
				})
			}
			userMap[userIDStr] = true
		}
	}

	return recipients
}

func (p *RecipientProcessorImpl) CreateSingleRecipient(ctx context.Context, recipient *entities.LetterIncomingRecipient) error {
	return p.recipientRepo.Create(ctx, recipient)
}
