package services

import (
	"context"
	"strings"
	"edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/domain"
	"edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/ports/driven"
	"edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/ports/driving"
)

type cloudletService struct {
	cloudletRepo driven.CloudletRepository
}

func NewCloudletService(cloudletRepo driven.CloudletRepository) driving.CloudletService {
	return &cloudletService{cloudletRepo: cloudletRepo}
}

func (s *cloudletService) CreateCloudlet(ctx context.Context, region string, cloudlet *domain.Cloudlet) error {
	if err := s.validateCloudlet(cloudlet); err != nil {
		return err
	}

	if region == "" {
		return domain.ErrMissingRegion
	}

	if err := s.cloudletRepo.CreateCloudlet(ctx, region, cloudlet); err != nil {
		if domain.IsNotFoundError(err) {
			return domain.NewCloudletError(domain.ErrResourceConflict, "CreateCloudlet", cloudlet.Key, region, 
				"cloudlet may already exist or have conflicting configuration")
		}
		return domain.NewCloudletError(domain.ErrInternalError, "CreateCloudlet", cloudlet.Key, region, 
			"failed to create cloudlet").WithDetails(err.Error())
	}

	return nil
}

func (s *cloudletService) ShowCloudlet(ctx context.Context, region string, cloudletKey domain.CloudletKey) (*domain.Cloudlet, error) {
	if err := s.validateCloudletKey(cloudletKey); err != nil {
		return nil, err
	}

	if region == "" {
		return nil, domain.ErrMissingRegion
	}

	cloudlet, err := s.cloudletRepo.ShowCloudlet(ctx, region, cloudletKey)
	if err != nil {
		if domain.IsNotFoundError(err) {
			return nil, domain.NewCloudletError(domain.ErrResourceNotFound, "ShowCloudlet", cloudletKey, region, 
				"cloudlet does not exist")
		}
		return nil, domain.NewCloudletError(domain.ErrInternalError, "ShowCloudlet", cloudletKey, region, 
			"failed to retrieve cloudlet").WithDetails(err.Error())
	}

	return cloudlet, nil
}

func (s *cloudletService) ShowCloudlets(ctx context.Context, region string, cloudletKey domain.CloudletKey) ([]domain.Cloudlet, error) {
	if region == "" {
		return nil, domain.ErrMissingRegion
	}

	cloudlets, err := s.cloudletRepo.ShowCloudlets(ctx, region, cloudletKey)
	if err != nil {
		return nil, domain.NewCloudletError(domain.ErrInternalError, "ShowCloudlets", cloudletKey, region, 
			"failed to list cloudlets").WithDetails(err.Error())
	}

	return cloudlets, nil
}

func (s *cloudletService) DeleteCloudlet(ctx context.Context, region string, cloudletKey domain.CloudletKey) error {
	if err := s.validateCloudletKey(cloudletKey); err != nil {
		return err
	}

	if region == "" {
		return domain.ErrMissingRegion
	}

	if err := s.cloudletRepo.DeleteCloudlet(ctx, region, cloudletKey); err != nil {
		if domain.IsNotFoundError(err) {
			return domain.NewCloudletError(domain.ErrResourceNotFound, "DeleteCloudlet", cloudletKey, region, 
				"cloudlet does not exist")
		}
		return domain.NewCloudletError(domain.ErrInternalError, "DeleteCloudlet", cloudletKey, region, 
			"failed to delete cloudlet").WithDetails(err.Error())
	}

	return nil
}

// validateCloudlet performs business logic validation on a cloudlet
func (s *cloudletService) validateCloudlet(cloudlet *domain.Cloudlet) error {
	if cloudlet == nil {
		return domain.NewDomainError(domain.ErrValidationFailed, "cloudlet cannot be nil")
	}

	if err := s.validateCloudletKey(cloudlet.Key); err != nil {
		return err
	}

	return nil
}

// validateCloudletKey validates a cloudlet key
func (s *cloudletService) validateCloudletKey(key domain.CloudletKey) error {
	if strings.TrimSpace(key.Organization) == "" {
		return domain.ErrInvalidCloudletKey.WithDetails("organization is required")
	}

	if strings.TrimSpace(key.Name) == "" {
		return domain.ErrInvalidCloudletKey.WithDetails("name is required")
	}

	return nil
}
