package processor

import (
	"context"
	"time"

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

	"github.com/google/uuid"
)

type LetterApprovalProcessor interface {
	CreateApprovalSteps(ctx context.Context, letter *entities.LetterOutgoing) error
	ProcessApprovalAction(ctx context.Context, letterID uuid.UUID, approval *entities.LetterOutgoingApproval, userID uuid.UUID, isApproval bool) error
	UpdateApprovalStatus(ctx context.Context, approval *entities.LetterOutgoingApproval, status entities.ApprovalStatus, userID uuid.UUID) error
	CheckAllApprovalsComplete(ctx context.Context, letterID uuid.UUID) (bool, error)
}

type LetterApprovalProcessorImpl struct {
	approvalRepo     *repository.LetterOutgoingApprovalRepository
	approvalFlowRepo *repository.ApprovalFlowRepository
	letterRepo       *repository.LetterOutgoingRepository
}

func NewLetterApprovalProcessor(
	approvalRepo *repository.LetterOutgoingApprovalRepository,
	approvalFlowRepo *repository.ApprovalFlowRepository,
	letterRepo *repository.LetterOutgoingRepository,
) *LetterApprovalProcessorImpl {
	return &LetterApprovalProcessorImpl{
		approvalRepo:     approvalRepo,
		approvalFlowRepo: approvalFlowRepo,
		letterRepo:       letterRepo,
	}
}

func (p *LetterApprovalProcessorImpl) CreateApprovalSteps(ctx context.Context, letter *entities.LetterOutgoing) error {
	if letter.ApprovalFlowID == nil {
		return nil
	}

	flow, err := p.approvalFlowRepo.Get(ctx, *letter.ApprovalFlowID)
	if err != nil || flow == nil || len(flow.Steps) == 0 {
		return err
	}

	// Find the minimum step order (first step)
	minStepOrder := flow.Steps[0].StepOrder
	for _, step := range flow.Steps {
		if step.StepOrder < minStepOrder {
			minStepOrder = step.StepOrder
		}
	}

	// Create approval records for each step
	for _, step := range flow.Steps {
		approval := entities.LetterOutgoingApproval{
			LetterID:      letter.ID,
			StepID:        step.ID,
			StepOrder:     step.StepOrder,
			ParallelGroup: step.ParallelGroup,
			IsRequired:    step.Required,
			ApproverID:    step.ApproverUserID,
		}

		// Set initial status
		if step.StepOrder == minStepOrder {
			approval.Status = entities.ApprovalStatusPending
		} else {
			approval.Status = entities.ApprovalStatusNotStarted
		}

		if err := p.approvalRepo.Create(ctx, &approval); err != nil {
			return err
		}
	}

	return nil
}

func (p *LetterApprovalProcessorImpl) ProcessApprovalAction(ctx context.Context, letterID uuid.UUID, approval *entities.LetterOutgoingApproval, userID uuid.UUID, isApproval bool) error {
	status := entities.ApprovalStatusApproved
	if !isApproval {
		status = entities.ApprovalStatusRejected
	}

	return p.UpdateApprovalStatus(ctx, approval, status, userID)
}

func (p *LetterApprovalProcessorImpl) UpdateApprovalStatus(ctx context.Context, approval *entities.LetterOutgoingApproval, status entities.ApprovalStatus, userID uuid.UUID) error {
	approval.Status = status
	approval.ApproverID = &userID
	now := time.Now()
	approval.ActedAt = &now

	return p.approvalRepo.Update(ctx, approval)
}

func (p *LetterApprovalProcessorImpl) CheckAllApprovalsComplete(ctx context.Context, letterID uuid.UUID) (bool, error) {
	approvals, err := p.approvalRepo.ListByLetter(ctx, letterID)
	if err != nil {
		return false, err
	}

	for _, approval := range approvals {
		if approval.IsRequired && approval.Status != entities.ApprovalStatusApproved {
			return false, nil
		}
	}

	return true, nil
}