package api

import (
	"net/http"

	"github.com/tidbcloud/account/central/events/publish"

	"github.com/tidbcloud/account/internel/dto"
	"github.com/tidbcloud/account/internel/svc/msp"
	orgsvc "github.com/tidbcloud/account/internel/svc/org"

	"github.com/duke-git/lancet/slice"
	"github.com/tidbcloud/account/internel/dao/entity"

	"github.com/tidbcloud/tiinf/monitor/tilog"
	"go.uber.org/zap"

	"github.com/gin-gonic/gin"
	"github.com/tidbcloud/account/admin/forms"
)

// @Summary GetCustomersByMspId
// @tags msp
// @Accept  json
// @Produce json
// @Param org_id path string true "org_id"
// @Success 200 {object} []forms.PartnerCustomer
// @Router /partner/msp/{org_id}/customers [get]
func GetCustomersByMspId(c *gin.Context) {
	ctx := c.Request.Context()

	req := forms.GetOrgIDReq{}
	if err := c.ShouldBindUri(&req); err != nil {
		tilog.Error(ctx, "GetCustomers err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusBadRequest)
		return
	}
	svc, _ := msp.GetMspSvc()

	resMap, err := svc.GetCustomerByMspID(ctx, entity.ID(req.OrgID))
	if err != nil {
		tilog.Error(ctx, "GetCustomerByMspID err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusInternalServerError)
		return
	}
	var arr []forms.PartnerCustomer
	for customer, customerOrg := range resMap {
		obj := forms.PartnerCustomer{
			Name:          customerOrg.Name,
			Email:         customerOrg.Email,
			PartnerOrgId:  customer.PartnerOrgID.Uint64(),
			CustomerOrgId: customer.CustomerOrgID.Uint64(),
			Status:        string(customer.Status),
			PartnerType:   customer.PartnerType,
			ExpiredAt:     customer.ExpiredAt,
			EffectedAt:    customer.EffectedAt,
		}

		arr = append(arr, obj)
	}
	err = slice.SortByField(arr, "CustomerOrgId", "asc")

	if err != nil {
		tilog.Error(ctx, "SortByField fail", zap.Error(err))
	}
	Success(c, arr, http.StatusOK)
}

// @Summary GetCustomersByPartnerId
// @tags msp
// @Accept  json
// @Produce json
// @Param org_id path string true "org_id"
// @Success 200 {object} []forms.PartnerCustomer
// @Router /partner/{org_id}/customers [get]
func GetCustomersByPartnerId(c *gin.Context) {
	ctx := c.Request.Context()

	req := forms.GetOrgIDReq{}
	if err := c.ShouldBindUri(&req); err != nil {
		tilog.Error(ctx, "GetCustomers err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusBadRequest)
		return
	}
	svc, _ := msp.GetMspSvc()

	resMap, err := svc.GetCustomerByMspID(ctx, entity.ID(req.OrgID))
	if err != nil {
		tilog.Error(ctx, "GetCustomerByMspID err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusInternalServerError)
		return
	}
	var arr []forms.PartnerCustomer
	for customer, customerOrg := range resMap {
		obj := forms.PartnerCustomer{
			Name:          customerOrg.Name,
			Email:         customerOrg.Email,
			PartnerOrgId:  customer.PartnerOrgID.Uint64(),
			CustomerOrgId: customer.CustomerOrgID.Uint64(),
			Status:        string(customer.Status),
			PartnerType:   customer.PartnerType,
			ExpiredAt:     customer.ExpiredAt,
			EffectedAt:    customer.EffectedAt,
		}

		arr = append(arr, obj)
	}
	err = slice.SortByField(arr, "CustomerOrgId", "asc")

	if err != nil {
		tilog.Error(ctx, "SortByField fail", zap.Error(err))
	}
	Success(c, arr, http.StatusOK)
}

// @Summary GetCustomerByOrgId
// @tags msp
// @Accept  json
// @Produce json
// @Param org_id path string true "org_id"
// @Success 200 {object} forms.PartnerCustomer
// @Router /partner/partner-customer/{org_id} [get]
func GetCustomerByCustomerOrgId(c *gin.Context) {

	ctx := c.Request.Context()

	req := forms.GetOrgIDReq{}
	if err := c.ShouldBindUri(&req); err != nil {
		tilog.Error(ctx, "GetCustomerByCustomerOrgId err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusBadRequest)
		return
	}
	mspSvc, _ := msp.GetMspSvc()

	customer, err := mspSvc.GetCustomerByCustomerID(ctx, entity.ID(req.OrgID))
	if err != nil {
		tilog.Error(ctx, "GetCustomerByCustomerID err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusInternalServerError)
		return
	}
	if customer == nil {
		Success(c, nil, http.StatusOK)
		return
	}
	orgSvc, _ := orgsvc.GetOrgSvc()
	org, err := orgSvc.GetOrgByID(ctx, req.OrgID)
	if err != nil {
		tilog.Error(ctx, "GetOrgByID err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	obj := forms.PartnerCustomer{
		Name:          org.Name,
		Email:         org.Email,
		PartnerOrgId:  customer.PartnerOrgID.Uint64(),
		CustomerOrgId: customer.CustomerOrgID.Uint64(),
		Status:        string(customer.Status),
		PartnerType:   customer.PartnerType,
		ExpiredAt:     customer.ExpiredAt,
		EffectedAt:    customer.EffectedAt,
	}

	Success(c, obj, http.StatusOK)
}

// @Summary CreateCustomer
// @tags msp
// @Accept  json
// @Produce json
// @Param msp body forms.PartnerCustomer true "CreateCustomer"
// @Success 200 {object} forms.EmptyResponse
// @Router /partner/partner-customer/create [post]
func CreateCustomer(c *gin.Context) {
	ctx := c.Request.Context()
	req := forms.PartnerCustomer{}
	if err := c.ShouldBindJSON(&req); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}
	//email, _ := GetUserEmail(c)
	tilog.Info(ctx, "CreateCustomer", zap.Any("req", req))
	svc, _ := msp.GetMspSvc()

	mspCustomer := &entity.PartnerCustomer{
		PartnerOrgID:  entity.ID(req.PartnerOrgId),
		CustomerOrgID: entity.ID(req.CustomerOrgId),
		EffectedAt:    req.EffectedAt,
		ExpiredAt:     req.ExpiredAt,
		PartnerType:   req.PartnerType,
		Status:        entity.Pending}

	err := svc.CreateCustomer(ctx, mspCustomer, true)
	if err != nil {
		tilog.Error(ctx, "CreateCustomer err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusBadRequest)
		return
	}

	if err := publish.PublishOrgEvent(ctx, dto.OrgEventData{OrgId: mspCustomer.CustomerOrgID.Uint64(), OrgEventType: entity.EntityEventTypeSchedule}); err != nil {
		tilog.Error(ctx, "PublishOrgEvent err when CreateCustomer", zap.Any("CustomerOrgID", mspCustomer.CustomerOrgID.Uint64()), zap.Error(err))
		Fail(c, nil, http.StatusInternalServerError)
	}
	tilog.Info(ctx, "CreateCustomer  success", zap.Any("mspCustomer", mspCustomer))
	Success(c, nil, http.StatusOK)
}

// @Summary DeleteCustomer
// @tags msp
// @Accept  json
// @Produce json
// @Param msp body forms.PartnerCustomer true "DeleteCustomer"
// @Success 200 {object} forms.EmptyResponse
// @Router /partner/partner-customer/delete [delete]
func DeleteCustomer(c *gin.Context) {
	ctx := c.Request.Context()
	req := forms.PartnerCustomer{}
	//req := forms.DeleteCustomerReq{}
	if err := c.ShouldBindJSON(&req); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}

	tilog.Info(ctx, "DeleteCustomer", zap.Any("req", req))
	svc, err := msp.GetMspSvc()
	if err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	mspCustomer := entity.PartnerCustomer{PartnerOrgID: entity.ID(req.PartnerOrgId), CustomerOrgID: entity.ID(req.CustomerOrgId), Status: entity.Delete}
	err = svc.DeleteCustomer(ctx, mspCustomer)
	if err != nil {
		tilog.Error(ctx, "DeleteCustomer err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	//if err := events.PublishCreateTenantEvent(ctx, mspOrg.ID.Uint64()); err != nil {
	//	tilog.Error(ctx, "PublishCreateTenantEvent err", zap.Any("TenantID", mspOrg.ID.Uint64()), zap.Error(err))
	//}
	tilog.Info(ctx, "DeleteCustomer  success", zap.Any("mspCustomer", mspCustomer))
	Success(c, nil, http.StatusOK)
}

// @Summary CancelCustomer
// @tags msp
// @Accept  json
// @Produce json
// @Param msp body forms.PartnerCustomer true "PartnerCustomer"
// @Success 200 {object} forms.EmptyResponse
// @Router /partner/partner-customer/cancel [post]
func CancelCustomer(c *gin.Context) {
	ctx := c.Request.Context()
	req := forms.PartnerCustomer{}
	//req := forms.DeleteCustomerReq{}
	if err := c.ShouldBindJSON(&req); err != nil {
		Fail(c, err, http.StatusBadRequest)
		return
	}

	tilog.Info(ctx, "CancelCustomer", zap.Any("req", req))
	svc, err := msp.GetMspSvc()
	if err != nil {
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	mspCustomer := entity.PartnerCustomer{PartnerOrgID: entity.ID(req.PartnerOrgId), CustomerOrgID: entity.ID(req.CustomerOrgId)}
	err = svc.CancelCustomer(ctx, mspCustomer)
	if err != nil {
		tilog.Error(ctx, "DeleteCustomer err", zap.Any("req", req), zap.Error(err))
		Fail(c, err, http.StatusInternalServerError)
		return
	}

	if err := publish.PublishOrgEvent(ctx, dto.OrgEventData{OrgId: mspCustomer.CustomerOrgID.Uint64(), OrgEventType: entity.EntityEventTypeScheduleCancel}); err != nil {
		tilog.Error(ctx, "PublishOrgEvent err when CancelCustomer", zap.Any("mspCustomer", mspCustomer.CustomerOrgID.Uint64()), zap.Error(err))

		Fail(c, err, http.StatusInternalServerError)
	}
	tilog.Info(ctx, "CancelCustomer  success", zap.Any("mspCustomer", mspCustomer))
	Success(c, nil, http.StatusOK)
}
