package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/hyperledger/fabric/core/chaincode/shim"
	"time"
)

//券结构
type Coupons struct {
	CoupId            string         `json:"coup_id"`             //券id
	IssueOrgId        string         `json:"issue_org_id"`        //券发行机构ID
	CoupType          string         `json:"coup_type"`           //券类型
	CoupValid         string         `json:"coup_valid"`          //券有效期
	CoupAvailableTime string         `json:"coup_available_time"` //券可用时间段
	CoupDescription   string         `json:"coup_description"`    //券使用说明
	CoupQuantity      int            `json:"coup_quantity"`       //发行数量
	CoupAmount        float64        `json:"coup_amount"`         //面额
	CoupDiscount      float64        `json:"coup_discount"`       //折扣
	CoupTotalAmount   float64        `json:"coup_total_amount"`   //券总金额
	FloorAmount       float64        `json:"floor_amount"`        //券使用门槛，最低消费金额
	UseMerchats       []string       `json:"use_merchats"`        //当前券支持的商户Id
	UseMerchantsType  *MerchantsType `json:"use_merchants_type"`
	Extensions        interface{}    `json:"extensions"` //拓展信息，机构自定义
}

type MerchantsType struct {
	UseMerchatsType []int    `json:"use_merchats_type"` //当前券支持的商户类型
	OrgMerchatsType []string `json:"org_merchats_type"` //支持的机构签发类别，len 为0 表示只支持自己机构签发的
	IsAll           []bool   `json:"is_all"`            //当前券支持的商户类型是只支持自己签发的商户还是支持全部机构签发的商户
}

//券可用时间段
type CoupAvailable struct {
	AvailableDay string `json:"available_day"`
	StartTime    string `json:"start_time"`
	EndTime      string `json:"end_time"`
}

//UTXO结构
type Utxo struct {
	Address      string   `json:"address"`       //Utxo记录地址
	PublicKey    string   `json:"public_key"`    //公钥
	UserId       string   `json:"user_id"`       //用户Id,代替公钥
	Status       string   `json:"status"`        //utxo状态.0发行  1分发  2领取  3 已使用
	CoupType     string   `json:"coup_type"`     //券类型
	CoupQuantity int      `json:"coup_quantity"` //券总量
	CoupAmount   float64  `json:"coup_amount"`   //面额
	CoupDiscount float64  `json:"coup_discount"` //折扣
	FloorAmount  float64  `json:"floor_amount"`  //券使用门槛，最低消费金额
	PreAddress   []string `json:"pre_address"`   //前置utxo地址
	CoupId       string   `json:"coup_id"`       //券id
}

//订单结构
type Order struct {
	OrderId    string    `json:"order_id"`
	CreateTime time.Time `json:"create_time"`
	OrderMoney float32   `json:"order_money"`
}

//用户信息
type UserInfo struct {
	Uid        string    `json:"uid"`         //用户id
	Name       string    `json:"name"`        //用户名
	Number     string    `json:"number"`      //身份证号
	Phone      string    `json:"phone"`       //手机号
	CreateTime time.Time `json:"create_time"` //创建时间
}

//商户信息
type Merchant struct {
	Mid        string    `json:"mid"`         //商户id
	Type       string    `json:"type"`        //商户类型
	Name       string    `json:"name"`        //商户名称
	Address    string    `json:"address"`     //商户地址
	Cert       string    `json:"cert"`        //证书
	CreateTime time.Time `json:"create_time"` //创建时间
}

//渠道信息
type Ditch struct {
	Did        string    `json:"did"`         //渠道id
	Name       string    `json:"name"`        //渠道名称
	Cert       string    `json:"cert"`        //证书
	CreateTime time.Time `json:"create_time"` //创建时间
}
//机构信息
type Orgnazation struct {
	Oid       string    `json:"oid"`
	Name       string    `json:"name"`        //渠道名称
	Cert       string    `json:"cert"`        //证书
	CreateTime time.Time `json:"create_time"` //创建时间
}
// 前端传递的数据
type Message struct {
	UserId string `json:"user_id"`      // 交易发起人的用户Id
	Data      string `json:"data"`      // 交易参数
	Sign      string `json:"sign"`      // 交易签名信息，if是商户交易，这里是券公钥
}

//交易体
type Trans struct {
	Value interface{} `json:"value"`       // 拓展字段，1、用发行卡券时代表卡券信息。2、使用卡券时代表订单信息.3、查询卡券信息时代表卡券编号。
	From  string      `json:"fromAddress"` //发起方utxo地址
	To    string      `json:"toAddress"`   // 接收方utxo地址
	ToPub string      `json:"toPublicKey"` //接收者公钥
}

func putStateUtxo(key string, utxo *Utxo, stub shim.ChaincodeStubInterface) error {
	valueByte, err := json.Marshal(utxo)
	if err != nil {
		return fmt.Errorf(" %s json marshal data fail,err: %s", key, err)
	}
	err = stub.PutState(key, valueByte)
	if err != nil {
		return fmt.Errorf("putState %s data fail,err: %s", key, err)
	}
	return nil
}

func putStateStruct(key string, value interface{}, stub shim.ChaincodeStubInterface) error {
	valueByte, err := json.Marshal(value)
	if err != nil {
		return fmt.Errorf(" %s json marshal data fail,err: %s", key, err)
	}
	err = stub.PutState(key, valueByte)
	if err != nil {
		return fmt.Errorf("putState %s data fail,err: %s", key, err)
	}
	return nil
}

func putStateByte(key string, value []byte, stub shim.ChaincodeStubInterface) error {
	err := stub.PutState(key, value)
	if err != nil {
		return fmt.Errorf("putState %s data fail,err: %s", key, err)
	}
	return nil
}

func putStateCoup(key string, coupons Coupons, stub shim.ChaincodeStubInterface) error {
	valueByte, err := json.Marshal(coupons)
	if err != nil {
		return fmt.Errorf(" %s json marshal data fail,err: %s", key, err)
	}
	err = stub.PutState(key, valueByte)
	if err != nil {
		return fmt.Errorf("putState %s data fail,err: %s", key, err)
	}
	return nil
}

func getStateUtxo(key string, stub shim.ChaincodeStubInterface) (*Utxo, error) {
	var utxo *Utxo
	utxoByteInfo, err := stub.GetState(key)
	if err != nil {
		return nil, err
	}
	if utxoByteInfo == nil {
		return nil, fmt.Errorf("The query information is empty")
	}
	err = json.Unmarshal(utxoByteInfo, &utxo)
	if err != nil {
		return nil, fmt.Errorf("Byte array serialization failed")
	}
	return utxo, nil
}

func getStateCoupons(key string, stub shim.ChaincodeStubInterface) (*Coupons, error) {
	coupons := &Coupons{}
	couponsByteInfo, err := stub.GetState(key)
	if err != nil {
		return nil, err
	}
	if couponsByteInfo == nil {
		return nil, fmt.Errorf("The query information is empty")
	}
	err = json.Unmarshal(couponsByteInfo, coupons)
	if err != nil {
		return nil, fmt.Errorf("Byte array serialization failed")
	}
	return coupons, nil
}

func getStateByte(key string, stub shim.ChaincodeStubInterface) ([]byte, error) {
	byteInfo, err := stub.GetState(key)
	if err != nil {
		return nil, err
	}
	if byteInfo == nil {
		return nil, fmt.Errorf("The query information is empty")
	}
	return byteInfo, nil
}

func getStateStruct(key string, value interface{}, stub shim.ChaincodeStubInterface) (err error) {
	byteInfo, err := stub.GetState(key)
	if err != nil {
		return err
	}
	if byteInfo == nil {
		return fmt.Errorf("The query information is empty")
	}
	return json.Unmarshal(byteInfo, value)
}

func getStateByConditions(key string, stub shim.ChaincodeStubInterface) ([]byte, error) {
	resultsIterator, err := stub.GetQueryResult(key)
	defer resultsIterator.Close()
	if err != nil {
		return nil, err
	}
	var buffer bytes.Buffer
	buffer.WriteString("[")
	bArrayMemberAlreadyWritten := false
	for resultsIterator.HasNext() {
		queryResponse, err := resultsIterator.Next()
		fmt.Println(queryResponse.String())
		if err != nil {
			return nil, err
		}
		if bArrayMemberAlreadyWritten == true {
			buffer.WriteString(",")
		}
		buffer.WriteString("{\"Key\":")
		buffer.WriteString("\"")
		buffer.WriteString(queryResponse.Key)
		buffer.WriteString("\"")
		buffer.WriteString(", \"Record\":")
		buffer.WriteString(string(queryResponse.Value))
		buffer.WriteString("}")
		bArrayMemberAlreadyWritten = true
	}
	buffer.WriteString("]")
	return buffer.Bytes(), nil
}

//判断key是否存在
func checkKey(key string, stub shim.ChaincodeStubInterface) (bool, error) {
	info, err := stub.GetState(key)
	if err != nil {
		return false, err
	}
	if info == nil {
		return false, nil
	}
	return true, nil
}
