package service

import (
	"context"
	butil "enterprise/base/util"
	"enterprise/common/config"
	"enterprise/common/dao"
	"enterprise/common/global"
	"enterprise/common/model"
	"fmt"
	"git.u8t.cn/open/gosdk/qyweixin"
	"git.u8t.cn/open/gosdk/wechat/message"
	"github.com/gogap/errors"
	log "github.com/sirupsen/logrus"
	"github.com/smartwalle/alipay/v3"
	"github.com/smbrave/goutil"
	"github.com/spf13/cast"
	"strings"
)

var (
	SpStatusCreated        = 1
	SpStatusPassed         = 2
	SpStatusRefused        = 3
	SpStatusCanceled       = 4
	SpStatusPassedCanceled = 6
)

type Approve struct {
	corp          *model.Corp
	corpConfig    *model.CorpConfig
	approveClient *qyweixin.AppApprove
}

func NewApprove(corp *model.Corp) *Approve {
	return &Approve{
		corp:       corp,
		corpConfig: corp.GetConfig(),
	}
}

func (b *Approve) Reply(msg message.MixMessage) *message.Reply {
	if b.approveClient == nil {
		b.approveClient = qyweixin.NewAppApprove(&qyweixin.AppConfig{
			Corpid: b.corpConfig.CorpId,
			Secret: b.corpConfig.ApproveSecret,
			Agent:  b.corpConfig.ApproveAgent,
		})
	}
	go b.handle(&msg)
	return &message.Reply{message.MsgTypeText, message.NewText("")}
}

func (a *Approve) handle(msg *message.MixMessage) {
	msgType := msg.MsgType

	if msgType == message.MsgTypeEvent {
		event := strings.ToUpper(string(msg.Event))
		if event == message.EventClick {
			a.handleClick(msg)
		} else if event == "SYS_APPROVAL_CHANGE" {
			a.handleApprovalChange(msg)
		}
	} else if msgType == message.MsgTypeText {
		a.handleText(msg)
	}

	log.Infof(goutil.EncodeJSONIndent(msg))
}

func (a *Approve) handleApprovalChange(msg *message.MixMessage) {
	spStatus := msg.ApprovalInfo.SpStatus
	spNo := msg.ApprovalInfo.SpNo
	templateId := msg.ApprovalInfo.TemplateId

	// 支出里审批通过的 或者审批通过撤销的
	if spStatus != SpStatusPassed && spStatus != SpStatusPassedCanceled {
		return
	}

	detail, err := a.approveClient.GetDetail(spNo)
	if err != nil {
		log.Errorf("get spn detail error :%s", err.Error())
		return
	}
	if detail == nil {

	}

	log.Infof("spno: %s detail: %s", spNo, goutil.EncodeJSON(detail))
	if templateId == a.corpConfig.TplIdRefund {
		a.handleRefund(detail, spStatus)
	} else if templateId == a.corpConfig.TplIdVacation {
		a.handleVacation(detail, spStatus)
	} else if templateId == a.corpConfig.TplIdCheckin {
		a.handleCheckin(detail, spStatus)
	} else if templateId == a.corpConfig.TplIdPayment {
		a.handlePayment(detail, spStatus)
	}
}

func (a *Approve) handlePayment(detail *qyweixin.ApproveDetail, spStatus int) {
	newData := new(model.ApprovalPayment)
	newData.From(detail)
	newData.CorpId = a.corp.Id
	dbDao := dao.NewApprovalPaymentDao()

	old, err := dbDao.GetBySpNo(a.corp.Id, detail.SpNo)
	if err != nil {
		log.Errorf("db error :%s", err.Error())
		return
	}

	if spStatus == SpStatusPassedCanceled {
		if old != nil {
			dbDao.Delete(old.Id)
		}
		return
	}

	if old != nil {
		newData.Id = old.Id
		newData.CreateTime = old.CreateTime
		err = dbDao.Update(newData)
	} else {
		_, err = dbDao.Create(newData)
	}

	if err != nil {
		log.Errorf("db error :%s", err.Error())
		return
	}
}

func (a *Approve) handleVacation(detail *qyweixin.ApproveDetail, spStatus int) {
	newData := new(model.ApprovalVacation)
	newData.From(detail)
	newData.CorpId = a.corp.Id
	dbDao := dao.NewApprovalVacationDao()

	old, err := dbDao.GetBySpNo(a.corp.Id, detail.SpNo)
	if err != nil {
		log.Errorf("db error :%s", err.Error())
		return
	}

	if spStatus == SpStatusPassedCanceled {
		if old != nil {
			dbDao.Delete(old.Id)
		}
		return
	}

	if old != nil {
		newData.Id = old.Id
		newData.CreateTime = old.CreateTime
		err = dbDao.Update(newData)
	} else {
		_, err = dbDao.Create(newData)
	}

	if err != nil {
		log.Errorf("db error :%s", err.Error())
		return
	}
}

func (a *Approve) handleCheckin(detail *qyweixin.ApproveDetail, spStatus int) {
	newData := new(model.ApprovalCheckin)
	newData.From(detail)
	newData.CorpId = a.corp.Id
	dbDao := dao.NewApprovalCheckinDao()

	old, err := dbDao.GetBySpNo(a.corp.Id, detail.SpNo)
	if err != nil {
		log.Errorf("db error :%s", err.Error())
		return
	}

	if spStatus == SpStatusPassedCanceled {
		if old != nil {
			dbDao.Delete(old.Id)
		}
		return
	}

	if old != nil {
		newData.Id = old.Id
		newData.CreateTime = old.CreateTime
		err = dbDao.Update(newData)
	} else {
		_, err = dbDao.Create(newData)
	}

	if err != nil {
		log.Errorf("db error :%s", err.Error())
		return
	}
}

func (a *Approve) refundWxpay(data *model.ApprovalRefund) error {
	openid, err := a.approveClient.GetOpenid(data.Username)
	if err != nil {
		log.Errorf("GetOpenid error :%s", err.Error())
		return err
	}

	var req qyweixin.PayReq
	req.BillNo = fmt.Sprintf("BX%s%s", data.SpNo, butil.CutTail(data.Username, 12))
	req.Title = fmt.Sprintf("【%s】报销", data.RefundType)
	req.Openid = openid
	req.TotalAmount = int64(100 * data.RefundAmount)
	qyPay := qyweixin.NewAppPay(&qyweixin.PayConfig{
		Corpid:       a.corpConfig.CorpId,
		Secret:       a.corpConfig.PaySecret,
		Agent:        a.corpConfig.PayAgent,
		SerialNumber: config.GetConfig().WxPay.PaySerialNumber,
		ApiKey:       config.GetConfig().WxPay.PayApiKeyV2,
		MchId:        config.GetConfig().WxPay.PayMchId,
		CertPem:      config.GetConfig().WxPay.PayCertPem,
		KeyPem:       config.GetConfig().WxPay.PayKeyPem,
	})
	if err = qyPay.PayMoney(&req); err != nil {
		log.Errorf("pay error[%s] :%s", goutil.EncodeJSON(req), err.Error())
		return err
	}
	return nil
}

func (a *Approve) refundAlipay(staff *model.StaffUser, data *model.ApprovalRefund) error {
	userPayee := staff.GetPayee()
	cli := config.GetAliPayClient("batiao")
	var req alipay.FundTransUniTransfer
	req.Remark = "报销_" + data.SpNo
	req.OutBizNo = fmt.Sprintf("BX%s%s", data.SpNo, butil.CutTail(data.Username, 12))
	req.TransAmount = cast.ToString(data.RefundAmount)
	req.ProductCode = "TRANS_ACCOUNT_NO_PWD"
	req.BizScene = "DIRECT_TRANSFER"
	req.OrderTitle = data.RefundRemark
	payee := new(alipay.PayeeInfo)
	req.PayeeInfo = payee
	payee.IdentityType = "ALIPAY_USER_ID"
	payee.Identity = userPayee.AlipayUid

	rsp, err := cli.FundTransUniTransfer(context.Background(), req)
	if err != nil {
		panic(err)
	}
	if !rsp.IsSuccess() {
		log.Errorf("FundTransUniTransfer error :%s", goutil.EncodeJSON(rsp))
		return errors.New(goutil.EncodeJSON(rsp))
	}
	return nil
}

func (a *Approve) handleRefund(detail *qyweixin.ApproveDetail, spStatus int) {
	newData := new(model.ApprovalRefund)
	newData.From(detail)
	newData.CorpId = a.corp.Id
	dbDao := dao.NewApprovalRefundDao()

	old, err := dbDao.GetBySpNo(a.corp.Id, detail.SpNo)
	if err != nil {
		log.Errorf("db error :%s", err.Error())
		return
	}

	if spStatus == SpStatusPassedCanceled {
		if old != nil {
			dbDao.Delete(old.Id)
		}
		return
	}

	if old != nil {
		newData.Id = old.Id
		newData.CreateTime = old.CreateTime
		err = dbDao.Update(newData)
	} else {
		_, err = dbDao.Create(newData)
	}

	if err != nil {
		log.Errorf("db error :%s", err.Error())
		return
	}

	//只有八条科技才自动付款
	if a.corp.Id != 1000 {
		return
	}
	staffUser, err := dao.NewStaffUserDao().GetByUsername(1000, newData.Username)
	if err != nil {
		log.Errorf("db error :%s", err.Error())
		return
	}
	userPayee := staffUser.GetPayee()
	// 支付费用
	var payType = "weixin"
	if userPayee.AlipayUid != "" {
		err = a.refundAlipay(staffUser, newData)
		payType = "alipay"
	} else {
		err = a.refundWxpay(newData)
	}
	var title string = "【报销成功】"
	if err == nil {
		newData.Status = model.ApprovalRefundStatusPayed
	} else {
		title = "【报销失败】"
	}

	message := make([]string, 0)
	message = append(message, title)
	message = append(message, fmt.Sprintf("发放金额:%s", fmt.Sprintf("%.2f", newData.RefundAmount)))
	message = append(message, fmt.Sprintf("费用类型:%s", newData.RefundType))
	message = append(message, fmt.Sprintf("支付方式:%s", payType))
	message = append(message, fmt.Sprintf("员工名称:%s", newData.Username))
	message = append(message, fmt.Sprintf("费用说明:%s", newData.RefundRemark))
	if err != nil {
		message = append(message, fmt.Sprintf("异常:%s", err.Error()))
	}

	if err := global.SendMessage([]string{"jiangyong"}, strings.Join(message, "\n")); err != nil {
		log.Errorf("send message error :%s", err.Error())
	}

	if err := dao.NewApprovalRefundDao().Update(newData); err != nil {
		log.Errorf("db error :%s", err.Error())
	}
}

func (a *Approve) HandleRefundApprove(approve *model.ApprovalRefund) error {
	staff, err := dao.NewStaffUserDao().GetByUsername(approve.CorpId, approve.Username)
	if err != nil {
		return err
	}
	if staff == nil {
		return errors.New("staff is not exist")
	}

	// 支付费用
	var payType = "weixin"
	payee := staff.GetPayee()
	if payee.AlipayUid != "" {
		err = a.refundAlipay(staff, approve)
		payType = "alipay"
	} else {
		err = a.refundWxpay(approve)
	}
	var title string = "【报销成功】"
	if err == nil {
		approve.Status = model.ApprovalRefundStatusPayed
	} else {
		title = "【报销失败】"
	}

	message := make([]string, 0)
	message = append(message, title)
	message = append(message, fmt.Sprintf("发放金额:%s", fmt.Sprintf("%.2f", approve.RefundAmount)))
	message = append(message, fmt.Sprintf("费用类型:%s", approve.RefundType))
	message = append(message, fmt.Sprintf("支付方式:%s", payType))
	message = append(message, fmt.Sprintf("员工名称:%s", approve.Username))
	message = append(message, fmt.Sprintf("费用说明:%s", approve.RefundRemark))
	if err != nil {
		message = append(message, fmt.Sprintf("异常:%s", err.Error()))
	}

	if err := global.SendMessage([]string{"jiangyong"}, strings.Join(message, "\n")); err != nil {
		log.Errorf("send message error :%s", err.Error())
	}

	if err := dao.NewApprovalRefundDao().Update(approve); err != nil {
		log.Errorf("db error :%s", err.Error())
	}
	return nil
}

func (a *Approve) handleText(msg *message.MixMessage) {

}

func (a *Approve) handleClick(msg *message.MixMessage) {

}

func (a *Approve) sendText(message string) {

}