package crm

import (
	"bytes"
	"encoding/csv"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"testing"
)

func TestFileWriteAtHole(t *testing.T) {
	fd, _ := os.OpenFile("r.t", os.O_WRONLY|os.O_CREATE, 0644)
	n, err := fd.WriteAt([]byte("323432423423"), 0)
	if err != nil {
		t.Fatal(err)
	}
	t.Log(n)
}

func TestCheckDelete(t *testing.T) {
	acToken := GetAccessToken()
	if acToken == "" {
		t.Fatal("get acToken failed")
	}
	openUserId := GetOpenUserID("18601011760", acToken)
	if openUserId == "" {
		t.Fatal("get openUserId failed")
	}
	getReq := CrmRequest{CorpAccessToken: acToken,
		CorpID: "FSCID_BBBDA0FD0A83028CD08938922C5D16DA", CurrentOpenUserID: openUserId}
	getReq.Data.ObjectDataId = "452_61c2e019117ae71feecb2380"
	getReq.Data.DataObjectAPIName = "object_h2EnS__c"
	_, err := GetCrmData(&getReq)
	if err != nil && err.Error() == "数据已作废或已删除" {
		log.Println(err)
	} else {
		log.Fatal(err)
	}
}

func TestOrder(t *testing.T) {
	//FieldDescFileName := 	"./etc/order-fielddesc.json"
	//NeedFieldFileName := "./etc/order-crm.csv"
	//crmDataFileName := "./etc/crm-order-data.json"
	fieldDescFileName := "./etc/business-opportunity-fielddesc.json"
	needFieldFileName := "./etc/business-opportunity-crm.csv"
	crmDataFileName := "./etc/crm-business-opportunity-data.json"

	fData, _ := os.ReadFile(fieldDescFileName)
	d := FieldsInfo{}
	json.Unmarshal(fData, &d)

	csvData, _ := os.ReadFile(needFieldFileName)
	csvReader := csv.NewReader(bytes.NewReader(csvData))
	csvReader.Read()
	fieldMap := make(map[string][]string)
	for {
		record, err := csvReader.Read()
		if err != nil {
			break
		}
		fieldMap[record[1]] = append(fieldMap[record[1]], record[0], record[5])
	}

	crmOrderData, _ := os.ReadFile(crmDataFileName)
	resp := CRMResp{}
	json.Unmarshal(crmOrderData, &resp)

	outputData := []map[string]interface{}{}
	for _, data := range resp.Data.DataList {
		order := map[string]interface{}{}
		for k, v := range fieldMap {
			if value, ok := data[k]; ok {
				if k == "field_sVh1u__c" {
					options := d.Data.Describe.Fields[k].Options
					for _, option := range options {
						if option.Value == value {
							order[v[0]] = option.Label
							break
						}
					}
				} else {
					order[k+"|"+v[0]] = value
				}
			} else {
				order[k+"|"+v[0]] = nil
			}
		}
		outputData = append(outputData, order)
	}

	outputDataJson, _ := json.Marshal(outputData)
	log.Println("输出: ", string(outputDataJson))
}

func TestGetAccessToken(t *testing.T) {
	acToken := GetAccessToken()
	if acToken == "" {
		t.Fatal("get acToken null")
	}

	t.Log(GetOpenUserID("18601011760", acToken))
}

func TestQueryTodoList(t *testing.T) {
	acToken := GetAccessToken()
	if acToken == "" {
		t.Fatal("get acToken failed")
	}
	openUserId := GetOpenUserID("18601011760", acToken)
	if openUserId == "" {
		t.Fatal("get openUserId failed")
	}

	requestData := CrmRequest{}
	requestData.CorpID = "FSCID_BBBDA0FD0A83028CD08938922C5D16DA"
	requestData.CorpAccessToken = acToken
	requestData.CurrentOpenUserID = openUserId
	requestData.Data.App = "ALL"
	requestData.Data.PageSize = 500

	resp, err := QueryTodoList(&requestData, Todo_URL)
	if err != nil {
		t.Fatal(err)
	}

	t.Log(len(resp.Data.TodoViewList))
	todolist := []TodoView{}
	for _, todo := range resp.Data.TodoViewList {
		switch todo.ObjectAPIName {
		case "SalesOrderObj", "QuoteObj", "object_e4icI__c":
			todolist = append(todolist, todo)
			t.Log(todo)
		}
	}
}

func TestQueryCrmOrderData(t *testing.T) {
	acToken := GetAccessToken()
	if acToken == "" {
		t.Fatal("get acToken failed")
	}
	openUserId := GetOpenUserID("18601011760", acToken)
	if openUserId == "" {
		t.Fatal("get openUserId failed")
	}

	requestData := CrmRequest{}
	requestData.CorpID = "FSCID_BBBDA0FD0A83028CD08938922C5D16DA"
	requestData.CorpAccessToken = acToken
	requestData.CurrentOpenUserID = openUserId
	requestData.Data.DataObjectAPIName = "SalesOrderObj"
	requestData.Data.SearchQueryInfo.Offset = 0
	requestData.Data.SearchQueryInfo.Limit = 100

	for {
		resp, err := QueryCrmData(&requestData, "")
		if err != nil {
			t.Fatal(err)
		}

		if resp.Data.Total > requestData.Data.SearchQueryInfo.Offset+requestData.Data.SearchQueryInfo.Limit {
			requestData.Data.SearchQueryInfo.Offset += requestData.Data.SearchQueryInfo.Limit
		} else {
			break
		}
	}
}

func TestQueryCrmBusinessOpportunityData(t *testing.T) {
	acToken := GetAccessToken()
	if acToken == "" {
		t.Fatal("get acToken failed")
	}
	openUserId := GetOpenUserID("18601011760", acToken)
	if openUserId == "" {
		t.Fatal("get openUserId failed")
	}

	requestData := CrmRequest{}
	requestData.CorpID = "FSCID_BBBDA0FD0A83028CD08938922C5D16DA"
	requestData.CorpAccessToken = acToken
	requestData.CurrentOpenUserID = openUserId
	//requestData.Data.DataObjectAPIName = "NewOpportunityObj"
	requestData.Data.DataObjectAPIName = "SalesOrderObj"
	requestData.Data.SearchQueryInfo.Offset = 0
	requestData.Data.SearchQueryInfo.Limit = 100

	for {
		resp, err := QueryCrmData(&requestData, "")
		if err != nil {
			t.Fatal(err)
		}

		t.Log(len(resp.Data.DataList))
		t.Log(resp.Data.Total)
		t.Log(resp.Data.DataList[0])

		if resp.Data.Total > requestData.Data.SearchQueryInfo.Offset+requestData.Data.SearchQueryInfo.Limit {
			requestData.Data.SearchQueryInfo.Offset += requestData.Data.SearchQueryInfo.Limit
		} else {
			break
		}
	}
}

func TestGenTableScheme(t *testing.T) {
	//needFieldFileName := "../etc/activerecord-crm.csv"
	//primaryKey := "记录ID"
	//tableName := "pingcap-crm-activityrecord"
	//needFieldFileName := "../etc/revrec-crm.csv"
	//primaryKey := "编号"
	//tableName := "pingcap-crm-revrec"
	//needFieldFileName := "../etc/business-opportunity-crm.csv"
	//primaryKey := "id"
	//tableName := "pingcap-crm-opportunity"
	needFieldFileName := "../etc/order-crm.csv"
	primaryKey := "id"
	tableName := "pingcap-crm-order"
	//NeedFieldFileName := "../etc/payment-crm.csv"
	//primaryKey := "回款核销编号"
	//tableName := "pingcap-crm-payment"
	csvData, _ := os.ReadFile(needFieldFileName)
	csvReader := csv.NewReader(bytes.NewReader(csvData))
	csvReader.Read()
	ss := strings.Builder{}
	ss.WriteString(fmt.Sprintf("CREATE TABLE `%s` (", tableName))
	for {
		record, err := csvReader.Read()
		if err != nil {
			break
		}
		desc := FieldDesc{record[1], record[0], record[6], record[3], record[5]}

		fieldType := "JsonString"
		gormString := "column:" + desc.FieldName
		typeString := "varchar(255) DEFAULT NULL"

		switch desc.Type {
		case "多行文本", "富文本":
			typeString = "TEXT DEFAULT NULL"
			gormString += ";type:text"
		case "金额", "数字", "计算字段", "百分数", "统计字段":
			typeString = "double DEFAULT NULL"
			fieldType = "JsonFloat64"
			gormString += ";type:double"
		case "日期时间":
			typeString = "bigint DEFAULT NULL"
			fieldType = "int64"
			//case "布尔值":
			//	typeString = "tinyint"
			//	fieldType = "bool"
		}

		if desc.FieldName == primaryKey {
			typeString = "varchar(255) NOT NULL"
		}
		log.Println(typeString)
		ss.WriteString(fmt.Sprintf("A%s %s `json:\"%s\" gorm:\"%s\"`", desc.FieldName, fieldType, desc.FieldName, gormString))
		//ss.WriteString(fmt.Sprintf("%s %s", desc.FieldName, typeString))
		ss.WriteString("\n")
	}
	ss.WriteString(fmt.Sprintf("PRIMARY KEY (`%s`)) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_bin", primaryKey))
	fmt.Println(ss.String())
	sqlFileName := strings.TrimRight(needFieldFileName, filepath.Ext(needFieldFileName)) + ".sql"
	fd, _ := os.OpenFile(sqlFileName, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
	fd.WriteString(ss.String())
	fd.Close()
}

func TestWashCrmData(t *testing.T) {
	acToken := GetAccessToken()
	if acToken == "" {
		t.Fatal("get acToken failed")
	}
	openUserId := GetOpenUserID("18601011760", acToken)
	if openUserId == "" {
		t.Fatal("get openUserId failed")
	}

	type crmDataSource struct {
		apiName           string
		fieldDescFileName string
		needFieldFileName string
		outputFile        string
		queryurl          string
	}

	ss := []crmDataSource{
		//{
		//	apiName:           "SalesOrderObj",
		//	fieldDescFileName: "../etc/order-fielddesc.json",
		//	needFieldFileName: "../etc/order-crm.csv",
		//	outputFile:        "../etc/order-washed-data.csv",
		//  queryurl:          "https://open.fxiaoke.com/cgi/crm/v2/data/query",
		//},
		//{
		//	apiName:           "NewOpportunityObj",
		//	fieldDescFileName: "../etc/business-opportunity-fielddesc.json",
		//	needFieldFileName: "../etc/business-opportunity-crm.csv",
		//	outputFile:        "../etc/businessopportunity-washed-data.csv",
		//  queryurl:          "https://open.fxiaoke.com/cgi/crm/v2/data/query",
		//},
		//{
		//	ApiName:           "PaymentObj",
		//	FieldDescFileName: "../etc/payment-fielddesc.json",
		//	NeedFieldFileName: "../etc/payment-crm.csv",
		//	outputFile:        "../etc/payment-washed-data.csv",
		//  queryurl:          "https://open.fxiaoke.com/cgi/crm/v2/data/query",
		//},
		//{
		//	apiName:           "ActiveRecordObj",
		//	fieldDescFileName: "../etc/activerecord-fielddesc.json",
		//	needFieldFileName: "../etc/activerecord-crm.csv",
		//	outputFile:        "../etc/activerecord-washed-data.csv",
		//  queryurl:          "https://open.fxiaoke.com/cgi/crm/v2/data/query",
		//},
		{
			apiName:           "object_wr96N__c",
			fieldDescFileName: "../etc/revrec-fielddesc.json",
			needFieldFileName: "../etc/revrec-crm.csv",
			outputFile:        "../etc/revrec-washed-data.csv",
			queryurl:          "https://open.fxiaoke.com/cgi/crm/custom/v2/data/query",
		},
	}

	for _, source := range ss {
		requestData := CrmRequest{}
		requestData.CorpID = "FSCID_BBBDA0FD0A83028CD08938922C5D16DA"
		requestData.CorpAccessToken = acToken
		requestData.CurrentOpenUserID = openUserId
		requestData.Data.DataObjectAPIName = source.apiName
		requestData.Data.SearchQueryInfo.Offset = 0
		requestData.Data.SearchQueryInfo.Limit = 100

		inputData := make([]map[string]interface{}, 0, 100)
		for {
			resp, err := QueryCrmData(&requestData, source.queryurl)
			if err != nil {
				t.Fatal(err)
			}

			for _, data := range resp.Data.DataList {
				inputData = append(inputData, data)
			}

			if resp.Data.Total > requestData.Data.SearchQueryInfo.Offset+requestData.Data.SearchQueryInfo.Limit {
				requestData.Data.SearchQueryInfo.Offset += requestData.Data.SearchQueryInfo.Limit
			} else {
				break
			}
		}

		outputData, fieldDesc := WashCrmData(source.fieldDescFileName,
			source.needFieldFileName, inputData, &requestData)
		// for test
		outputDataBytes, _ := json.Marshal(outputData.Data[0])
		fmt.Println(string(outputDataBytes))

		fd, _ := os.OpenFile(source.outputFile, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0600)
		tmpArr := make([]string, 0, len(fieldDesc))
		// to csv
		for _, field := range fieldDesc {
			tmpArr = append(tmpArr, strconv.Quote(field.FieldName))
		}
		fd.WriteString(strings.Join(tmpArr, ","))
		fd.WriteString("\n")
		for _, data := range outputData.Data {
			tmpArr = tmpArr[:0]
			for i, field := range fieldDesc {
				fieldData := data[field.FieldName]
				switch fieldData.(type) {
				case string:
					if field.Type == "金额" ||
						field.Type == "数字" ||
						field.Type == "计算字段" ||
						field.Type == "统计字段" ||
						field.Type == "百分数" {
						v, err := strconv.ParseFloat(fieldData.(string), 64)
						if err != nil {
							fd.WriteString(fieldData.(string))
						} else {
							fd.WriteString(fmt.Sprintf("%.2f", v))
						}
					} else {
						tmp := "\"" + strings.Replace(fieldData.(string), "\n", "\\n", -1) + "\""
						log.Println(tmp, fieldData, field)
						fd.WriteString(tmp)
					}

				case nil:
				case bool:
					fd.WriteString(strconv.FormatBool(fieldData.(bool)))
				case float64:
					fd.WriteString(fmt.Sprintf("%.0f", fieldData.(float64)))
				case []interface{}:
					strArr := []string{}
					for _, v := range fieldData.([]interface{}) {
						switch v.(type) {
						case map[string]interface{}:
							vBytes, _ := json.Marshal(v)
							strArr = append(strArr, strings.Replace(string(vBytes), "\"", "\"\"", -1))
						case string:
							strArr = append(strArr, v.(string))
						}
					}
					if len(strArr) != 0 {
						fd.WriteString("\"" + strings.Join(strArr, ",") + "\"")
					}
				case int:
					fd.WriteString(strconv.Itoa(fieldData.(int)))
				default:
					fmt.Printf("%T, %v\n", fieldData, fieldData)
				}

				if i != len(fieldDesc)-1 {
					fd.WriteString(",")
				} else {
					fd.WriteString("\n")
				}
			}
		}
		fd.Close()
	}
}
