package logic

import (
	"errors"
	"fmt"
	"fusenapi/constants"
	"fusenapi/model/gmodel"
	"fusenapi/utils/auth"
	"fusenapi/utils/basic"
	"fusenapi/utils/order"
	"gorm.io/gorm"
	"strings"
	"time"

	"context"

	"fusenapi/server/orders/internal/svc"
	"fusenapi/server/orders/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type GetOrderDetailLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetOrderDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetOrderDetailLogic {
	return &GetOrderDetailLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetOrderDetailLogic) GetOrderDetail(req *types.GetOrderDetailReq, userinfo *auth.UserInfo) (resp *basic.Response) {
	//查询订单信息
	orderModel := gmodel.NewFsOrderModel(l.svcCtx.MysqlConn)
	orderInfo, err := orderModel.FindOneBySn(l.ctx, userinfo.UserId, req.Sn)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "the order is not exists")
		}
		logx.Error(err)
		return resp.SetStatus(basic.CodeServiceErr, "failed to get order info")
	}
	//获取订单详情
	orderDetailModel := gmodel.NewFsOrderDetailModel(l.svcCtx.MysqlConn)
	orderDetails, err := orderDetailModel.GetOrderDetailsByOrderId(l.ctx, orderInfo.Id)
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get order details")
	}
	if len(orderDetails) == 0 {
		return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "order details is empty")
	}
	optionalIds := make([]int64, 0, len(orderDetails))
	productIds := make([]int64, 0, len(orderDetails))
	orderDetailTemplateIds := make([]int64, 0, len(orderDetails))
	for _, v := range orderDetails {
		optionalIds = append(optionalIds, *v.OptionalId)
		productIds = append(productIds, *v.ProductId)
		orderDetailTemplateIds = append(orderDetailTemplateIds, *v.OrderDetailTemplateId)
	}
	//获取配件列表
	productModel3dModel := gmodel.NewFsProductModel3dModel(l.svcCtx.MysqlConn)
	productModel3dList, err := productModel3dModel.GetAllByIds(l.ctx, optionalIds, "")
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get product 3d models")
	}
	mapModel3d := make(map[int64]int)
	for k, v := range productModel3dList {
		mapModel3d[v.Id] = k
	}
	//获取产品列表
	productModel := gmodel.NewFsProductModel(l.svcCtx.MysqlConn)
	productList, err := productModel.GetProductListByIds(l.ctx, productIds, "")
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get order product list")
	}
	mapProduct := make(map[int64]int)
	for k, v := range productList {
		mapProduct[v.Id] = k
	}
	//获取模板列表
	orderDetailTemplateModel := gmodel.NewFsOrderDetailTemplateModel(l.svcCtx.MysqlConn)
	detailTemplateList, err := orderDetailTemplateModel.GetListByIds(l.ctx, orderDetailTemplateIds)
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get order detail template list")
	}
	sizeIds := make([]int64, 0, len(detailTemplateList))
	mapDetailTemplate := make(map[int64]int)
	for k, v := range detailTemplateList {
		sizeIds = append(sizeIds, *v.SizeId)
		mapDetailTemplate[v.Id] = k
	}
	//获取尺寸信息
	productSizeModel := gmodel.NewFsProductSizeModel(l.svcCtx.MysqlConn)
	productSizeList, err := productSizeModel.GetAllByIds(l.ctx, sizeIds, "")
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get product size list")
	}
	mapProductSize := make(map[int64]int)
	for k, v := range productSizeList {
		mapProductSize[v.Id] = k
	}
	//获取支付信息
	payModel := gmodel.NewFsPayModel(l.svcCtx.MysqlConn)
	payList, err := payModel.GetOrderPayList(l.ctx, *orderInfo.Sn, 1, 0)
	if err != nil {
		logx.Error(err)
		return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get pay records")
	}
	mapPay := make(map[int64]int) //pay_stat作为索引
	for k, v := range payList {
		mapPay[*v.PayStage] = k
	}
	//处理订单状态
	orderStatus := order.GetOrderStatus(constants.Order(*orderInfo.Status), constants.DeliveryMethod(*orderInfo.DeliveryMethod))
	//组装
	productListRsp := make([]*types.Product, 0, len(orderDetails))
	for _, v := range orderDetails {
		cover := *v.Cover
		if req.Size >= 200 {
			coverSlice := strings.Split(".", *v.Cover)
			if len(coverSlice) >= 2 {
				cover = fmt.Sprintf("%s_%d.%s", coverSlice[0], req.Size, coverSlice[1])
			}
		}
		Fitting := ""
		if model3dIndex, ok := mapModel3d[*v.OptionalId]; ok {
			Fitting = *productModel3dList[model3dIndex].Title
		}
		pcBox := int64(0)
		Size := ""
		if detailTemplateIndex, ok := mapDetailTemplate[*v.OrderDetailTemplateId]; ok {
			pcBox = *v.BuyNum / *detailTemplateList[detailTemplateIndex].EachBoxNum
			if sizeIndex, ok := mapProductSize[*detailTemplateList[detailTemplateIndex].SizeId]; ok {
				Size = *productSizeList[sizeIndex].Capacity
			}
		}
		Title := ""
		if productIndex, ok := mapProduct[*v.ProductId]; ok {
			Title = *productList[productIndex].Title
		}
		productListRsp = append(productListRsp, &types.Product{
			Cover:                 cover,
			Fitting:               Fitting,
			OptionPrice:           *v.OptionPrice,
			OrderDetailTemplateId: *v.OrderDetailTemplateId,
			OrderId:               *v.OrderId,
			Pcs:                   *v.BuyNum,
			PcsBox:                pcBox,
			Price:                 *v.Amount,
			ProductId:             *v.ProductId,
			Size:                  Size,
			Title:                 Title,
		})
	}
	data := types.GetOrderDetailRsp{
		Id:             orderInfo.Id,
		TotalAmount:    *orderInfo.TotalAmount,
		Deposit:        *orderInfo.TotalAmount / 2,
		Remaining:      *orderInfo.TotalAmount - *orderInfo.TotalAmount/2,
		IsPayCompleted: *orderInfo.IsPayCompleted,
		DeliveryMethod: *orderInfo.DeliveryMethod,
		Sn:             *orderInfo.Sn,
		Status:         int64(orderStatus),
		Ctime:          time.Unix(*orderInfo.Ctime, 0).Format("2006-01-02 15:04:05"),
		Address:        nil,
		ProductList:    productListRsp,
	}
	//直接邮寄才有地址信息
	if *orderInfo.DeliveryMethod == int64(constants.DELIVERY_METHOD_ADDRESS) {
		addressInfo, err := gmodel.NewFsAddressModel(l.svcCtx.MysqlConn).GetOne(l.ctx, *orderInfo.AddressId, userinfo.UserId)
		if err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "address not exists")
			}
			logx.Error(err)
			return resp.SetStatusWithMessage(basic.CodeServiceErr, "failed to get address info")
		}
		data.Address = &types.Address{
			Id:        addressInfo.Id,
			UserId:    *addressInfo.UserId,
			Name:      *addressInfo.Name,
			FirstName: *addressInfo.FirstName,
			LastName:  *addressInfo.LastName,
			Mobile:    *addressInfo.Mobile,
			Street:    *addressInfo.Street,
			Suite:     *addressInfo.Suite,
			City:      *addressInfo.City,
			State:     *addressInfo.State,
			Country:   *addressInfo.Country,
			ZipCode:   *addressInfo.ZipCode,
			Status:    *addressInfo.Status,
			IsDefault: *addressInfo.IsDefault,
		}
	}
	data.PayInfo = &types.PayInfo{}
	//首款
	if payIndex, ok := mapPay[1]; ok {
		data.PayInfo.Deposit = types.Deposit{
			Method:  *payList[payIndex].Brand,
			TransNo: *payList[payIndex].TradeNo,
		}
	}
	//尾款
	if payIndex, ok := mapPay[2]; ok {
		data.PayInfo.Final = types.Deposit{
			Method:  *payList[payIndex].Brand,
			TransNo: *payList[payIndex].TradeNo,
		}
	}
	return resp.SetStatusWithMessage(basic.CodeOK, "success", data)
}