package processor

import (
	"apskel-pos-be/internal/appcontext"
	"apskel-pos-be/internal/entities"
	"apskel-pos-be/internal/mappers"
	"apskel-pos-be/internal/models"
	"apskel-pos-be/internal/repository"
	"context"
	"fmt"

	"github.com/google/uuid"
)

type OutletProcessor interface {
	ListOutletsByOrganization(ctx context.Context, organizationID uuid.UUID, page, limit int) ([]*models.OutletResponse, int64, error)
	GetOutletByID(ctx context.Context, organizationID uuid.UUID, outletID uuid.UUID) (*models.OutletResponse, error)
	CreateOutlet(ctx context.Context, req *models.CreateOutletRequest) (*models.OutletResponse, error)
	UpdateOutlet(ctx context.Context, outletID uuid.UUID, req *models.UpdateOutletRequest) (*models.OutletResponse, error)
	DeleteOutlet(ctx context.Context, outletID uuid.UUID) error
}

type OutletProcessorImpl struct {
	outletRepo *repository.OutletRepositoryImpl
}

func NewOutletProcessorImpl(outletRepo *repository.OutletRepositoryImpl) *OutletProcessorImpl {
	return &OutletProcessorImpl{
		outletRepo: outletRepo,
	}
}

func (p *OutletProcessorImpl) ListOutletsByOrganization(ctx context.Context, organizationID uuid.UUID, page, limit int) ([]*models.OutletResponse, int64, error) {
	offset := (page - 1) * limit

	outlets, total, err := p.outletRepo.GetByOrganizationIDWithPagination(ctx, organizationID, limit, offset)
	if err != nil {
		return nil, 0, fmt.Errorf("failed to get outlets: %w", err)
	}

	// Convert to response models
	responses := make([]*models.OutletResponse, len(outlets))
	for i, outlet := range outlets {
		responses[i] = mappers.OutletEntityToResponse(outlet)
	}

	return responses, total, nil
}

func (p *OutletProcessorImpl) GetOutletByID(ctx context.Context, organizationID, outletID uuid.UUID) (*models.OutletResponse, error) {
	outlet, err := p.outletRepo.GetByID(ctx, outletID)
	if err != nil {
		return nil, fmt.Errorf("outlet not found: %w", err)
	}

	if outlet.OrganizationID != organizationID {
		return nil, fmt.Errorf("outlet does not belong to the organization")
	}

	response := mappers.OutletEntityToResponse(outlet)
	return response, nil
}

func (p *OutletProcessorImpl) CreateOutlet(ctx context.Context, req *models.CreateOutletRequest) (*models.OutletResponse, error) {
	// Get organization ID from context
	contextInfo := appcontext.FromContext(ctx)
	if contextInfo.OrganizationID == uuid.Nil {
		return nil, fmt.Errorf("organization ID not found in context")
	}

	// Set organization ID from context
	req.OrganizationID = contextInfo.OrganizationID

	// Create outlet entity
	outlet := &entities.Outlet{
		OrganizationID: req.OrganizationID,
		Name:           req.Name,
		Address:        &req.Address,
		Currency:       string(req.Currency),
		TaxRate:        req.TaxRate,
		IsActive:       true,
	}

	err := p.outletRepo.Create(ctx, outlet)
	if err != nil {
		return nil, fmt.Errorf("failed to create outlet: %w", err)
	}

	response := mappers.OutletEntityToResponse(outlet)
	return response, nil
}

func (p *OutletProcessorImpl) UpdateOutlet(ctx context.Context, outletID uuid.UUID, req *models.UpdateOutletRequest) (*models.OutletResponse, error) {
	outlet, err := p.outletRepo.GetByID(ctx, outletID)
	if err != nil {
		return nil, fmt.Errorf("outlet not found: %w", err)
	}

	if outlet.OrganizationID != req.OrganizationID {
		return nil, fmt.Errorf("outlet does not belong to the organization")
	}

	if req.Name != nil {
		outlet.Name = *req.Name
	}
	if req.Address != nil {
		outlet.Address = req.Address
	}
	if req.TaxRate != nil {
		outlet.TaxRate = *req.TaxRate
	}
	if req.IsActive != nil {
		outlet.IsActive = *req.IsActive
	}

	err = p.outletRepo.Update(ctx, outlet)
	if err != nil {
		return nil, fmt.Errorf("failed to update outlet: %w", err)
	}

	response := mappers.OutletEntityToResponse(outlet)
	return response, nil
}

func (p *OutletProcessorImpl) DeleteOutlet(ctx context.Context, outletID uuid.UUID) error {
	contextInfo := appcontext.FromContext(ctx)
	if contextInfo.OrganizationID == uuid.Nil {
		return fmt.Errorf("organization ID not found in context")
	}

	// Get existing outlet
	outlet, err := p.outletRepo.GetByID(ctx, outletID)
	if err != nil {
		return fmt.Errorf("outlet not found: %w", err)
	}

	if outlet.OrganizationID != contextInfo.OrganizationID {
		return fmt.Errorf("outlet does not belong to the organization")
	}

	err = p.outletRepo.Delete(ctx, outletID)
	if err != nil {
		return fmt.Errorf("failed to delete outlet: %w", err)
	}

	return nil
}
