package msp

import (
	"context"

	"github.com/tidbcloud/tiinf/errs"

	"github.com/tidbcloud/account/internel/dao/entity"
	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

type MspCustomerFilter struct {
	PartnerOrgIDs  []entity.ID
	CustomerOrgIDs []entity.ID
	Status         []entity.EntityStatus
	PartnerTypes   []entity.PartnerType
}

func (d *MspDao) GetCustomerByCustomerID(ctx context.Context, tx *gorm.DB, orgID entity.ID) (*entity.PartnerCustomer, error) {
	var mspCustomer entity.PartnerCustomer
	err := entity.NewPartnerCustomerQuerySet(tx).CustomerOrgIDEq(orgID).One(&mspCustomer)

	if err != nil && err != gorm.ErrRecordNotFound {
		tilog.Error(ctx, "MspCustomerDao GetCustomerByCustomerID err: ", zap.Any("mspCustomer: ", mspCustomer))
		return nil, err
	}
	if err == gorm.ErrRecordNotFound {
		tilog.Info(ctx, "MspCustomerDao GetCustomerByCustomerID is nil: ", zap.Any("mspCustomer: ", mspCustomer))
		return nil, nil
	}
	tilog.Info(ctx, "MspCustomerDao GetMspCustomerByMspID success: ", zap.Any("mspCustomer: ", mspCustomer))
	return &mspCustomer, nil
}

func (d *MspDao) GetCustomerByMspID(ctx context.Context, tx *gorm.DB, orgID entity.ID) ([]entity.PartnerCustomer, error) {
	var mspCustomer []entity.PartnerCustomer
	err := entity.NewPartnerCustomerQuerySet(tx).PartnerOrgIDEq(orgID).All(&mspCustomer)

	if err != nil {
		return nil, err
	}
	tilog.Info(ctx, "MspCustomerDao GetMspCustomerByMspID success: ", zap.Any("mspCustomer: ", mspCustomer))
	return mspCustomer, nil
}

func (d *MspDao) GetCustomerIdsByMspID(ctx context.Context, tx *gorm.DB, orgID entity.ID) ([]uint64, error) {
	var mspCustomers []entity.PartnerCustomer
	var ids []uint64

	//tx.Model(&entity.PartnerCustomer{}).Select("customer_org_id").Find(&ids)
	err := entity.NewPartnerCustomerQuerySet(tx).Select(entity.PartnerCustomerDBSchema.CustomerOrgID).PartnerOrgIDEq(orgID).All(&mspCustomers)

	if err != nil && err != gorm.ErrRecordNotFound {
		tilog.Error(ctx, "GetCustomerIdsByMspID fail: ", zap.Error(err))
		return nil, err
	}
	for _, m := range mspCustomers {
		ids = append(ids, m.CustomerOrgID.Uint64())
	}
	tilog.Info(ctx, "MspCustomerDao GetMspCustomerByMspID success: ", zap.Any("mspCustomers: ", ids))
	return ids, nil
}

func (d *MspDao) CreateMspCustomer(ctx context.Context, tx *gorm.DB, mspOrgConfig *entity.PartnerCustomer) error {
	err := tx.Create(mspOrgConfig).Error
	if err != nil {
		return err
	}
	tilog.Info(ctx, "MspCustomerDao CreateMspCustomer success: ", zap.Any("mspOrgConfig: ", mspOrgConfig))

	return nil
}

func (d *MspDao) UpdateMspCustomer(ctx context.Context, tx *gorm.DB, mspCustomer entity.PartnerCustomer) error {
	updater := entity.NewPartnerCustomerQuerySet(tx).IDEq(mspCustomer.ID).GetUpdater()

	if mspCustomer.PartnerOrgID != 0 {
		updater.SetPartnerOrgID(mspCustomer.PartnerOrgID)
	}
	if mspCustomer.CustomerOrgID != 0 {
		updater.SetCustomerOrgID(mspCustomer.CustomerOrgID)
	}
	if mspCustomer.Status != "" {
		updater.SetStatus(mspCustomer.Status)
	}
	if mspCustomer.EffectedAt != nil {
		updater.SetEffectedAt(mspCustomer.EffectedAt)
	}
	if mspCustomer.ExpiredAt != nil {
		updater.SetExpiredAt(mspCustomer.ExpiredAt)
	}

	err := updater.Update()

	if err != nil {
		return err
	}
	return nil
}
func (d *MspDao) DeleteCustomer(ctx context.Context, tx *gorm.DB, mspCustomer entity.PartnerCustomer) error {
	err := entity.NewPartnerCustomerQuerySet(tx).PartnerOrgIDEq(mspCustomer.PartnerOrgID).CustomerOrgIDEq(mspCustomer.CustomerOrgID).Delete()

	if err != nil {
		return err
	}
	tilog.Info(ctx, "MspCustomerDao DeleteCustomer success: ", zap.Any("mspCustomer: ", mspCustomer))
	return nil
}

func (d *MspDao) ListCustomers(ctx context.Context, tx *gorm.DB, filter MspCustomerFilter) ([]entity.PartnerCustomer, error) {
	var objs []entity.PartnerCustomer

	if len(filter.PartnerOrgIDs) == 0 && len(filter.CustomerOrgIDs) == 0 && len(filter.Status) == 0 && len(filter.PartnerTypes) == 0 {
		tilog.Info(ctx, "ListCustomers  param  is nil ", zap.Error(nil))
		return nil, errs.NewBadRequest("should not be empty", nil)
	}

	qs := entity.NewPartnerCustomerQuerySet(tx)

	if len(filter.PartnerOrgIDs) > 0 {
		qs = qs.PartnerOrgIDIn(filter.PartnerOrgIDs...)
	}
	if len(filter.CustomerOrgIDs) > 0 {
		qs = qs.CustomerOrgIDIn(filter.CustomerOrgIDs...)
	}
	if len(filter.Status) > 0 {
		qs = qs.StatusIn(filter.Status...)
	}
	if len(filter.PartnerTypes) > 0 {
		var types []string
		for _, p := range filter.PartnerTypes {
			types = append(types, string(p))
		}
		qs = qs.PartnerTypeIn(types...)
	}

	qs = qs.OrderDescByCreatedAt()
	err := qs.All(&objs)
	if err != nil && err != gorm.ErrRecordNotFound {
		tilog.Error(ctx, "ListCustomers fail", zap.Error(err))
		return nil, err
	}
	tilog.Info(ctx, "ListCustomers  success", zap.Any("filter", filter))
	return objs, nil
}
