package main

import (
	"fmt"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	pb "github.com/hyperledger/fabric/protos/peer"
	"encoding/json"
	"strings"
	"encoding/hex"
)

func transactionProcess(paths, args []string, stub shim.ChaincodeStubInterface) pb.Response {
	switch paths[1] {
	case "createCoupons": //发行卡券
		return createCouponsApi(args, stub)
	case "disCoupon": //分发卡券
		return disCouponApi(args, stub)
	case "userApplyCoupon": //用户申请券
		return userApplyCouponApi(args, stub)
	case "useCoupon": //使用卡券
		return useCouponApi(args, stub)
	case "updateMertUtxo":
		return updateMertUtxoApi(args,stub)
	default:
		return shim.Error(fmt.Sprintf("Unsupported schema function of %s", paths[1]))
	}
}

//发行卡券:卡券信息
// 入参：券信息（券id、券类型、发放开始时间、券有效期、可用时间段、使用说明、发行数量、面额、券总金额、最低额度使用门槛、拓展信息）、UTXO地址、机构证书、机构签名
func createCouponsApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
	// 解析请求数据
	trans, message, _,err := messageToTrans(CreateCoupon, args, stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	//解析卡券信息
	var coupon Coupons
	expand, ok := trans.Value.(string) //判断类型
	if !ok {
		return shim.Error("Error expanding parameter type，must be string")
	}
	err = json.Unmarshal([]byte(expand), &coupon)
	if err != nil {
		return shim.Error("Parameter error" + err.Error())
	}
	boo, err := checkKey(KEY+coupon.CoupId, stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	if boo {
		return shim.Error("Coupon issue failed, coupon number already exists")
	}
	boo, err = checkKey(KEY+trans.To, stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	if boo {
		return shim.Error("Coupon issue failed, coupon number already exists")
	}
	//创建UTXO资产
	utxo := &Utxo{
		Address:      trans.To,
		UserId:       message.OwnId,
		Status:       "0",
		CoupType:     coupon.CoupType,
		CoupQuantity: coupon.CoupQuantity,
		CoupAmount:   coupon.CoupAmount,
		CoupDiscount: coupon.CoupDiscount,
		FloorAmount:  coupon.FloorAmount,
		PreAddress:   []string{""},
		CoupId:       coupon.CoupId,
	}
	err = putStateCoup(KEY+coupon.CoupId, coupon, stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	err = putStateUtxo(KEY+trans.To, utxo, stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success([]byte(stub.GetTxID()))
}

//分发卡券:
// 入参：渠道方证书、券数量、渠道utxo地址、机构utxo地址、机构签名
func disCouponApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
	// 解析请求数据
	trans, message, _,err := messageToTrans(DisCoupon, args, stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	expand, ok := trans.Value.(string) //判断类型
	if !ok {
		return shim.Error("Error expanding parameter type，must be string")
	}
	var dat map[string]interface{}
	err =json.Unmarshal([]byte(expand), &dat)
	if err != nil{
		fmt.Println(err)
	}
	//拿到机构id。
	did ,ok:= dat["did"].(string)
	if !ok {
		return shim.Error("Error expanding did parameter type，must be string")
	}
	//机构UTXO
	orgUtxo, err := getStateUtxo(KEY+trans.From, stub)
	if err != nil {
		return shim.Error("getStateUtxo error" + err.Error())
	}
	//判断渠道UTXO的地址是否已存在
	boo, err := checkKey(KEY+trans.To, stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	if boo {
		return shim.Error("Coupon distribution failed, utxo address already exists")
	}
	if orgUtxo.UserId != message.OwnId {
		return shim.Error("OwnId alignment error")
	}
	if orgUtxo.Status != "0" {
		return shim.Error("Card coupon status is abnormal and cannot be dis")
	}
	//分发卡券，资产拆分
	_amount,ok :=dat["amount"].(float64)
	if !ok {
		fmt.Println("Error expanding parameter type，amount must be int")
	}
	if orgUtxo.CoupQuantity < int(_amount){
		return shim.Error("Distribution failed, margin insufficient")
	}
	orgUtxo.CoupQuantity -= int(_amount)

	dictUtxo := &Utxo{
		Address:      trans.To,
		UserId:       did,
		Status:       "1",
		CoupType:     orgUtxo.CoupType,
		CoupQuantity: int(_amount),
		CoupAmount:   orgUtxo.CoupAmount,
		CoupDiscount: orgUtxo.CoupDiscount,
		FloorAmount:  orgUtxo.FloorAmount,
		PreAddress:   []string{trans.From},
		CoupId:       orgUtxo.CoupId,
	}
	err = putStateUtxo(KEY+trans.From, orgUtxo, stub)
	if err != nil {
		return shim.Error("putStateUtxo error " + err.Error())
	}
	err = putStateUtxo(KEY+trans.To, dictUtxo, stub)
	if err != nil {
		return shim.Error("putStateUtxo error" + err.Error())
	}
	return shim.Success([]byte(stub.GetTxID()))
}

//用户领取卡券: 一个用户只能领取一张
// 入参：utxo地址、渠道utxo地址、渠道交易签名、渠道公钥
func userApplyCouponApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
	// 解析请求数据
	trans, message,_, err := messageToTrans(ApplyCoupon, args, stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	//解析用户信息
	var user UserInfo
	expand, ok := trans.Value.(string) //判断类型
	if !ok {
		return shim.Error("Error expanding parameter type，must be string")
	}
	err = json.Unmarshal([]byte(expand), &user)
	if err != nil {
		return shim.Error("Parameter error" + err.Error())
	}
	//TODO 用户领取规则过滤

	//渠道UTXO
	dictUtxo, err := getStateUtxo(KEY+trans.From, stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	boo, err := checkKey(KEY+trans.To, stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	if boo {
		return shim.Error("Coupon apply failed, utxo address already exists")
	}
	if dictUtxo.Status != "1" {
		return shim.Error("Card coupon status is abnormal and cannot be apply")
	}
	if dictUtxo.UserId != message.OwnId {
		return shim.Error("OwnId alignment error")
	}
	if dictUtxo.CoupQuantity < 1 {
		return shim.Error("Drawing failure, insufficient margin")
	}
	dictUtxo.CoupQuantity -= 1
	userUtxo := &Utxo{
		Address:      trans.To,
		PublicKey:    trans.ToPub,
		UserId:       user.Uid,
		Status:       "2",
		CoupType:     dictUtxo.CoupType,
		CoupQuantity: 1,
		CoupAmount:   dictUtxo.CoupAmount,
		CoupDiscount: dictUtxo.CoupDiscount,
		FloorAmount:  dictUtxo.FloorAmount,
		PreAddress:   []string{dictUtxo.Address},
		CoupId:       dictUtxo.CoupId,
	}
	err = putStateUtxo(KEY+trans.To, userUtxo, stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	err = putStateUtxo(KEY+trans.From, dictUtxo, stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success([]byte(stub.GetTxID()))
}

//使用卡券:
// 入参：utxo地址、商户utxo地址、订单信息签名、商户证书、商户交易签名
func useCouponApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
	// 解析请求数据
	trans, message,_, err := messageToTrans(UseCoupon, args, stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	utxo, err := getStateUtxo(KEY+trans.From, stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	if utxo.Status != "2" {
		return shim.Error("Card coupon status is abnormal and cannot be used")
	}
	//TODO	解析订单信息，校验券使用条件是否满足.待定。
	isSupport,err := isSupportMerchants(utxo.CoupId,message.OwnId,stub)
	if err != nil{
		return shim.Error(err.Error())
	}
	if !isSupport {
		shim.Error(fmt.Sprintf("coupon %s unsupport merchant %s use",utxo.CoupId,message.OwnId))
	}
	expand, ok := trans.Value.(string) //判断类型
	if !ok {
		return shim.Error("Error expanding parameter type，must be string")
	}
	var dat map[string]interface{}
	err =json.Unmarshal([]byte(expand), &dat)
	if err != nil{
		fmt.Println(err)
	}
	order,orderSign,also,err :=parseArgsToOrderInfo(dat)
	if err != nil {
		return shim.Error(err.Error())
	}
	pub,_,err :=ParsePublicKey(utxo.PublicKey)
	if err != nil {
		return shim.Error("PublicKey ParsePublicKey error,"+err.Error())
	}
	signature,err := hex.DecodeString(orderSign)
	if err != nil{
		return shim.Error("orderSign  DecodeString  error,"+err.Error())
	}
	//TODO 验证订单签名信息
	err = checkSignature(also,[]byte(order),[]byte(signature),pub)
	if err != nil {
		return shim.Error(err.Error())
	}
	//_,pubKey,err := ParsePrivateKey(privHex)
	//pubHex := hex.EncodeToString(pubKey)
	//if utxo.PublicKey != pubHex {
	//	return shim.Error("coupons verify error")
	//}
	utxo.Status = "3"
	var mertNewUtxo Utxo
	mertByteUtxo, _ := stub.GetState(KEY+trans.To)
	//判断是否存在。存在修改，不存在初始化一条
	if mertByteUtxo == nil {
		mertNewUtxo = Utxo{
			Address:      trans.To,
			UserId:       message.OwnId ,
			Status:       "4",
			CoupType:     utxo.CoupType,
			CoupQuantity: utxo.CoupQuantity,
			CoupAmount:   utxo.CoupAmount,
			CoupDiscount: utxo.CoupDiscount,
			FloorAmount:  utxo.FloorAmount,
			PreAddress:   []string{trans.From},
			CoupId:       utxo.CoupId,
		}
	}else {
		_ =json.Unmarshal(mertByteUtxo,&mertNewUtxo)
		mertNewUtxo.CoupQuantity += 1
		mertNewUtxo.PreAddress = append(mertNewUtxo.PreAddress,trans.From)
	}
	err = putStateUtxo(KEY+trans.From, utxo, stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	err = putStateUtxo(KEY+trans.To, &mertNewUtxo, stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success([]byte(stub.GetTxID()))
}

//修改商户utxo===清分。券未被领取、领取了未使用。
//入参：商户utxo地址、公钥、二维码utxo地址（数组）
func updateMertUtxoApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
	// 解析请求数据
	trans, _, _,err := messageToTrans(UseCoupon, args, stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	expand, ok := trans.Value.(string) //判断类型
	if !ok {
		return shim.Error("Error expanding parameter type，must be string")
	}
	var dat map[string]interface{}
	err =json.Unmarshal([]byte(expand),&dat)
	if err != nil {
		return shim.Error("Unmarshal error" + err.Error())
	}

	str,ok :=dat["uAddress"].(string)
	if !ok {
		return shim.Error("Error expanding parameter type，uAddress must be string")
	}
	//mid,ok :=dat["mid"].(string)
	//if !ok {
	//	return shim.Error("Error expanding parameter type，mid must be string")
	//}
	utxo,err :=getStateUtxo(trans.From,stub)
	if err != nil {
		return shim.Error(err.Error())
	}
	if utxo.PublicKey != trans.ToPub {
		return shim.Error("")
	}
	arr :=strings.Split(str,"=")
	for _,value1 := range arr{
		for b,value2 := range  utxo.PreAddress{
			if  value1 == value2{
				fmt.Println(b)

			}
		}
	}

	return shim.Success(nil)
}

/*
	检查商户是否支持券使用
*/
func isSupportMerchants(couponId,merId string ,stub shim.ChaincodeStubInterface)(support bool,err error){
	coupons ,err := getStateCoupons(KEY+couponId,stub)
	if err!=nil{
		return
	}
	for _,id:= range coupons.UseMerchats{
		if merId == id{
			support = true
			return
		}
	}
	return
}