package shanghu

import (
	orm "duoduo/database"
	"errors"
	"fmt"
	"github.com/shopspring/decimal"
	"time"
)

type ClientPayTrans struct {
	ID             int64           `gorm:"column:id;type:bigint(20);primary_key" json:"id"`                   // 主键
	RequestID      string          `gorm:"column:request_id;type:varchar(255)" json:"request_id"`             // 请求id,幂等性
	OutTradeNo     string          `gorm:"column:out_trade_no;type:varchar(255)" json:"out_trade_no"`         // 交易id
	MerchantCardID int64           `gorm:"column:merchant_card_id;type:bigint(20)" json:"merchant_card_id"`   // 商户卡id
	ClientOpenID   string          `gorm:"column:client_open_id;type:varchar(255)" json:"client_open_id"`     // 客户端openid
	Status         int             `gorm:"column:status;type:int(11)" json:"status"`                          // 1-未支付 2-支付成功 3-取消支付 4-退款
	Amount         decimal.Decimal `gorm:"column:amount;type:decimal(10,2)" json:"amount"`                    // 交易金额
	ThirdTradeNo   string          `gorm:"column:third_trade_no;type:varchar(255)" json:"third_trade_no"`     // 微信交易id
	PayTime        time.Time       `gorm:"column:pay_time;type:datetime(3);default:null" json:"pay_time"`     // 支付时间
	InvitationCode string          `gorm:"column:invitation_code;type:varchar(25)" json:"invitation_code"`    // 邀请码
	AccountStatus  int             `gorm:"column:account_status;type:int(11)" json:"account_status"`          // 分账状态 99-分账成功 2-分账失败 1-未分账
	AccountErrLog  string          `gorm:"column:account_err_log;type:varchar(255)" json:"account_err_log"`   // 分账err日志
	CreateBy       int64           `gorm:"column:create_by;type:bigint(20)" json:"create_by"`                 // 创建者
	UpdateBy       int64           `gorm:"column:update_by;type:bigint(20)" json:"update_by"`                 // 更新者
	CreatedAt      time.Time       `gorm:"column:created_at;type:datetime(3)" json:"created_at"`              // 创建时间
	UpdatedAt      time.Time       `gorm:"column:updated_at;type:datetime(3)" json:"updated_at"`              // 最后更新时间
	DeletedAt      time.Time       `gorm:"column:deleted_at;type:datetime(3);default:null" json:"deleted_at"` // 删除时间
}

func (m *ClientPayTrans) TableName() string {
	return "client_pay_trans"
}

func (m *ClientPayTrans) GetRequestNum() int {
	var count int

	tableCount := orm.ShMysql.Table(m.TableName()).Where("request_id = ? ", m.RequestID)
	tableCount.Count(&count)
	return count

}

func (m *ClientPayTrans) GetNumByCardID() int {
	var count int

	tableCount := orm.ShMysql.Table(m.TableName()).Where("merchant_card_id = ? and status =2 ", m.MerchantCardID)
	tableCount.Count(&count)

	return count
}

func (m *ClientPayTrans) GetPayTransByOpenid() (ClientPayTrans, error) {
	var doc ClientPayTrans

	table := orm.ShMysql.Table(m.TableName())
	table = table.Where("merchant_card_id = ? and  client_open_id = ? and status = 2 ", m.MerchantCardID, m.ClientOpenID)

	if err := table.Select("*").First(&doc).Error; err != nil {
		return doc, err
	}

	return doc, nil
}

func (m *ClientPayTrans) GetPayTransByOpenId() (ClientPayTrans, error) {
	var doc ClientPayTrans

	table := orm.ShMysql.Table(m.TableName())
	table = table.Where("client_open_id = ? and status = 2 ", m.ClientOpenID)

	if err := table.Select("*").First(&doc).Error; err != nil {
		return doc, err
	}

	return doc, nil
}

func (m *ClientPayTrans) GetPaySuccessTransByInvitationCode(pageSize int, pageIndex int) ([]ClientPayTrans, int, error) {
	var doc []ClientPayTrans

	table := orm.ShMysql.Table(m.TableName())

	table = table.Where("invitation_code = ?  and status = 2  and account_status = 99", m.InvitationCode)
	var count int
	if err := table.Select("*").Order("id desc").Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&doc).Error; err != nil {
		return nil, 0, err
	}
	table.Count(&count)
	return doc, count, nil

}

func (m *ClientPayTrans) GetPayTransById() (ClientPayTrans, error) {
	var doc ClientPayTrans

	table := orm.ShMysql.Table(m.TableName())
	table = table.Where("id = ?  ", m.ID)

	if err := table.Select("*").First(&doc).Error; err != nil {
		return doc, err
	}

	return doc, nil
}

func (m *ClientPayTrans) GetPayTransByTradeNo() (ClientPayTrans, error) {
	var doc ClientPayTrans

	table := orm.ShMysql.Table(m.TableName())
	table = table.Where("out_trade_no = ?  ", m.OutTradeNo)

	if err := table.Select("*").First(&doc).Error; err != nil {
		return doc, err
	}

	return doc, nil
}

func (u *ClientPayTrans) Create() (ClientPayTrans, error) {
	var doc ClientPayTrans
	var err error

	doc = *u
	err = orm.ShMysql.Table(u.TableName()).Create(&doc).Error
	if err != nil {
		return doc, err
	}

	return doc, nil
}

func (m *ClientPayTrans) UpdatePayTransByTradeNo() error {

	if err := orm.ShMysql.Table(m.TableName()).Model(&m).Where("out_trade_no = ? ", m.OutTradeNo).Updates(
		map[string]interface{}{
			"third_trade_no": m.ThirdTradeNo,
			"pay_time":       m.PayTime,
			"status":         m.Status,
			"account_status": m.AccountStatus,
			"updated_at":     time.Now()}).Error; err != nil {
		return err
	}
	return nil
}

func (m *ClientPayTrans) GetTransByAccount() (ClientPayTrans, error) {
	var doc ClientPayTrans

	table := orm.ShMysql.Table(m.TableName())
	table = table.Where("account_status = ?  ", m.AccountStatus)

	if err := table.Select("*").First(&doc).Error; err != nil {
		return doc, err
	}

	return doc, nil
}

func (m *ClientPayTrans) GetPayTransByStatus() (ClientPayTrans, error) {
	var doc ClientPayTrans

	table := orm.ShMysql.Table(m.TableName())
	table = table.Where("status = ? and  account_status = ?", m.Status, m.AccountStatus)

	if err := table.Select("*").First(&doc).Error; err != nil {
		return doc, err
	}

	return doc, nil
}

func (m *ClientPayTrans) UpdateById(data map[string]interface{}) error {
	err := orm.ShMysql.Table(m.TableName()).Where("id = ?", m.ID).Updates(data).Error
	if err != nil {
		return err
	}
	return nil
}

func (m *ClientPayTrans) GetPayTransSuccessByOpenID(pageSize int, pageIndex int) ([]ClientPayTrans, int, error) {
	var doc []ClientPayTrans

	table := orm.ShMysql.Table(m.TableName())

	//if m.ActivityStartTime != 0

	table = table.Where("client_open_id = ?  and status = 2", m.ClientOpenID)
	var count int
	if err := table.Select("*").Order("id desc").Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&doc).Error; err != nil {
		return nil, 0, err
	}
	table.Count(&count)
	return doc, count, nil

}

func (m *ClientPayTrans) GetPayTransSuccessByMerchantID(pageSize int, pageIndex int, merchantId []int64) ([]ClientPayTrans, int, error) {
	var doc []ClientPayTrans

	table := orm.ShMysql.Table(m.TableName())

	table = table.Where("merchant_card_id in (?)  and status = 2", merchantId)
	var count int
	if err := table.Select("*").Order("id desc").Offset((pageIndex - 1) * pageSize).Limit(pageSize).Find(&doc).Error; err != nil {
		return nil, 0, err
	}
	table.Count(&count)
	return doc, count, nil

}

func (m *ClientPayTrans) SettleAdd(merchantAmount, clientAmount decimal.Decimal, merchantOpenId, clientOpenId string, payTransId int64) error {
	// 使用事务 添加
	var err error
	var clientAccount MerchantClientAccount
	var merchantAccount MerchantAccount
	var amountPreMerchant decimal.Decimal
	var amountPreClient decimal.Decimal
	tx := orm.ShMysql.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	//查看是否有账号,没有创建
	err = tx.Table("merchant_account").Select("*").Where("merchant_open_id = ?", merchantOpenId).Find(&merchantAccount).Error
	if err != nil && err.Error() != "record not found" {
		return err
	}

	if merchantAccount.ID == 0 {
		merchantAccount.MerchantOpenID = merchantOpenId
		merchantAccount.Version = 1
		merchantAccount.UpdatedAt = time.Now()
		merchantAccount.CreatedAt = time.Now()
		err = tx.Table("merchant_account").Create(&merchantAccount).Error
		if err != nil {
			return err
		}
	}
	amountPreMerchant = merchantAccount.Amount

	if clientOpenId != "" { //原始码不抽佣金
		err = tx.Table("merchant_client_account").Select("*").Where("client_open_id = ?", clientOpenId).Find(&clientAccount).Error
		if err != nil && err.Error() != "record not found" {
			return err
		}

		if clientAccount.ID == 0 {
			clientAccount.ClientOpenID = clientOpenId
			clientAccount.Version = 1
			clientAccount.UpdatedAt = time.Now()
			clientAccount.CreatedAt = time.Now()
			err = tx.Table("merchant_client_account").Create(&clientAccount).Error
			if err != nil {
				return err
			}
		}
		amountPreClient = clientAccount.Amount

		clientAmountAdd := clientAccount.Amount.Add(clientAmount)
		result := tx.Table("merchant_client_account").Model(&clientAccount).Where("client_open_id = ? and version = ?", clientOpenId, clientAccount.Version).Updates(
			map[string]interface{}{
				"amount":     clientAmountAdd,
				"version":    clientAccount.Version + 1,
				"updated_at": time.Now()})
		if result.Error != nil {
			return result.Error
		}

		if result.RowsAffected <= 0 {
			err = errors.New("rows is zero")
			return err
		}

		var clientAccountLog MerchantClientAccountLog

		clientAccountLog.ClientOpenID = clientOpenId
		clientAccountLog.UpdatedAt = time.Now()
		clientAccountLog.AmountPre = amountPreClient
		clientAccountLog.AmountAfter = clientAmountAdd
		clientAccountLog.ReviewAmountAfter = clientAccount.ReviewAmount
		clientAccountLog.ReviewAmountPre = clientAccount.ReviewAmount
		clientAccountLog.Amount = clientAmount
		clientAccountLog.PayTransId = payTransId

		err = tx.Table("merchant_client_account_log").Create(&clientAccountLog).Error
		if err != nil {
			return err
		}
	}

	//做金额加减操作并且入日志库
	merchantAmountAdd := merchantAccount.Amount.Add(merchantAmount)
	result := tx.Table("merchant_account").Model(&merchantAccount).Where("merchant_open_id = ? and version = ?", merchantOpenId, merchantAccount.Version).Updates(
		map[string]interface{}{
			"amount":     merchantAmountAdd,
			"version":    merchantAccount.Version + 1,
			"updated_at": time.Now()})

	if result.Error != nil {
		return result.Error
	}
	if result.RowsAffected <= 0 {
		err = errors.New("rows is zero")
		return err
	}

	var merchantAccountLog MerchantAccountLog

	fmt.Println("amountPreMerchant = ", amountPreMerchant)
	fmt.Println("merchantAccount.Amount = ", merchantAccount.Amount)

	merchantAccountLog.MerchantOpenID = merchantOpenId
	merchantAccountLog.UpdatedAt = time.Now()
	merchantAccountLog.AmountPre = amountPreMerchant
	merchantAccountLog.AmountAfter = merchantAmountAdd
	merchantAccountLog.ReviewAmountAfter = merchantAccount.ReviewAmount
	merchantAccountLog.ReviewAmountPre = merchantAccount.ReviewAmount
	merchantAccountLog.Amount = merchantAmount
	merchantAccountLog.PayTransId = payTransId
	err = tx.Table("merchant_account_log").Create(&merchantAccountLog).Error
	if err != nil {
		return err
	}

	return nil

}

func (m *ClientPayTrans) SettleAddCashOutFee(amount decimal.Decimal, clientOpenId string, cashOutId int64) error {
	// 使用事务 添加
	var err error
	var clientAccount MerchantClientAccount
	var amountPreClient decimal.Decimal
	tx := orm.ShMysql.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	err = tx.Table("merchant_client_account").Select("*").Where("client_open_id = ?", clientOpenId).Find(&clientAccount).Error
	if err != nil && err.Error() != "record not found" {
		return err
	}

	if clientAccount.ID == 0 {
		clientAccount.ClientOpenID = clientOpenId
		clientAccount.Version = 1
		clientAccount.UpdatedAt = time.Now()
		clientAccount.CreatedAt = time.Now()
		err = tx.Table("merchant_client_account").Create(&clientAccount).Error
		if err != nil {
			return err
		}
	}
	amountPreClient = clientAccount.Amount

	clientAmountAdd := clientAccount.Amount.Add(amount)
	result := tx.Table("merchant_client_account").Model(&clientAccount).Where("client_open_id = ? and version = ?", clientOpenId, clientAccount.Version).Updates(
		map[string]interface{}{
			"amount":     clientAmountAdd,
			"version":    clientAccount.Version + 1,
			"updated_at": time.Now()})
	if result.Error != nil {
		return result.Error
	}

	if result.RowsAffected <= 0 {
		err = errors.New("rows is zero")
		return err
	}

	var clientAccountLog MerchantClientAccountLog

	clientAccountLog.ClientOpenID = clientOpenId
	clientAccountLog.UpdatedAt = time.Now()
	clientAccountLog.AmountPre = amountPreClient
	clientAccountLog.AmountAfter = clientAmountAdd
	clientAccountLog.ReviewAmountAfter = clientAccount.ReviewAmount
	clientAccountLog.ReviewAmountPre = clientAccount.ReviewAmount
	clientAccountLog.Amount = amount
	clientAccountLog.PayTransId = cashOutId
	clientAccountLog.TransType = 3 //服务费

	err = tx.Table("merchant_client_account_log").Create(&clientAccountLog).Error
	if err != nil {
		return err
	}

	return nil

}

func (m *ClientPayTrans) SettleSubClient(clientAmount decimal.Decimal, clientOpenId string, cashOutId int64) error {
	// 使用事务 添加
	var err error
	var clientAccount MerchantClientAccount
	var cashOut CashOut
	var amountPreClient decimal.Decimal
	tx := orm.ShMysql.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	err = tx.Table("merchant_client_account").Select("*").Where("client_open_id = ?", clientOpenId).Find(&clientAccount).Error
	if err != nil {
		return err
	}

	amountPreClient = clientAccount.Amount

	if clientAccount.Amount.Cmp(clientAmount) < 0 {
		err = errors.New("账户金额不够")
		return err
	}

	clientAmountSub := clientAccount.Amount.Sub(clientAmount)
	result := tx.Table("merchant_client_account").Model(&clientAccount).Where("client_open_id = ? and version = ?", clientOpenId, clientAccount.Version).Updates(
		map[string]interface{}{
			"amount":     clientAmountSub,
			"version":    clientAccount.Version + 1,
			"updated_at": time.Now()})
	if result.Error != nil {
		return result.Error
	}

	if result.RowsAffected <= 0 {
		err = errors.New("rows is zero")
		return err
	}

	var clientAccountLog MerchantClientAccountLog

	clientAccountLog.ClientOpenID = clientOpenId
	clientAccountLog.UpdatedAt = time.Now()
	clientAccountLog.AmountPre = amountPreClient
	clientAccountLog.AmountAfter = clientAmountSub
	clientAccountLog.ReviewAmountAfter = clientAccount.ReviewAmount
	clientAccountLog.ReviewAmountPre = clientAccount.ReviewAmount
	clientAccountLog.Amount = clientAmount
	clientAccountLog.PayTransId = cashOutId
	clientAccountLog.TransType = 2

	err = tx.Table("merchant_client_account_log").Create(&clientAccountLog).Error
	if err != nil {
		return err
	}

	result = tx.Table("cash_out").Model(&cashOut).Where("id = ? ", cashOutId).Updates(
		map[string]interface{}{
			"status":         99, //体现成功
			"account_status": 99, //分账成功
			"updated_at":     time.Now()})
	if result.Error != nil {
		return result.Error
	}

	if result.RowsAffected <= 0 {
		err = errors.New("rows is zero")
		return err
	}

	return nil

}

func (m *ClientPayTrans) SettleSubMerchant(merchantAmount decimal.Decimal, merchantOpenId string, cashOutId int64) error {
	// 使用事务 添加
	var err error
	var merchantAccount MerchantAccount
	var cashOut CashOut
	var amountPreMerchant decimal.Decimal
	tx := orm.ShMysql.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	err = tx.Table("merchant_account").Select("*").Where("merchant_open_id = ?", merchantOpenId).Find(&merchantAccount).Error
	if err != nil {
		return err
	}

	amountPreMerchant = merchantAccount.Amount

	if merchantAccount.Amount.Cmp(merchantAmount) < 0 {
		err = errors.New("账户金额不够")
		return err
	}

	merchantAmountSub := merchantAccount.Amount.Sub(merchantAmount)
	result := tx.Table("merchant_account").Model(&merchantAccount).Where("merchant_open_id = ? and version = ?", merchantOpenId, merchantAccount.Version).Updates(
		map[string]interface{}{
			"amount":     merchantAmountSub,
			"version":    merchantAccount.Version + 1,
			"updated_at": time.Now()})
	if result.Error != nil {
		return result.Error
	}

	if result.RowsAffected <= 0 {
		err = errors.New("rows is zero")
		return err
	}

	var merchantAccountLog MerchantAccountLog

	merchantAccountLog.MerchantOpenID = merchantOpenId
	merchantAccountLog.UpdatedAt = time.Now()
	merchantAccountLog.AmountPre = amountPreMerchant
	merchantAccountLog.AmountAfter = merchantAmountSub
	merchantAccountLog.ReviewAmountAfter = merchantAccount.ReviewAmount
	merchantAccountLog.ReviewAmountPre = merchantAccount.ReviewAmount
	merchantAccountLog.Amount = merchantAmount
	merchantAccountLog.PayTransId = cashOutId
	merchantAccountLog.TransType = 2

	err = tx.Table("merchant_account_log").Create(&merchantAccountLog).Error
	if err != nil {
		return err
	}

	result = tx.Table("cash_out").Model(&cashOut).Where("id = ? ", cashOutId).Updates(
		map[string]interface{}{
			"status":         99, //体现成功
			"account_status": 99, //分账成功
			"updated_at":     time.Now()})
	if result.Error != nil {
		return result.Error
	}

	if result.RowsAffected <= 0 {
		err = errors.New("rows is zero")
		return err
	}

	return nil

}