package service

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/UpmeshLTD/urus-aio/infrastructure/db/entities"
	"github.com/UpmeshLTD/urus-aio/infrastructure/enums"
	gin2 "github.com/UpmeshLTD/urus-aio/infrastructure/server/transport/http/gin"
	"github.com/UpmeshLTD/urus-aio/shipment/server/http/dto"
	"github.com/UpmeshLTD/urus-aio/shipment/service/transform"
	"github.com/gin-gonic/gin"
	"github.com/mitchellh/mapstructure"
	"github.com/pkg/errors"
	"io/ioutil"
	"net/http"
	"net/url"
)

type iWebhook interface {
	NotifyStatusJTExpressTH(ctx *gin.Context)
	NotifyStatusJTExpressMY(ctx *gin.Context)
	NotifyStatusJTExpressSG(ctx *gin.Context)
	NotifyStatusKerryExpressTH(ctx *gin.Context)
	NotifyStatusFlashExpressTH(ctx *gin.Context)
	NotifyStatusFlashExpressPH(ctx *gin.Context)

	NotifyCourierFlashExpressTH(ctx *gin.Context)
	NotifyCourierFlashExpressPH(ctx *gin.Context)
}

// NotifyStatusJTExpressTH godoc
// @Summary Update shipment status webhook
// @Description Update shipment status webhook
// @Tags Shipment
// @Accept */*
// @Produce json
// @Param request body dto.NotifyStatusJTExpressTHRequest true "request"
// @Success 200 {object} dto.NotifyStatusJTExpressTHResponse
// @Router /webhook/jt-express/status [POST]
func (s *serviceImpl) NotifyStatusJTExpressTH(c *gin.Context) {
	body, err := c.GetRawData()
	if err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusJTExpressTH] Failed to get raw data",
			"requestURI", c.Request.RequestURI,
			"error", err,
		)
		gin2.ResponseBadRequest(c, errors.Wrap(err, "Failed to get raw data"))
		return
	}
	payload := string(body)

	s.logger.Infow("[Webhook][NotifyStatusJTExpressTH] Incoming request data",
		"requestURI", c.Request.RequestURI,
		"payload", payload,
	)

	req := &dto.NotifyStatusJTExpressTHRequest{}
	if err := json.Unmarshal(body, &req); err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusJTExpressTH] Failed to unmarshal json",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseBadRequest(c, errors.Wrap(err, "invalid json data"))
		return
	}

	logisticInterface, err := json.Marshal(req.LogisticInterface)
	if err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusJTExpressTH] Failed to marshal json",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseBadRequest(c, errors.New("invalid logistic_interface"))
		return
	}

	courierService, _ := s.externalShipmentFactory.Get(entities.CourierCodeJTExpressTH)
	if !courierService.IsValidWebhookRequest(map[string]interface{}{
		"eccompanyID": req.EccompanyID,
		"digest":      req.DataDigest,
		"payload":     string(logisticInterface),
	}) {
		s.logger.Warnw("[Webhook][NotifyStatusJTExpressTH] Authentication failed",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
		)
		gin2.ResponseBadRequest(c, errors.New("invalid digest"))
		return
	}

	data := &dto.NotifyStatusJTExpressTHRequestData{}
	if err := mapstructure.Decode(req.LogisticInterface, &data); err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusJTExpressTH] Failed to decode mapstructure",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseBadRequest(c, errors.New("invalid data"))
		return
	}

	if data.Traces == nil || len(data.Traces) == 0 {
		s.logger.Infow("[Webhook][NotifyStatusJTExpressTH] Empty traces list",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
		)
		gin2.ResponseBadRequest(c, errors.New("empty traces list"))
		return
	}

	shipmentEntity, err := s.shipmentDomain.GetByCourierTrackingID(c, data.BillCode)
	if err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusJTExpressTH] Failed to get shipment",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseInternalServerError(c, err)
		return
	}

	shipmentStatusLog := transform.NotifyStatusJTExpressTHRequestToShipmentStatusLogEntity(shipmentEntity, data)

	if err := s.webhookDomain.UpdateShipmentStatus(c, shipmentEntity, shipmentStatusLog); err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusJTExpressTH] Failed to update shipment status",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseSuccess(c, &dto.NotifyStatusJTExpressTHResponse{
			LogisticProviderID: data.LogisticProviderID,
			ResponseItems: dto.NotifyStatusJTExpressTHResponseItem{
				Success:      "false",
				Reason:       err.Error(),
				BillCode:     data.BillCode,
				TxLogisticID: data.TxLogisticID,
			},
		})
		return
	}

	gin2.ResponseSuccess(c, &dto.NotifyStatusJTExpressTHResponse{
		LogisticProviderID: data.LogisticProviderID,
		ResponseItems: dto.NotifyStatusJTExpressTHResponseItem{
			Success:      "true",
			Reason:       "",
			BillCode:     data.BillCode,
			TxLogisticID: data.TxLogisticID,
		},
	})
}

// NotifyStatusJTExpressMY godoc
// @Summary Update shipment status webhook
// @Description Update shipment status webhook
// @Tags Shipment
// @Accept */*
// @Produce json
// @Param request body dto.NotifyStatusJTExpressMYRequest true "request"
// @Success 200 {object} dto.NotifyStatusJTExpressMYResponse
// @Router /webhook/jt-express-my/status [POST]
func (s *serviceImpl) NotifyStatusJTExpressMY(c *gin.Context) {
	body, _ := ioutil.ReadAll(c.Request.Body)
	c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
	payload := string(body)

	s.logger.Infow("[Webhook][NotifyStatusJTExpressMY] Incoming request data",
		"requestURI", c.Request.RequestURI,
		"payload", payload,
	)

	req := &dto.NotifyStatusJTExpressMYRequest{}
	req.LogisticInterface, _ = url.QueryUnescape(c.Request.FormValue("logistics_interface"))
	req.DataDigest = c.Request.FormValue("data_digest")
	req.MsgType = c.Request.FormValue("msg_type")
	req.EccompanyID = c.Request.FormValue("eccompanyid")

	courierService, _ := s.externalShipmentFactory.Get(entities.CourierCodeJTExpressMY)
	if !courierService.IsValidWebhookRequest(map[string]interface{}{
		"eccompanyID": req.EccompanyID,
		"digest":      req.DataDigest,
		"payload":     req.LogisticInterface,
	}) {
		s.logger.Warnw("[Webhook][NotifyStatusJTExpressMY] Authentication failed",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
		)
		gin2.ResponseBadRequest(c, errors.New("invalid digest"))
		return
	}

	data := &dto.NotifyStatusJTExpressMYRequestData{}
	if err := json.Unmarshal([]byte(req.LogisticInterface), &data); err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusJTExpressMY] Failed to unmarshal LogisticInterface",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseBadRequest(c, errors.Wrap(err, "invalid logistic_interface"))
		return
	}

	if data.History == nil || len(data.History) == 0 {
		s.logger.Infow("[Webhook][NotifyStatusJTExpressMY] Empty history list",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
		)
		gin2.ResponseBadRequest(c, errors.New("empty history list"))
		return
	}

	shipmentEntity, err := s.shipmentDomain.GetByCourierTrackingID(c, data.BillCode)
	if err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusJTExpressMY] Failed to get shipment",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseInternalServerError(c, err)
		return
	}

	shipmentStatusLog := transform.NotifyStatusJTExpressMYRequestToShipmentStatusLogEntity(shipmentEntity, data)

	if err := s.webhookDomain.UpdateShipmentStatus(c, shipmentEntity, shipmentStatusLog); err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusJTExpressMY] Failed to update shipment status",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseSuccess(c, &dto.NotifyStatusJTExpressMYResponse{
			LogisticProviderID: s.config.GetShipmentProviderConfig().JTExpressMY.WebhookLogisticProviderID,
			ResponseItems: dto.NotifyStatusJTExpressMYResponseItem{
				Success:  "false",
				Reason:   err.Error(),
				BillCode: data.BillCode,
			},
		})
		return
	}

	gin2.ResponseSuccess(c, &dto.NotifyStatusJTExpressMYResponse{
		LogisticProviderID: s.config.GetShipmentProviderConfig().JTExpressMY.WebhookLogisticProviderID,
		ResponseItems: dto.NotifyStatusJTExpressMYResponseItem{
			Success:  "true",
			Reason:   "",
			BillCode: data.BillCode,
		},
	})
}

// NotifyStatusJTExpressSG godoc
// @Summary JTExpressSingaporeNotifyStatus webhook
// @Description JTExpressSingaporeNotifyStatus webhook
// @Tags Shipment
// @Accept */*
// @Produce json
// @Param request body dto.NotifyStatusJTExpressSGRequest true "request"
// @Success 200
// @Router /webhook/jt-express-sg/status [POST]
func (s *serviceImpl) NotifyStatusJTExpressSG(c *gin.Context) {
	requestID := c.Request.Header.Get("X-SimplyPost-Id")
	signature := c.Request.Header.Get("X-SimplyPost-Signature")

	body, err := c.GetRawData()
	if err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusJTExpressSG] Failed to get raw data",
			"requestURI", c.Request.RequestURI,
			"error", err,
		)
		gin2.ResponseBadRequest(c, errors.Wrap(err, "failed to get raw data"))
		return
	}
	payload := string(body)

	s.logger.Infow("[Webhook][NotifyStatusJTExpressSG] Incoming request data",
		"requestURI", c.Request.RequestURI,
		"payload", payload,
		"header", map[string]interface{}{
			"X-SimplyPost-Id":        requestID,
			"X-SimplyPost-Signature": signature,
		},
	)

	courierService, _ := s.externalShipmentFactory.Get(entities.CourierCodeJTExpressSG)
	if !courierService.IsValidWebhookRequest(map[string]interface{}{
		"requestID": requestID,
		"signature": signature,
	}) {
		gin2.ResponseUnauthorized(c, errors.New("invalid signature"))
		return
	}

	req := &dto.NotifyStatusJTExpressSGRequest{}
	if err := json.Unmarshal(body, &req); err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusJTExpressSG] Failed to unmarshal json",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseBadRequest(c, errors.Wrap(err, "invalid json data"))
		return
	}

	shipmentEntity, err := s.shipmentDomain.GetByCourierTrackingID(c, req.TrackingID)
	if err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusJTExpressSG] Failed to get shipment",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseInternalServerError(c, err)
		return
	}

	if shipmentEntity.Courier.Code != entities.CourierCodeJTExpressSG {
		s.logger.Warn("[Webhook][NotifyStatusJTExpressSG] Invalid courier",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
		)
		gin2.ResponseInternalServerError(c, errors.New("invalid courier"))
		return
	}

	shipmentStatusLog := transform.NotifyStatusJTExpressSGRequestToShipmentStatusLogEntity(shipmentEntity, req)
	if err := s.webhookDomain.UpdateShipmentStatus(c, shipmentEntity, shipmentStatusLog); err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusJTExpressSG] Failed to update shipment status",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseInternalServerError(c, errors.Wrap(err, "failed to update shipment status"))
		return
	}

	gin2.ResponseSuccess(c, req)
}

// NotifyStatusKerryExpressTH godoc
// @Summary NotifyStatusKerryExpressTH webhook
// @Description NotifyStatusKerryExpressTH webhook
// @Tags Shipment
// @Accept */*
// @Produce json
// @Param request body dto.NotifyStatusKerryExpressTHRequest true "request"
// @Success 200
// @Router /webhook/kerry-express-th/status [POST]
func (s *serviceImpl) NotifyStatusKerryExpressTH(c *gin.Context) {
	body, err := c.GetRawData()
	if err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusKerryExpressTH] Failed to get raw data",
			"requestURI", c.Request.RequestURI,
			"error", err,
		)
		gin2.ResponseBadRequest(c, errors.Wrap(err, "failed to get raw data"))
		return
	}
	payload := string(body)

	s.logger.Infow("[Webhook][NotifyStatusKerryExpressTH] Incoming request data",
		"requestURI", c.Request.RequestURI,
		"payload", payload,
	)

	req := &dto.NotifyStatusKerryExpressTHRequest{}
	if err := json.Unmarshal(body, &req); err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusKerryExpressTH] Failed to unmarshal json",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseBadRequest(c, errors.Wrap(err, "invalid json data"))
		return
	}

	shipmentEntity, err := s.shipmentDomain.GetByCourierTrackingID(c, req.TrackingID)
	if err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusKerryExpressTH] Failed to get shipment",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseInternalServerError(c, err)
		return
	}

	if shipmentEntity.Courier.Code != entities.CourierCodeKerryExpressTH {
		s.logger.Warn("[Webhook][NotifyStatusKerryExpressTH] Invalid courier",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
		)
		gin2.ResponseInternalServerError(c, errors.New("invalid courier"))
		return
	}

	shipmentStatusLog := transform.NotifyStatusKerryExpressTHRequestToShipmentStatusLogEntity(shipmentEntity, req)
	if err := s.webhookDomain.UpdateShipmentStatus(c, shipmentEntity, shipmentStatusLog); err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusJTExpressSG] Failed to update shipment status",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseInternalServerError(c, errors.Wrap(err, "failed to update shipment status"))
		return
	}

	gin2.ResponseSuccess(c, req)
}

// NotifyStatusFlashExpressTH godoc
// @Summary Update shipment status webhook
// @Description Update shipment status webhook
// @Tags Shipment
// @Accept */*
// @Produce json
// @Param request body dto.NotifyStatusFlashExpressRequest true "request"
// @Success 200 {object} dto.NotifyStatusFlashExpressSuccessResponse
// @Router /webhook/flash-express/status [POST]
func (s *serviceImpl) NotifyStatusFlashExpressTH(c *gin.Context) {
	body, err := c.GetRawData()
	if err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusFlashExpressTH] Failed to get raw data",
			"requestURI", c.Request.RequestURI,
			"error", err,
		)
		gin2.ResponseBadRequest(c, errors.Wrap(err, "Failed to get raw data"))
		return
	}
	payload := string(body)

	s.logger.Infow("[Webhook][NotifyStatusFlashExpressTH] Incoming request data",
		"requestURI", c.Request.RequestURI,
		"payload", payload,
	)

	req := &dto.NotifyStatusFlashExpressRequest{}
	if err := json.Unmarshal(body, &req); err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusFlashExpressTH] Failed to unmarshal json",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseBadRequest(c, errors.Wrap(err, "Invalid json data"))
		return
	}

	// Authentication
	signReq := &dto.FlashExpressWebhookSign{
		MchId:    req.MchId,
		NonceStr: req.NonceStr,
		Sign:     req.Sign,
	}
	jsonSignReqBytes, err := json.Marshal(signReq)
	if err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusFlashExpressTH] Failed to marshal json",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseInternalServerError(c, err)
		return
	}
	jsonSignReqObj := make(map[string]interface{})
	err = json.Unmarshal(jsonSignReqBytes, &jsonSignReqObj)
	if err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusFlashExpressTH] Failed to unmarshal json",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseInternalServerError(c, err)
		return
	}
	externalShipment, err := s.externalShipmentFactory.Get(entities.CourierCodeFlashExpressTH)
	if err != nil {
		gin2.ResponseInternalServerError(c, err)
		return
	}
	if !externalShipment.IsValidWebhookRequest(jsonSignReqObj) {
		s.logger.Warnw("[Webhook][NotifyStatusFlashExpressTH] Authentication failed",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
		)
		gin2.ResponseInternalServerError(c, errors.New("authentication failed"))
		return
	}

	shipmentEntity, err := s.shipmentDomain.GetByCourierTrackingID(c, req.Data.PNO)
	if err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusFlashExpressTH] Failed to get shipment",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseInternalServerError(c, err)
		return
	}

	shipmentStatusLog := transform.NotifyStatusFlashExpressRequestToShipmentStatusLogEntity(shipmentEntity, &req.Data)

	err = s.webhookDomain.UpdateShipmentStatus(c, shipmentEntity, shipmentStatusLog)
	if err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusFlashExpressTH] Failed to update shipment status",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		c.JSON(http.StatusInternalServerError, dto.NotifyStatusFlashExpressErrorResponse{
			ErrorCode: "0",
		})
		return
	}

	gin2.ResponseSuccess(c, &dto.NotifyStatusFlashExpressSuccessResponse{
		ErrorCode: "1",
		State:     "success",
	})
}

// NotifyStatusFlashExpressPH godoc
// @Summary Update shipment status webhook
// @Description Update shipment status webhook
// @Tags Shipment
// @Accept */*
// @Produce json
// @Param request body dto.NotifyStatusFlashExpressRequest true "request"
// @Success 200 {object} dto.NotifyStatusFlashExpressSuccessResponse
// @Router /webhook/flash-express-ph/status [POST]
func (s *serviceImpl) NotifyStatusFlashExpressPH(c *gin.Context) {
	body, err := c.GetRawData()
	if err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusFlashExpressPH] Failed to get raw data",
			"requestURI", c.Request.RequestURI,
			"error", err,
		)
		gin2.ResponseBadRequest(c, errors.Wrap(err, "failed to get raw data"))
		return
	}
	payload := string(body)

	s.logger.Infow("[Webhook][NotifyStatusFlashExpressPH] Incoming request data",
		"requestURI", c.Request.RequestURI,
		"payload", payload,
	)

	req := &dto.NotifyStatusFlashExpressRequest{}
	if err := json.Unmarshal(body, &req); err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusFlashExpressPH] Failed to unmarshal json",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseBadRequest(c, errors.Wrap(err, "invalid json data"))
		return
	}

	shipmentEntity, err := s.shipmentDomain.GetByCourierTrackingID(c, req.Data.PNO)
	if err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusFlashExpressPH] Failed to get shipment",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		gin2.ResponseInternalServerError(c, errors.Wrap(err, "failed to get shipment"))
		return
	}

	if shipmentEntity.Courier.Code != entities.CourierCodeFlashExpressPH {
		s.logger.Warnw("[Webhook][NotifyStatusFlashExpressPH] Invalid courier",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
		)
		gin2.ResponseInternalServerError(c, errors.New("invalid courier"))
		return
	}

	shipmentStatusLog := transform.NotifyStatusFlashExpressRequestToShipmentStatusLogEntity(shipmentEntity, &req.Data)
	if err := s.webhookDomain.UpdateShipmentStatus(c.Request.Context(), shipmentEntity, shipmentStatusLog); err != nil {
		s.logger.Errorw("[Webhook][NotifyStatusFlashExpressPH] Failed to update shipment status",
			"requestURI", c.Request.RequestURI,
			"payload", payload,
			"error", err,
		)
		c.JSON(http.StatusInternalServerError, dto.NotifyStatusFlashExpressErrorResponse{
			ErrorCode: "0",
		})
		return
	}

	gin2.ResponseSuccess(c, &dto.NotifyStatusFlashExpressSuccessResponse{
		ErrorCode: "1",
		State:     "success",
	})
}

/*- Notify Courier Status --------------------------------------------------------------------------------------------*/

// NotifyCourierFlashExpressTH godoc
// @Summary Update shipment courier webhook
// @Description Update shipment courier webhook
// @Tags Shipment
// @Accept */*
// @Produce json
// @Param request body dto.NotifyCourierFlashExpressRequest true "request"
// @Success 200 {object} dto.NotifyStatusFlashExpressSuccessResponse
// @Router /webhook/flash-express/courier [POST]
func (s *serviceImpl) NotifyCourierFlashExpressTH(c *gin.Context) {
	req := &dto.NotifyCourierFlashExpressRequest{}
	if err := gin2.BindData(c, &req, gin2.BindType_JSON); err != nil {
		gin2.ResponseBadRequest(c, err)
		return
	}

	// Authentication
	signReq := &dto.FlashExpressWebhookSign{
		MchId:    req.MchID,
		NonceStr: req.NonceStr,
		Sign:     req.Sign,
	}
	jsonSignReqBytes, err := json.Marshal(signReq)
	if err != nil {
		gin2.ResponseInternalServerError(c, err)
		return
	}
	jsonSignReqObj := make(map[string]interface{})
	err = json.Unmarshal(jsonSignReqBytes, &jsonSignReqObj)
	if err != nil {
		gin2.ResponseInternalServerError(c, err)
		return
	}
	externalShipment, err := s.externalShipmentFactory.Get(entities.CourierCodeFlashExpressTH)
	if err != nil {
		gin2.ResponseInternalServerError(c, err)
		return
	}
	if !externalShipment.IsValidWebhookRequest(jsonSignReqObj) {
		gin2.ResponseInternalServerError(c, errors.New("authentication failed"))
		return
	}

	// Update courier webhook status
	if req.Data.State == enums.FlashExpressCourierStatus.Cancelled {
		if err = s.webhookDomain.FlashExpressUpdateCourier(c, transform.NotifyCourierFlashExpressTHRequestToCourierLogParamsEntity(req)); err != nil {
			s.logger.Errorw("[Webhook][NotifyCourierFlashExpressTH] Failed to update courier", "error", err)
			gin2.ResponseSuccess(c, &dto.NotifyStatusFlashExpressErrorResponse{
				ErrorCode: "0",
			})
			return
		}
	} else if req.Data.State == enums.FlashExpressCourierStatus.PickedUp {
		go func() {
			flashPickup, err := s.flashExpressPickupDomain.GetByTicketPickupID(c, req.Data.TicketPickupID)
			if err != nil {
				s.logger.Errorw(fmt.Sprintf("[Webhook][NotifyCourierFlashExpressTH] Flash pickup %s not found", req.Data.TicketPickupID), "error", err)
				return
			}
			courier, err := s.courierDomain.GetCourier(c, &entities.GetCourierParams{Code: entities.CourierCodeFlashExpressTH})
			if err != nil {
				s.logger.Errorw(fmt.Sprintf("[Webhook][NotifyCourierFlashExpressTH] Courier %s not found", entities.CourierCodeFlashExpressTH), "error", err)
				return
			}
			sellerCourier, err := s.courierDomain.GetSellerCourier(c, flashPickup.WorkspaceId, courier.ID.ToInt64())
			if err != nil {
				s.logger.Errorw(fmt.Sprintf("[Webhook][NotifyCourierFlashExpressTH] Seller %s in Courier %d not found", flashPickup.WorkspaceId, courier.ID.ToInt64()), "error", err)
				return
			}
			s.shipmentDomain.NotifyFlashExpressCourier(c, sellerCourier, &flashPickup.PickupPoint)
		}()
	}

	gin2.ResponseSuccess(c, &dto.NotifyStatusFlashExpressSuccessResponse{
		ErrorCode: "1",
		State:     "success",
	})
}

// NotifyCourierFlashExpressPH godoc
// @Summary Update shipment courier webhook
// @Description Update shipment courier webhook
// @Tags Shipment
// @Accept */*
// @Produce json
// @Param request body dto.NotifyCourierFlashExpressRequest true "request"
// @Success 200 {object} dto.NotifyStatusFlashExpressSuccessResponse
// @Router /webhook/flash-express-ph/courier [POST]
func (s *serviceImpl) NotifyCourierFlashExpressPH(c *gin.Context) {
	req := &dto.NotifyCourierFlashExpressRequest{}
	if err := c.BindJSON(req); err != nil {
		gin2.ResponseBadRequest(c, err)
		return
	}

	// Update courier webhook status
	if req.Data.State == enums.FlashExpressCourierStatus.Cancelled {
		if err := s.webhookDomain.FlashExpressUpdateCourier(c, transform.NotifyCourierFlashExpressTHRequestToCourierLogParamsEntity(req)); err != nil {
			s.logger.Errorw("[Webhook][NotifyCourierFlashExpressPH] Failed to update courier", "error", err)
			gin2.ResponseSuccess(c, &dto.NotifyStatusFlashExpressErrorResponse{
				ErrorCode: "0",
			})
			return
		}
	} else if req.Data.State == enums.FlashExpressCourierStatus.PickedUp {
		go func() {
			flashPickup, err := s.flashExpressPickupDomain.GetByTicketPickupID(c, req.Data.TicketPickupID)
			if err != nil {
				s.logger.Errorw(fmt.Sprintf("[Webhook][NotifyCourierFlashExpressPH] Flash pickup %s not found", req.Data.TicketPickupID), "error", err)
				return
			}
			courier, err := s.courierDomain.GetCourier(c, &entities.GetCourierParams{Code: entities.CourierCodeFlashExpressPH})
			if err != nil {
				s.logger.Errorw(fmt.Sprintf("[Webhook][NotifyCourierFlashExpressPH] Courier %s not found", entities.CourierCodeFlashExpressPH), "error", err)
				return
			}
			sellerCourier, err := s.courierDomain.GetSellerCourier(c, flashPickup.WorkspaceId, courier.ID.ToInt64())
			if err != nil {
				s.logger.Errorw(fmt.Sprintf("[Webhook][NotifyCourierFlashExpressPH] Seller %s in Courier %d not found", flashPickup.WorkspaceId, courier.ID.ToInt64()), "error", err)
				return
			}
			s.shipmentDomain.NotifyFlashExpressCourier(c, sellerCourier, &flashPickup.PickupPoint)
		}()
	}

	gin2.ResponseSuccess(c, &dto.NotifyStatusFlashExpressSuccessResponse{
		ErrorCode: "1",
		State:     "success",
	})
}
