package paid_order

import (
	"context"

	"github.com/UpmeshLTD/urus-aio/infrastructure/common"
	"github.com/UpmeshLTD/urus-aio/infrastructure/db/entities"
	"github.com/UpmeshLTD/urus-aio/paid-order/db/gormdb"
)

type Repository interface {
	GetList(ctx context.Context, params *entities.GetPaidOrdersParams) ([]*entities.PaidOrder, int64, error)
	Get(ctx context.Context, params *entities.GetPaidOrderParams) (*entities.PaidOrder, error)
	GetByCartID(ctx context.Context, cartID string) ([]*entities.PaidOrder, error)
	GetCount(ctx context.Context, params *entities.GetPaidOrdersParams) (int64, error)
	CreateBatch(ctx context.Context, entities []*entities.PaidOrder) error
	Update(ctx context.Context, id string, maps map[string]interface{}) error
	UpdateBatch(ctx context.Context, ids []string, maps map[string]interface{}) error
	Delete(ctx context.Context, cartId string) error
}

type repositoryImpl struct {
	db gormdb.GormDB
}

func NewRepository(db gormdb.GormDB) Repository {
	return &repositoryImpl{
		db: db,
	}
}

func (r repositoryImpl) GetList(ctx context.Context, params *entities.GetPaidOrdersParams) ([]*entities.PaidOrder, int64, error) {
	var (
		total      int64
		results    []*entities.PaidOrder
		pagination = params.Pagination
		builder    = r.db.DB().Model(&entities.PaidOrder{})
	)

	if params.IDs != nil && len(params.IDs) > 0 {
		builder = builder.Where("id IN ?", params.IDs)
	}

	if params.WorkspaceID != nil {
		builder = builder.Where("workspace_id = ? ", params.WorkspaceID)
	}

	if params.CartIDs != nil && len(params.CartIDs) > 0 {
		builder = builder.Where("cart_id IN ?", params.CartIDs)
	}

	if len(params.FulfillmentIDs) > 0 {
		builder = builder.Where("fulfillment_id in ?", params.FulfillmentIDs)
	}

	if params.OnlyDraft {
		builder = builder.Where("fulfillment_id is not null AND shipment_id is null")
	}

	if params.HasFulfillment != nil {
		if *params.HasFulfillment {
			builder = builder.Where("fulfillment_id IS NOT NULL")
		} else {
			builder = builder.Where("fulfillment_id IS NULL")
		}
	}

	if params.HasArrangedShip != nil {
		if *params.HasArrangedShip {
			builder = builder.Where("shipment_id IS NOT NULL")
		} else {
			builder = builder.Where("shipment_id IS NULL")
		}
	}

	if params.Fields != nil {
		builder = builder.Select(*params.Fields)
	}

	if pagination != nil {
		builder.Scopes(common.Paginate(results, pagination, builder))
	}

	if err := builder.Find(&results).Error; err != nil {
		return nil, 0, err
	}

	if pagination == nil {
		total = int64(len(results))
	} else {
		total = pagination.Total
	}

	return results, total, nil
}

func (r repositoryImpl) CreateBatch(ctx context.Context, paidOrders []*entities.PaidOrder) error {
	return r.db.DB().CreateInBatches(paidOrders, len(paidOrders)).Error
}

func (r repositoryImpl) Get(ctx context.Context, params *entities.GetPaidOrderParams) (*entities.PaidOrder, error) {
	var paidOrder *entities.PaidOrder
	var builder = r.db.DB().Model(&entities.PaidOrder{})

	if params.ID != "" {
		builder = builder.Where("id = ?", params.ID)
	}

	if params.CartID != "" {
		builder = builder.Where("cart_id = ?", params.CartID)

		if params.ShippingGroupID == nil {
			builder = builder.Where("shipping_group_id is NULL")
		} else {
			builder = builder.Where("shipping_group_id = ?", params.ShippingGroupID)
		}
	}

	if err := builder.First(&paidOrder).Error; err != nil {
		return nil, err
	}
	return paidOrder, nil
}

func (r repositoryImpl) GetByCartID(ctx context.Context, cartID string) ([]*entities.PaidOrder, error) {
	var pos []*entities.PaidOrder
	if err := r.db.DB().Model(&entities.PaidOrder{}).Where("cart_id = ?", cartID).Find(&pos).Error; err != nil {
		return nil, err
	}
	return pos, nil
}

func (r repositoryImpl) GetCount(ctx context.Context, params *entities.GetPaidOrdersParams) (int64, error) {
	var count int64
	builder := r.db.DB().Model(&entities.PaidOrder{})

	if params.IDs != nil && len(params.IDs) > 0 {
		builder = builder.Where("id IN ?", params.IDs)
	}

	if params.WorkspaceID != nil {
		builder = builder.Where("workspace_id = ? ", params.WorkspaceID)
	}

	if params.OnlyDraft {
		builder = builder.Where("fulfillment_id is not null AND shipment_id is null")
	}

	if err := builder.Count(&count).Error; err != nil {
		return 0, err
	}
	return count, nil
}

func (r repositoryImpl) Update(ctx context.Context, id string, maps map[string]interface{}) error {
	return r.db.DB().Model(&entities.PaidOrder{}).Where("id = ?", id).Updates(maps).Error
}

func (r repositoryImpl) UpdateBatch(ctx context.Context, ids []string, maps map[string]interface{}) error {
	return r.db.DB().Model(&entities.PaidOrder{}).Where("id in ?", ids).Updates(maps).Error
}

func (r repositoryImpl) Delete(ctx context.Context, cartId string) error {
	return r.db.DB().Where("cart_id = ?", cartId).Delete(&entities.PaidOrder{}).Error
}
