package main

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

func certManagement(paths, args []string, stub shim.ChaincodeStubInterface) pb.Response {
	switch paths[1] {
	case "createOrg": //机构认证
		return createOrgApi(args, stub)
	case "createDitch": //渠道方入驻
		return createDitchApi(args, stub)
	case "createMerchants": //商户入驻  .证书操作、 注销、解锁  （签名、证书）
		return createMerchantsApi(args, stub)
	case "ditchCertBurn": //渠道用户证书注销
		return certUpdateDitchApi(args, stub)
	case "merchantCertBurn": //商户证书注销
		return certUpdateMerchantApi(args, stub)
	case "ditchCertUnLock": //渠道用户证书解锁
		return certUpdateMerchantApi(args, stub)
	case "merchantCertUnLock": //商户证书解锁
		return certUpdateMerchantApi(args, stub)
	default:
		return shim.Error(fmt.Sprintf("Unsupported cert function of %s", paths[1]))
	}
}

//机构认证
func createOrgApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
	if len(args) < 1 {
		return shim.Error("put data operation expected more than 2 parameters! ")
	}
	org := &Orgnazation{}
	err := json.Unmarshal([]byte(args[0]),org)
	if err != nil{
		return shim.Error(err.Error())
	}
	cert,err := ParseCertificate([]byte(org.Cert))
	if err != nil{
		return shim.Error(err.Error())
	} else if cert.CertType != OrganizationCert {
		return shim.Error("certificate type must organization")
	}

	//TODO  机构的认证规则待定
	key := KEY + org.Oid
	err = putStateByte(key,[]byte(args[0]),stub)
	if err != nil{
		return shim.Error(err.Error())
	}
	return shim.Success(nil)
}

/*渠道方入驻
	Parameters:
		args:args[0]:为机构签发者 args[1]：为渠道证书
*/
func createDitchApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
	if len(args) < 2 {
		return shim.Error("put data operation expected more than 2 parameters! ")
	}
	orgByte,err := getStateByte(KEY + args[0],stub)
	if err != nil{
		return shim.Error(err.Error())
	}
	org := &Orgnazation{}
	err = json.Unmarshal(orgByte,org)
	if err != nil{
		return shim.Error(err.Error())
	}
	cert,err := ParseCertificate([]byte(org.Cert))
	if err != nil{
		return shim.Error(err.Error())
	} else if cert.CertType != OrganizationCert {
		return shim.Error("certificate creater type must organization")
	}
	ditch := &Ditch{}
	err = json.Unmarshal([]byte(args[1]),ditch)
	if err != nil{
		return shim.Error(err.Error())
	}
	channelCert,err := ParseCertificate([]byte(ditch.Cert))
	if err != nil{
		return shim.Error(err.Error())
	} else if channelCert.CertType != ChannelCert {
		return shim.Error("certificate type must channel")
	}
	err = channelCert.CheckSignatureFrom(cert)
	if err != nil{
		return shim.Error(err.Error())
	}
	key := KEY+ditch.Did
	err = putStateByte(key,[]byte(args[1]),stub)
	if err != nil{
		return shim.Error(err.Error())
	}
	return shim.Success(nil)
}

/*
	商户入驻
	Parameters:
		args:args[0]:为机构签发者 args[1]：为商户证书
*/
func createMerchantsApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
	if len(args) < 2 {
		return shim.Error("put data operation expected more than 2 parameters! ")
	}
	orgByte,err := getStateByte(KEY + args[0],stub)
	if err != nil{
		return shim.Error(err.Error())
	}
	org := &Orgnazation{}
	err = json.Unmarshal(orgByte,org)
	if err != nil{
		return shim.Error(err.Error())
	}
	cert,err := ParseCertificate([]byte(org.Cert))
	if err != nil{
		return shim.Error(err.Error())
	} else if cert.CertType != OrganizationCert {
		return shim.Error("certificate creater type must organization")
	}
	merchant := &Merchant{}
	err = json.Unmarshal([]byte(args[1]),merchant)
	if err != nil{
		return shim.Error(err.Error())
	}
	merchantCert,err := ParseCertificate([]byte(merchant.Cert))
	if err != nil{
		return shim.Error(err.Error())
	} else if merchantCert.CertType != MerchantCert {
		return shim.Error("certificate type must merchant ")
	}
	err = merchantCert.CheckSignatureFrom(cert)
	if err != nil{
		return shim.Error(err.Error())
	}
	key := KEY+merchant.Mid
	err = putStateByte(key,[]byte(args[1]),stub)
	if err != nil{
		return shim.Error(err.Error())
	}
	return shim.Success(nil)
}

/*
	证书注销,直接修改证书的过期时间
	Parameters:
		args:args[0]:为机构签发者 args[1]：为渠道证书
*/
func certUpdateDitchApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
	if len(args) < 2 {
		return shim.Error("put data operation expected more than 2 parameters! ")
	}
	orgByte,err := getStateByte(KEY + args[0],stub)
	if err != nil{
		return shim.Error(err.Error())
	}
	org := &Orgnazation{}
	err = json.Unmarshal(orgByte,org)
	if err != nil{
		return shim.Error(err.Error())
	}
	cert,err := ParseCertificate([]byte(org.Cert))
	if err != nil{
		return shim.Error(err.Error())
	}else if cert.CertType != OrganizationCert {
		return shim.Error("certificate updater type must organization")
	}
	ditch := &Ditch{}
	err = json.Unmarshal([]byte(args[1]),ditch)
	if err != nil{
		return shim.Error(err.Error())
	}
	subCert,err := ParseCertificate([]byte(ditch.Cert))
	if err != nil{
		return shim.Error(err.Error())
	}
	err = subCert.CheckSignatureFrom(cert)
	if err != nil{
		return shim.Error(err.Error())
	}
	key := KEY+ditch.Did
	_,err = getStateByte(key,stub)
	if err != nil{
		return shim.Error(err.Error())
	}
	err = putStateByte(key,[]byte(args[1]),stub)
	if err != nil{
		return shim.Error(err.Error())
	}
	return shim.Success(nil)
}


/*
	证书注销,直接修改证书的过期时间
	Parameters:
		args:args[0]:为机构签发者 args[1]：为渠道证书
*/
func certUpdateMerchantApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
	if len(args) < 2 {
		return shim.Error("put data operation expected more than 2 parameters! ")
	}
	orgByte,err := getStateByte(KEY + args[0],stub)
	if err != nil{
		return shim.Error(err.Error())
	}
	org := &Orgnazation{}
	err = json.Unmarshal(orgByte,org)
	if err != nil{
		return shim.Error(err.Error())
	}
	cert,err := ParseCertificate([]byte(org.Cert))
	if err != nil{
		return shim.Error(err.Error())
	}else if cert.CertType != OrganizationCert {
		return shim.Error("certificate updater type must organization")
	}
	merchant := &Merchant{}
	err = json.Unmarshal([]byte(args[1]),merchant)
	if err != nil{
		return shim.Error(err.Error())
	}
	subCert,err := ParseCertificate([]byte(merchant.Cert))
	if err != nil{
		return shim.Error(err.Error())
	}
	err = subCert.CheckSignatureFrom(cert)
	if err != nil{
		return shim.Error(err.Error())
	}
	key := KEY+merchant.Mid
	_,err = getStateByte(key,stub)
	if err != nil{
		return shim.Error(err.Error())
	}
	err = putStateByte(key,[]byte(args[1]),stub)
	if err != nil{
		return shim.Error(err.Error())
	}
	return shim.Success(nil)
}

/*
	证书解锁,直接修改证书的过期时间
	Parameters:
		args:args[0]:为机构签发者 args[1]：为渠道证书
*/
func certUnLockApi(args []string, stub shim.ChaincodeStubInterface) pb.Response {
	if len(args) < 2 {
		return shim.Error("put data operation expected more than 2 parameters! ")
	}
	return shim.Success(nil)
}

/*
	进行用户交易验证
*/
func CheckCertSignature( message *Message,txType TxType,stub shim.ChaincodeStubInterface)(pubKey string,err error){
	cert := &Certificate{}
	switch txType {
	case CreateCoupon:
		cert ,err = getCert(message.OwnId,0,stub)
		if err != nil{
			return
		}
		pubKey = hex.EncodeToString(cert.PublicKeyByte)
		if cert.CertType != OrganizationCert{
			return "",errors.New("only organization account can create coupon")
		}
	case DisCoupon:
		cert ,err = getCert(message.OwnId,0,stub)
		if err != nil{
			return
		}
		pubKey = hex.EncodeToString(cert.PublicKeyByte)
		if cert.CertType != OrganizationCert{
			return "",errors.New("only organization account can distribute coupon")
		}
	case ApplyCoupon:
		cert ,err = getCert(message.OwnId,1,stub)
		if err != nil{
			return
		}
		pubKey = hex.EncodeToString(cert.PublicKeyByte)
		if cert.CertType != ChannelCert{
			return "",errors.New("only channel account can create apply coupon transaction")
		}
	case UseCoupon:
		cert ,err = getCert(message.OwnId,2,stub)
		if err != nil{
			return
		}
		pubKey = hex.EncodeToString(cert.PublicKeyByte)
		if cert.CertType != MerchantCert{
			return "",errors.New("only merchant account can create use coupon transaction")
		}
	default:
		return "",errors.New("Unsupported transaction types")
	}
	// 检查交易时间是否在证书有效期内
	//timestamp,err := stub.GetTxTimestamp()
	//fmt.Println(timestamp.Seconds)
	//fmt.Println(cert.NotBefore)
	//fmt.Println(cert.NotAfter)
	//if !(cert.NotBefore < timestamp.Seconds && cert.NotAfter > timestamp.Seconds) {
	//	return "",errors.New("cert expired ")
	//}
	var algo SignatureAlgorithm
	if cert.PublicKeyHashAlgorithm == crypto.Hash(21){
		algo = SM2WithSM3
	}else {
		algo = ECDSAWithSHA256
	}
	//signed,err := hex.DecodeString(message.Data)
	//if err != nil{
	//	return
	//}
	signature,err := hex.DecodeString(message.Sign)
	if err != nil{
		return
	}
	err = cert.CheckSignature(algo,[]byte(message.Data),signature)
	return
}

/*
	得到证书并解析
*/
func getCert(userId string,userType int,stub shim.ChaincodeStubInterface)( cert *Certificate, err error){
	switch userType {
	case 0 :
		org := &Orgnazation{}
		orgByte,err := getStateByte(KEY+userId,stub)
		if err != nil{
			return nil,err
		}
		err = json.Unmarshal(orgByte,org)
		if err != nil{
			return nil,err
		}
		cert,err = ParseCertificate([]byte(org.Cert))
		if err != nil{
			return nil,err
		} else if cert.CertType != OrganizationCert {
			 err = errors.New("certificate type must organization")
			return nil,err
		}
	case 1:
		ditch := &Ditch{}
		ditchByte,err := getStateByte(KEY+userId,stub)
		if err != nil{
			return nil,err
		}
		err = json.Unmarshal(ditchByte,ditch)
		if err != nil{
			return nil,err
		}
		cert,err = ParseCertificate([]byte(ditch.Cert))
		if err != nil{
			return nil,err
		} else if cert.CertType != ChannelCert {
			err = errors.New("certificate type must ditch")
			return nil,err
		}
	case 2:
		mer := &Merchant{}
		merByte,err := getStateByte(KEY+userId,stub)
		if err != nil{
			return nil,err
		}
		err = json.Unmarshal(merByte,mer)
		if err != nil{
			return nil,err
		}
		cert,err = ParseCertificate([]byte(mer.Cert))
		if err != nil{
			return nil,err
		} else if cert.CertType != MerchantCert {
			err = errors.New("certificate type must merchant")
			return nil,err
		}
	default:
		err = errors.New("unsupport user type ")
	}
	return
}
