package delivery_address

import (
	"context"
	"github.com/UpmeshLTD/urus-aio/infrastructure/db/entities"
	"github.com/UpmeshLTD/urus-aio/paid-order/db/gormdb"
	"github.com/UpmeshLTD/urus-aio/paid-order/domain/address"
	"github.com/UpmeshLTD/urus-aio/paid-order/domain/delivery_address_log"
	"github.com/UpmeshLTD/urus-aio/paid-order/service/transform"
	"gorm.io/gorm"
)

type Service interface {
	Create(ctx context.Context, entity *entities.DeliveryAddress) error
	Update(ctx context.Context, entity *entities.DeliveryAddress) error
	UpdatePatch(ctx context.Context, entity *entities.DeliveryAddress, params *entities.SaveDeliveryAddressParams) error
	Get(ctx context.Context, cartID string) (*entities.DeliveryAddress, error)
	GetList(ctx context.Context, cartIDs []string) ([]*entities.DeliveryAddress, error)
}

type serviceImpl struct {
	db                     gormdb.GormDB
	deliveryAddressRepo    Repository
	addressRepo            address.Repository
	deliveryAddressLogRepo delivery_address_log.Repository
}

func NewService(
	db gormdb.GormDB,
	deliveryAddressRepo Repository,
	addressRepo address.Repository,
	deliveryAddressLogRepo delivery_address_log.Repository,
) Service {
	return &serviceImpl{
		db:                     db,
		deliveryAddressRepo:    deliveryAddressRepo,
		addressRepo:            addressRepo,
		deliveryAddressLogRepo: deliveryAddressLogRepo,
	}
}

func (s *serviceImpl) Create(ctx context.Context, entity *entities.DeliveryAddress) error {
	// Create
	return s.db.DB().Transaction(func(tx *gorm.DB) error {
		a, err := s.addressRepo.Create(ctx, tx, &entity.Address)
		if err != nil {
			tx.Rollback()
			return err
		}
		entity.AddressID = a.ID.ToInt64()
		if err := s.deliveryAddressRepo.Create(ctx, tx, entity); err != nil {
			tx.Rollback()
			return err
		}
		return nil
	})
}

func (s *serviceImpl) Update(ctx context.Context, entity *entities.DeliveryAddress) error {
	if err := s.db.DB().Transaction(func(tx *gorm.DB) error {
		if err := s.addressRepo.Update(ctx, tx, entities.IDFromInt64(entity.AddressID), transform.DeliveryAddressEntityToAddressMaps(entity)); err != nil {
			tx.Rollback()
			return err
		}
		if err := s.deliveryAddressRepo.Update(ctx, tx, entity.CartID, transform.DeliveryAddressEntityToDeliveryAddressMaps(entity)); err != nil {
			tx.Rollback()
			return err
		}
		return nil
	}); err != nil {
		return err
	}
	return nil
}

func (s *serviceImpl) UpdatePatch(ctx context.Context, entity *entities.DeliveryAddress, params *entities.SaveDeliveryAddressParams) error {
	if err := s.db.DB().Transaction(func(tx *gorm.DB) error {
		if err := s.addressRepo.Update(ctx, tx, entities.IDFromInt64(entity.AddressID), transform.DeliveryAddressParamsToAddressMaps(params)); err != nil {
			tx.Rollback()
			return err
		}
		if err := s.deliveryAddressRepo.Update(ctx, tx, entity.CartID, transform.DeliveryAddressParamsToDeliveryAddressMaps(params)); err != nil {
			tx.Rollback()
			return err
		}
		return nil
	}); err != nil {
		return err
	}
	return nil
}

func (s *serviceImpl) Get(ctx context.Context, cartID string) (*entities.DeliveryAddress, error) {
	return s.deliveryAddressRepo.GetByCartID(ctx, s.db.DB(), cartID)
}

func (s *serviceImpl) GetList(ctx context.Context, cartIDs []string) ([]*entities.DeliveryAddress, error) {
	return s.deliveryAddressRepo.GetByCartIDs(ctx, s.db.DB(), cartIDs)
}
