package processor

import (
	"context"
	"fmt"

	"apskel-pos-be/internal/mappers"
	"apskel-pos-be/internal/models"

	"github.com/google/uuid"
)


type ChartOfAccountTypeProcessor interface {
	CreateChartOfAccountType(ctx context.Context, req *models.CreateChartOfAccountTypeRequest) (*models.ChartOfAccountTypeResponse, error)
	GetChartOfAccountTypeByID(ctx context.Context, id uuid.UUID) (*models.ChartOfAccountTypeResponse, error)
	UpdateChartOfAccountType(ctx context.Context, id uuid.UUID, req *models.UpdateChartOfAccountTypeRequest) (*models.ChartOfAccountTypeResponse, error)
	DeleteChartOfAccountType(ctx context.Context, id uuid.UUID) error
	ListChartOfAccountTypes(ctx context.Context, filters map[string]interface{}, page, limit int) ([]models.ChartOfAccountTypeResponse, int, error)
}

type ChartOfAccountTypeProcessorImpl struct {
	chartOfAccountTypeRepo ChartOfAccountTypeRepository
}

func NewChartOfAccountTypeProcessorImpl(chartOfAccountTypeRepo ChartOfAccountTypeRepository) *ChartOfAccountTypeProcessorImpl {
	return &ChartOfAccountTypeProcessorImpl{
		chartOfAccountTypeRepo: chartOfAccountTypeRepo,
	}
}

func (p *ChartOfAccountTypeProcessorImpl) CreateChartOfAccountType(ctx context.Context, req *models.CreateChartOfAccountTypeRequest) (*models.ChartOfAccountTypeResponse, error) {
	// Check if code already exists
	existing, err := p.chartOfAccountTypeRepo.GetByCode(ctx, req.Code)
	if err == nil && existing != nil {
		return nil, fmt.Errorf("chart of account type with code %s already exists", req.Code)
	}

	entity := mappers.ChartOfAccountTypeCreateRequestToEntity(req)
	err = p.chartOfAccountTypeRepo.Create(ctx, entity)
	if err != nil {
		return nil, fmt.Errorf("failed to create chart of account type: %w", err)
	}

	return mappers.ChartOfAccountTypeEntityToResponse(entity), nil
}

func (p *ChartOfAccountTypeProcessorImpl) GetChartOfAccountTypeByID(ctx context.Context, id uuid.UUID) (*models.ChartOfAccountTypeResponse, error) {
	entity, err := p.chartOfAccountTypeRepo.GetByID(ctx, id)
	if err != nil {
		return nil, fmt.Errorf("chart of account type not found: %w", err)
	}

	return mappers.ChartOfAccountTypeEntityToResponse(entity), nil
}

func (p *ChartOfAccountTypeProcessorImpl) UpdateChartOfAccountType(ctx context.Context, id uuid.UUID, req *models.UpdateChartOfAccountTypeRequest) (*models.ChartOfAccountTypeResponse, error) {
	entity, err := p.chartOfAccountTypeRepo.GetByID(ctx, id)
	if err != nil {
		return nil, fmt.Errorf("chart of account type not found: %w", err)
	}

	// Check if new code already exists (if code is being updated)
	if req.Code != nil && *req.Code != entity.Code {
		existing, err := p.chartOfAccountTypeRepo.GetByCode(ctx, *req.Code)
		if err == nil && existing != nil {
			return nil, fmt.Errorf("chart of account type with code %s already exists", *req.Code)
		}
	}

	mappers.ChartOfAccountTypeUpdateRequestToEntity(entity, req)
	err = p.chartOfAccountTypeRepo.Update(ctx, entity)
	if err != nil {
		return nil, fmt.Errorf("failed to update chart of account type: %w", err)
	}

	return mappers.ChartOfAccountTypeEntityToResponse(entity), nil
}

func (p *ChartOfAccountTypeProcessorImpl) DeleteChartOfAccountType(ctx context.Context, id uuid.UUID) error {
	_, err := p.chartOfAccountTypeRepo.GetByID(ctx, id)
	if err != nil {
		return fmt.Errorf("chart of account type not found: %w", err)
	}

	err = p.chartOfAccountTypeRepo.Delete(ctx, id)
	if err != nil {
		return fmt.Errorf("failed to delete chart of account type: %w", err)
	}

	return nil
}

func (p *ChartOfAccountTypeProcessorImpl) ListChartOfAccountTypes(ctx context.Context, filters map[string]interface{}, page, limit int) ([]models.ChartOfAccountTypeResponse, int, error) {
	entities, total, err := p.chartOfAccountTypeRepo.List(ctx, filters, page, limit)
	if err != nil {
		return nil, 0, fmt.Errorf("failed to list chart of account types: %w", err)
	}

	responses := make([]models.ChartOfAccountTypeResponse, len(entities))
	for i, entity := range entities {
		responses[i] = *mappers.ChartOfAccountTypeEntityToResponse(entity)
	}

	return responses, total, nil
}
