package models

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha1"
	"crypto/sha256"
	"encoding/hex"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

/* 	ocr := YiDsOcr{}
resultM := ocr.New().UrlAddSignIsPostUrl().PostGetAllJson(this.GetString("image")).RemoveOtherGetItems().GetItemM()
fmt.Println(resultM) */

type YiDsOcr struct {
	host        string
	urlPath     string
	url         string
	query       string
	AccessKey   string
	Secretkey   string
	Sign        string
	RequestType string
	PostUrl     string
	AllJson     string

	items  string
	i      int
	itemsM map[int]string
}

// ok
func (this *YiDsOcr) New() *YiDsOcr {
	this.RequestType = "GET"
	this.AllJson = ""
	this.host = "https://api-wuxi-1.cmecloud.cn:8443"
	this.urlPath = "/api/ocr/v1/general"
	this.url = this.host + this.urlPath
	this.AccessKey = "566fb5cc631047c9b8e330246522c6a9"
	this.Secretkey = "cbea3dde4d414ef3915a570d1f61afb0"
	bq := "AccessKey=" + this.AccessKey +
		"&SignatureMethod=HmacSHA1&SignatureNonce=" + this.Sha1(strconv.Itoa(int(time.Now().Unix()))) +
		"&SignatureVersion=V2.0&Timestamp=" + time.Now().Format("2006-01-02T15:04:05Z") +
		"&Version=2016-12-05"
	this.query = bq

	this.items = ""
	this.i = 0
	this.itemsM = make(map[int]string)
	return this
}

func (this *YiDsOcr) Sha256(str string) string {
	m := sha256.New()
	m.Write([]byte(str))
	res := hex.EncodeToString(m.Sum(nil))
	return res
}

func (this *YiDsOcr) Sha1(s string) string {
	o := sha1.New()
	o.Write([]byte(s))
	res := hex.EncodeToString(o.Sum(nil))
	return res
}

func (this *YiDsOcr) HmacSha1(v, keyStr string) string {
	h := sha1.New()
	io.WriteString(h, v)
	h.Sum(nil)
	//hmac ,use sha1
	key := []byte(keyStr)
	mac := hmac.New(sha1.New, key)
	// mac := hmac.New(md5.New, key)
	mac.Write([]byte(v))
	a := fmt.Sprintf("%x", mac.Sum(nil))
	return a
}

func (this *YiDsOcr) UrlAddSignIsPostUrl() *YiDsOcr {
	this.RequestType = "POST"
	Urr := this.url + "?" + this.query + "&Signature=" + this.GetSign()
	this.PostUrl = Urr
	return this

}

func (this *YiDsOcr) Pencode(str string) string {
	str = strings.Replace(str, "+", "%20", -1)
	str = strings.Replace(str, "*", "%2A", -1)
	str = strings.Replace(str, "%7E", "~", -1)
	return str

}

func (this *YiDsOcr) ToASCII(str string) string {
	s := strconv.QuoteToASCII(str)
	true_utf := s[1 : len(s)-1]
	return true_utf
}

func (this *YiDsOcr) GetSign() string {
	m := make(map[int]map[string]string)
	uri := this.query
	if len(uri) < 1 { // 空字符串
		return "error"
	}
	if uri[0:1] == "?" { // 有没有包含？,有的话忽略。
		uri = uri[1:]
	}

	// 首先分解&（sessionid=22222&token=3333 )变成
	// sessionid=222222 和 token=3333
	pars := strings.Split(uri, "&")
	i := 0
	for _, par := range pars {
		mm := make(map[string]string)
		// 然后分解 sessionid=222222 和 token=3333
		parkv := strings.Split(par, "=")
		mm[parkv[0]] = parkv[1] // 等号前面是key,后面是value
		m[i] = mm
		i++
	}
	result := ""
	for i := 0; i < len(m); i++ {
		for k, v := range m[i] {
			result = result + this.Pencode(url.QueryEscape(this.ToASCII(k))) + "=" + this.Pencode(url.QueryEscape(this.ToASCII(v))) + "&"
		}
	}
	result = result[0 : len(result)-1]

	//url utf8编码
	re := this.RequestType + "\n" +
		this.Pencode(url.QueryEscape(this.urlPath)) + "\n" +
		this.Sha256(result)
	key := this.ToASCII("BC_SIGNATURE&" + this.Secretkey)
	res := this.HmacSha1(re, key)

	return url.QueryEscape(res)
}

// ok
func (this *YiDsOcr) Parse_str(uri string) (map[string]string, error) {
	m := make(map[string]string)
	if len(uri) < 1 { // 空字符串
		return m, errors.New("uri is none")
	}
	if uri[0:1] == "?" { // 有没有包含？,有的话忽略。
		uri = uri[1:]
	}

	// 首先分解&（sessionid=22222&token=3333 )变成
	// sessionid=222222 和 token=3333
	pars := strings.Split(uri, "&")
	for _, par := range pars {
		// 然后分解 sessionid=222222 和 token=3333
		parkv := strings.Split(par, "=")
		m[parkv[0]] = parkv[1] // 等号前面是key,后面是value
	}
	return m, nil
}

// 注意一点js 发送的Base64必须把头文件去除 不然报错 这API要求不能包含有头文件
func (this *YiDsOcr) PostGetAllJson(base64 string) *YiDsOcr {
	bodys := "{\"image\": \"" + base64 + "\"}"
	//fmt.Println(bodys)
	req, _ := http.NewRequest("POST", this.PostUrl, bytes.NewBuffer([]byte(bodys)))
	req.Header.Set("Content-Type", "application/json; charset=UTF-8")
	client := &http.Client{}
	resp, err2 := client.Do(req)
	if err2 != nil {
		return nil
	}
	defer resp.Body.Close()
	// fmt.Println("status", resp.Status)
	// fmt.Println("headers", resp.Header)
	body, _ := ioutil.ReadAll(resp.Body)
	this.AllJson = string(body)
	return this
}

// 过滤掉不需要的 只要返回内容 items
func (this *YiDsOcr) RemoveOtherGetItems() *YiDsOcr {
	//fmt.Println(restr)
	start := strings.Index(this.AllJson, "items")
	end := strings.Index(this.AllJson, "class")
	this.items = this.AllJson[start+7 : end-2]
	this.items = strings.ReplaceAll(this.items, " ", "")
	return this
}

// items 长在3000多个字符串中 找到对应 "itemstring":后面的值 合并到一个 map[int]string 想要的数据都在这里面
func (this *YiDsOcr) GetItemM() map[int]string {
	start := -1
	end := 0
	if strings.Index(this.items, "itemstring") != -1 {
		start = strings.Index(this.items, "itemstring") + 12
		this.items = this.items[start:]
		end = strings.Index(this.items, ",")
		this.itemsM[this.i] = this.items[0:end]
		this.items = this.items[end+1:]
		this.i++
		this.GetItemM()
	}
	this.AllJson = ""
	this.i = 0
	return this.itemsM
}
