package service

import (
	"context"
	"errors"
	"fmt"
	log "github.com/sirupsen/logrus"
	"github.com/wechatpay-apiv3/wechatpay-go/core"
	"github.com/wechatpay-apiv3/wechatpay-go/core/option"
	"github.com/wechatpay-apiv3/wechatpay-go/services/payments/native"
	"github.com/wechatpay-apiv3/wechatpay-go/utils"
	"gorm.io/gorm"
	"time"
	"youngee_b_api/app/dao"
	"youngee_b_api/app/entity"
	"youngee_b_api/app/util"
	"youngee_b_api/app/vo"
)

type RechargeService struct{}

// 充值管理——对公转账
func (s RechargeService) TransferToPublic(param *vo.RechargeTransferParam) (*string, error) {
	var rechargeId string
	var phone string
	//if param.SubAccountId == 0 {
	//	rechargeId = util.MakeRechargeId(param.EnterpriseId)
	//	phone, _ = dao.EnterpriseDao{}.GetEnterprisePhone(param.EnterpriseId)
	//} else {
	//	rechargeId = util.MakeRechargeId(strconv.FormatInt(param.SubAccountId, 10))
	//	phone, _ = dao.SubAccountDao{}.GetSubAccountPhone(param.SubAccountId)
	//}
	rechargeId = util.GenerateDateRelatedUUID(16)
	phone, _ = dao.EnterpriseDao{}.GetEnterprisePhone(param.EnterpriseId)
	rechargeRecord := entity.RechargeRecord{
		RechargeID:         rechargeId,
		EnterpriseID:       param.EnterpriseId,
		SubAccountId:       param.SubAccountId,
		RechargeAmount:     param.Amount,
		TransferVoucherUrl: param.TransferVoucherUrl,
		Phone:              phone,
		RechargeMethod:     1,
		Status:             1,
		CommitAt:           time.Now(),
	}
	err := dao.RechargeRecordDao{}.Insert(&rechargeRecord)
	if err != nil {
		return nil, err
	}
	return &rechargeId, nil
}

// 获取微信支付CodeUrl
func (s RechargeService) NativeApiServicePrepay(enterpriseId string, subAccountId int64, tradeId string, amount int64) (string, *time.Time, error) {
	var (
		mchID                      string = "1615933939"                               // 商户号
		mchCertificateSerialNumber string = "33DDFEC51BF5412F663B9B56510FD567B625FC68" // 商户证书序列号
		mchAPIv3Key                string = "V10987654321younggee12345678910V"         // 商户APIv3密钥，用于加密和解密平台证书
	)

	// 使用 utils 提供的函数从本地文件中加载商户私钥
	mchPrivateKey, err := utils.LoadPrivateKeyWithPath("./apiclient_key.pem") // 商户私钥，用于生成请求的签名
	if err != nil {
		log.Print("load merchant private key error")
	}

	ctx := context.Background()
	// 使用商户私钥等初始化 微信支付client，并使它具有自动定时获取微信支付平台证书的能力
	opts := []core.ClientOption{
		option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
	}
	client, err := core.NewClient(ctx, opts...)
	if err != nil {
		log.Printf("new wechat pay client err: %s", err)
	}

	// 采用 Native 支付方式
	svc := native.NativeApiService{Client: client}
	// 发送请求
	timeExpire := time.Now().Add(5 * time.Minute)
	resp, result, err := svc.Prepay(ctx,
		native.PrepayRequest{
			Appid:         core.String("wxac396a3be7a16844"),
			Mchid:         core.String("1615933939"),
			Description:   core.String("样叽微信支付充值"),
			OutTradeNo:    core.String(tradeId),
			TimeExpire:    core.Time(timeExpire),
			Attach:        core.String("微信支付充值"),
			NotifyUrl:     core.String("https://www.weixin.qq.com/wxpay/pay.php"),
			SupportFapiao: core.Bool(true),
			Amount: &native.Amount{
				Currency: core.String("CNY"),
				Total:    core.Int64(amount),
			},
		},
	)

	if err != nil {
		// 处理错误
		log.Printf("call Prepay err:%s", err)
		return "", nil, err
	} else {
		// 处理返回结果
		log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)
		log.Println("codeUrl:", *resp.CodeUrl)
	}

	// 生成充值记录
	phone, _ := dao.EnterpriseDao{}.GetEnterprisePhone(enterpriseId)
	rechargeRecord := entity.RechargeRecord{
		RechargeID:     tradeId,
		EnterpriseID:   enterpriseId,
		SubAccountId:   subAccountId,
		RechargeAmount: float64(amount) / 100,
		Phone:          phone,
		RechargeMethod: 2,
		Status:         1,
		CommitAt:       time.Now(),
		RefuseAt:       timeExpire,
	}
	err = dao.RechargeRecordDao{}.Insert(&rechargeRecord)
	if err != nil {
		return "", nil, err
	}

	return *resp.CodeUrl, &timeExpire, nil
}

// 根据交易id查询微信是否扫码付款
// https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_2.shtml
func (s RechargeService) QueryOrderByTradeId(enterpriseId string, subAccountId int64, tradeId string) (tradeState string, err error) {
	var (
		mchID                      string = "1615933939"                               // 商户号
		mchCertificateSerialNumber string = "33DDFEC51BF5412F663B9B56510FD567B625FC68" // 商户证书序列号
		mchAPIv3Key                string = "V10987654321younggee12345678910V"         // 商户APIv3密钥
	)

	// 使用 utils 提供的函数从本地文件中加载商户私钥，商户私钥会用来生成请求的签名
	mchPrivateKey, err := utils.LoadPrivateKeyWithPath("./apiclient_key.pem")
	if err != nil {
		log.Print("load merchant private key error")
	}

	ctx := context.Background()
	// 使用商户私钥等初始化 client，并使它具有自动定时获取微信支付平台证书的能力
	opts := []core.ClientOption{
		option.WithWechatPayAutoAuthCipher(mchID, mchCertificateSerialNumber, mchPrivateKey, mchAPIv3Key),
	}
	client, err := core.NewClient(ctx, opts...)
	if err != nil {
		log.Printf("new wechat pay client err: %s", err)
	}

	svc := native.NativeApiService{Client: client}
	resp, result, err := svc.QueryOrderByOutTradeNo(ctx,
		native.QueryOrderByOutTradeNoRequest{
			OutTradeNo: core.String(tradeId),
			Mchid:      core.String("1615933939"),
		},
	)
	fmt.Printf("支付 %+v\n", resp)
	if err != nil {
		// 处理错误
		log.Printf("call QueryOrderByOutTradeNo err: %s", err)
		return "", err
	} else {
		// 处理返回结果
		log.Printf("status=%d resp=%s", result.Response.StatusCode, resp)
	}

	// 更新充值记录/账户金额相关信息
	if "SUCCESS" == *resp.TradeState {
		payTime := resp.SuccessTime
		t, _ := time.Parse("2006-01-02 15:04:05", *payTime)
		err = dao.RechargeRecordDao{}.UpdateRechargeStatus(tradeId, 2, t)
		amount := float64(*resp.Amount.Total) / 100
		_, err = dao.EnterpriseDao{}.UpdateEnterpriseBalance(enterpriseId, amount)
	} else if "CLOSED" == *resp.TradeState {
		err = dao.RechargeRecordDao{}.UpdateRechargeStatus(tradeId, 3, time.Now())
	}

	return *resp.TradeState, nil
}

// 余额管理——总金额、可用余额、冻结金额
func (s RechargeService) ShowBalance(param *vo.BalanceParam) (*vo.ReBalanceShow, error) {
	reBalanceShow := new(vo.ReBalanceShow)
	enterprise, err := dao.EnterpriseDao{}.GetEnterpriseInfo(param.EnterpriseId)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return reBalanceShow, nil
		} else {
			return nil, err
		}
	}
	reBalanceShow.TotalBalance = enterprise.Balance
	reBalanceShow.AvailBalance = enterprise.AvailableBalance
	reBalanceShow.FrozenBalance = enterprise.FrozenBalance
	return reBalanceShow, nil
}

// 余额管理——冻结记录
func (s RechargeService) FrozenInfoList(param *vo.BalanceParam) (vo.ResultVO, error) {
	if param.Page <= 0 {
		param.Page = 1
	}
	if param.PageSize <= 0 {
		param.PageSize = 10
	}
	var result vo.ResultVO
	var reBalanceShows []*vo.ReFrozenInfo
	var selectionInfos []*entity.SelectionInfo
	var projects []*entity.Project
	if param.FrozenState == 1 {
		// 电商带货
		selectionInfos, _ = dao.SelectionInfoDAO{}.GetSelectionFrozenList(param.EnterpriseId)
		// 品牌种草
		projects, _ = dao.ProjectDAO{}.GetProjectFrozenList(param.EnterpriseId)
		// 本地生活

	} else {
		// 电商带货
		selectionInfos, _ = dao.SelectionInfoDAO{}.GetSelectionFrozenCancelList(param.EnterpriseId)
		// 品牌种草
		projects, _ = dao.ProjectDAO{}.GetProjectFrozenCancelList(param.EnterpriseId)
		// 本地生活

	}
	// 汇总结果
	for _, selection := range selectionInfos {
		// 获取商品详情字段
		var creatorName string
		var productName string
		var productPrice float64
		var mainImage string
		if selection.SubAccountId == 0 {
			enterprise, err := dao.EnterpriseDao{}.GetEnterprise(selection.EnterpriseID)
			if err == nil && enterprise != nil {
				creatorName = enterprise.BusinessName
			}
		} else {
			subAccount, err := dao.SubAccountDao{}.GetSubAccount(selection.SubAccountId)
			if err == nil && subAccount != nil {
				creatorName = subAccount.SubAccountName
			}
		}
		product, err := dao.ProductDAO{}.GetProductByID(selection.ProductID)
		if err == nil && product != nil {
			productName = product.ProductName
			productPrice = product.ProductPrice
		}
		mainImage, err = dao.ProductPhotoDAO{}.GetMainPhotoByProductID(selection.ProductID)
		// 电商带货汇总
		reBalanceShow := &vo.ReFrozenInfo{
			ProductId:     selection.ProductID,
			MainImage:     mainImage,
			ProductName:   productName,
			ProductPrice:  productPrice,
			Platform:      selection.Platform,
			CreatorName:   creatorName,
			TaskType:      "电商带货",
			FrozenBalance: selection.EstimatedCost,
			FrozenTime:    selection.PayAt.Format("2006-01-02 15:04:05"),
			EnterpriseId:  selection.EnterpriseID,
			SubAccountId:  selection.SubAccountId,
			TaskId:        selection.SelectionID,
		}
		if param.FrozenState == 2 {
			reBalanceShow.FrozenCancelBalance = selection.SettlementAmount
		}
		reBalanceShows = append(reBalanceShows, reBalanceShow)
	}
	for _, project := range projects {
		// 获取商品详情字段
		var creatorName string
		var productName string
		var productPrice float64
		var mainImage string
		if project.SubAccountId == 0 {
			enterprise, err := dao.EnterpriseDao{}.GetEnterprise(project.EnterpriseID)
			if err == nil && enterprise != nil {
				creatorName = enterprise.BusinessName
			}
		} else {
			subAccount, err := dao.SubAccountDao{}.GetSubAccount(project.SubAccountId)
			if err == nil && subAccount != nil {
				creatorName = subAccount.SubAccountName
			}
		}
		product, err := dao.ProductDAO{}.GetProductByID(project.ProductID)
		if err == nil && product != nil {
			productName = product.ProductName
			productPrice = product.ProductPrice
		}
		mainImage, err = dao.ProductPhotoDAO{}.GetMainPhotoByProductID(project.ProductID)
		// 电商带货汇总
		reBalanceShow := &vo.ReFrozenInfo{
			ProductId:     project.ProductID,
			MainImage:     mainImage,
			ProductName:   productName,
			ProductPrice:  productPrice,
			Platform:      project.ProjectPlatform,
			CreatorName:   creatorName,
			TaskType:      "品牌种草",
			FrozenBalance: project.NeedPay,
			FrozenTime:    project.PayAt.Format("2006-01-02 15:04:05"),
			EnterpriseId:  project.EnterpriseID,
			SubAccountId:  project.SubAccountId,
			TaskId:        project.ProjectId,
		}
		if param.FrozenState == 2 {
			reBalanceShow.FrozenCancelBalance = project.SettlementAmount
		}
		reBalanceShows = append(reBalanceShows, reBalanceShow)
	}

	startIndex := (param.Page - 1) * param.PageSize
	endIndex := startIndex + param.PageSize

	// 分页
	if startIndex >= len(reBalanceShows) {
		result = vo.ResultVO{
			Page:     param.Page,
			PageSize: param.PageSize,
			Total:    int64(len(reBalanceShows)),
			Data:     nil,
		}
		return result, nil
	}
	if endIndex > len(reBalanceShows) {
		endIndex = len(reBalanceShows)
	}
	result = vo.ResultVO{
		Page:     param.Page,
		PageSize: param.PageSize,
		Total:    int64(len(reBalanceShows)),
		Data:     reBalanceShows[startIndex:endIndex],
	}
	return result, nil
}

// 余额管理——冻结记录-角标
func (t RechargeService) FrozenInfoCount(param *vo.BalanceParam) map[string]int64 {
	res := make(map[string]int64)
	var blockNum1 int64
	var blockNum2 int64
	var blockReleaseNum1 int64
	var blockReleaseNum2 int64
	// 冻结中
	dao.Db.Model(entity.SelectionInfo{}).Where(fmt.Sprintf("enterprise_id = ? AND (selection_status between 5 and 6) "), param.EnterpriseId).Count(&blockNum1)
	dao.Db.Model(entity.Project{}).Where(fmt.Sprintf("enterprise_id = ? AND project_type = ? AND (project_status between 7 and 8) "), param.EnterpriseId, 1).Count(&blockNum2)
	// 冻结解除
	dao.Db.Model(entity.SelectionInfo{}).Where(fmt.Sprintf("enterprise_id = ? AND (selection_status between 7 and 8) "), param.EnterpriseId).Count(&blockReleaseNum1)
	dao.Db.Model(entity.Project{}).Where(fmt.Sprintf("enterprise_id = ? AND project_type = ? AND (project_status between 9 and 10) "), param.EnterpriseId, 1).Count(&blockReleaseNum2)

	res["blockNum"] = blockNum1 + blockNum2
	res["blockReleaseNum"] = blockReleaseNum1 + blockReleaseNum2

	return res
}

// 充值管理——累计充值金额、确认中金额
func (s RechargeService) ShowRecharge(param *vo.RechargeParam) (*vo.ReRechargeShow, error) {
	reRechargeShow := new(vo.ReRechargeShow)
	confirmingRecharge, _ := dao.RechargeRecordDao{}.GetRechargeAmount(param.EnterpriseId, 1)
	totalRecharge, _ := dao.RechargeRecordDao{}.GetRechargeAmount(param.EnterpriseId, 2)
	reRechargeShow.ConfirmingRecharge = confirmingRecharge
	reRechargeShow.TotalRecharge = totalRecharge
	return reRechargeShow, nil
}

// 充值管理——充值记录
func (s RechargeService) RechargeInfoList(param *vo.RechargeParam) (vo.ResultVO, error) {
	if param.Page <= 0 {
		param.Page = 1
	}
	if param.PageSize <= 0 {
		param.PageSize = 10
	}
	var result vo.ResultVO
	var reRechargeInfos []*vo.ReRechargeInfo
	rechargeRecords, total, err := dao.RechargeRecordDao{}.RechargeInfoList(param)
	if err != nil {
		return result, err
	}
	for _, rechargeRecord := range rechargeRecords {
		var creatorName string
		if rechargeRecord.SubAccountId == 0 {
			enterprise, err := dao.EnterpriseDao{}.GetEnterprise(rechargeRecord.EnterpriseID)
			if err == nil && enterprise != nil {
				creatorName = enterprise.BusinessName
			}
		} else {
			subAccount, err := dao.SubAccountDao{}.GetSubAccount(rechargeRecord.SubAccountId)
			if err == nil && subAccount != nil {
				creatorName = subAccount.SubAccountName
			}
		}
		reRechargeInfo := &vo.ReRechargeInfo{
			RechargeId:         rechargeRecord.RechargeID,
			CreatorName:        creatorName,
			RechargeAmount:     rechargeRecord.RechargeAmount,
			RechargeMethod:     rechargeRecord.RechargeMethod,
			TransferVoucherUrl: rechargeRecord.TransferVoucherUrl,
		}
		if param.RechargeState == 1 {
			reRechargeInfo.CommitAt = rechargeRecord.CommitAt.Format("2006-01-02 15:04:05")
		} else if param.RechargeState == 2 {
			reRechargeInfo.ConfirmAt = rechargeRecord.ConfirmAt.Format("2006-01-02 15:04:05")
		} else if param.RechargeState == 3 {
			reRechargeInfo.RefuseAt = rechargeRecord.RefuseAt.Format("2006-01-02 15:04:05")
			reRechargeInfo.FailReason = rechargeRecord.FailReason
		}
		reRechargeInfos = append(reRechargeInfos, reRechargeInfo)
	}
	//rechargingNum, _ := dao.RechargeRecordDao{}.RechargeStatusCount(param.EnterpriseId, 1)
	//rechargedNum, _ := dao.RechargeRecordDao{}.RechargeStatusCount(param.EnterpriseId, 2)
	//failNum, _ := dao.RechargeRecordDao{}.RechargeStatusCount(param.EnterpriseId, 3)
	resMap := make(map[string]interface{})
	//resMap["rechargingNum"] = rechargingNum
	//resMap["rechargedNum"] = rechargedNum
	//resMap["failNum"] = failNum
	resMap["reRechargeInfos"] = reRechargeInfos
	result = vo.ResultVO{
		Page:     param.Page,
		PageSize: param.PageSize,
		Total:    total,
		Data:     resMap,
	}
	return result, nil
}

// 余额管理——冻结记录-角标
func (t RechargeService) RechargeInfoCount(param *vo.RechargeParam) map[string]int64 {
	res := make(map[string]int64)
	var rechargeConfirming int64
	var recharged int64
	var rechargeFail int64
	dao.Db.Model(&entity.RechargeRecord{}).Where("enterprise_id = ? AND status = ?", param.EnterpriseId, 1).Count(&rechargeConfirming)
	dao.Db.Model(&entity.RechargeRecord{}).Where("enterprise_id = ? AND status = ?", param.EnterpriseId, 2).Count(&recharged)
	dao.Db.Model(&entity.RechargeRecord{}).Where("enterprise_id = ? AND status = ?", param.EnterpriseId, 3).Count(&rechargeFail)
	res["rechargeConfirming"] = rechargeConfirming
	res["recharged"] = recharged
	res["rechargeFail"] = rechargeFail

	return res
}

// 财务待办——充值确认中金额
func (s RechargeService) GetFinance(param *vo.CommonParam) (float64, error) {
	confirmingRecharge, err := dao.RechargeRecordDao{}.GetRechargeAmount(param.EnterpriseId, 1)
	if err != nil {
		return 0, err
	}

	return confirmingRecharge, nil
}
