package salesforce

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

	"github.com/pingcap/crm-bot/model"
	"github.com/pingcap/crm-bot/pkg/config"
	"github.com/pingcap/crm-bot/pkg/db"
)

func TestGetObejct(t *testing.T) {
	_, _ = GetCurrencyRate()

	token, err := GetAuthToken()
	if err != nil {
		t.Fatal(err)
	}
	obj, err := GetObejct(token, "Opportunity")
	if err != nil {
		t.Fatal(err)
	}

	t.Log(len(obj.(*SalfeForceObjectData).RecentItems))
}

func TestGetObejctByQuery(t *testing.T) {
	token, err := GetAuthToken()
	if err != nil {
		t.Fatal(err)
	}
	params := map[string]string{
		"q": "SELECT name from Order",
	}
	obj := &SalfeForceObjectQueryData{}
	err = GetObejctByQuery(token, params, obj)
	if err != nil {
		t.Fatal(err)
	}

	t.Log(len(obj.GetRecentItem()))
}

func TestGetAuthToken(t *testing.T) {
	token, err := GetAuthToken()
	if err != nil {
		t.Fatal(err)
	}

	t.Log(token)
}

func TestGetRow(t *testing.T) {
	token, err := GetAuthToken()
	if err != nil {
		t.Fatal(err)
	}
	data, err := GetRow("/services/data/v52.0/sobjects/Opportunity/0065g000007wo7mAAA", token)
	if err != nil {
		t.Fatal(err)
	}

	t.Log(data)
}

func TestWashData(t *testing.T) {
	tpls := []struct {
		obejct     interface{}
		filterFile string
		fn         func(string, interface{}, IObjectData) error
		data       interface{}
	}{
		//{map[string]string{"q": "SELECT name from Opportunity"}, "../etc/salesforce_opportunity.csv", GetObejctByQuery, nil},
		//{map[string]string{"q": "SELECT name from Lead"}, "../etc/salesforce_lead.csv", GetObejctByQuery},
		//{map[string]string{"q": "SELECT name from Order"}, "../etc/salesforce_order.csv", GetObejctByQuery, nil},
		//{map[string]string{"q": "SELECT name from PoC__c"},
		//	"../etc/salesforce_poc.csv", GetObejctByQuery,
		//	[]model.PingcapSalesforcePoc{},
		//},
		//{map[string]string{"q": "SELECT name from Revenue__c"},
		//	"../etc/salesforce_revrec.csv", GetObejctByQuery,
		//	[]model.PingcapSalesforceRevrec{},
		//},
		{map[string]string{"q": "SELECT subject from Task"},
			"../etc/salesforce_task.csv", GetObejctByQuery,
			[]model.PingcapSalesforceRevrec{},
		},
	}

	autoToken, err := GetAuthToken()
	if err != nil {
		t.Fatal(err)
	}

	concurrency := 50
	ch := make(chan struct{}, concurrency)
	for i := 0; i < concurrency; i++ {
		ch <- struct{}{}
	}

	for i := range tpls {
		tpl := tpls[i]
		recentItems := []RecentItem{}
		var iObjectData IObjectData
		iObjectData = &SalfeForceObjectQueryData{}
		err := tpl.fn(autoToken, tpl.obejct, iObjectData)
		if err != nil {
			t.Fatal(err)
		}

		for {
			recentItems = append(recentItems, iObjectData.GetRecentItem()...)
			if iObjectData.IsDone() {
				break
			}

			iObjectData, err = GetObjectData(iObjectData.NextURL(), autoToken)
			if err != nil {
				log.Fatal(err)
			}
		}

		var lock sync.Mutex
		var wg sync.WaitGroup
		datas := []map[string]interface{}{}
		for _, item := range recentItems {
			<-ch
			tmpItem := item
			wg.Add(1)
			go func() {
				defer wg.Done()
				data, err := GetRow(tmpItem.Attributes.URL, autoToken)
				if err != nil {
					panic(err)
				}

				lock.Lock()
				datas = append(datas, data)
				lock.Unlock()
				ch <- struct{}{}
			}()
		}

		wg.Wait()
		output := WashData(datas, tpl.filterFile, autoToken)
		for _, d := range output {
			if accountId, ok := d["AccountID"]; ok {
				log.Println(accountId, d)
			}
		}
		jbytes, _ := json.Marshal(output[0])
		fmt.Println(string(jbytes))
	}
}

func TestGenTableScheme(t *testing.T) {
	tpls := []struct {
		filename   string
		primarykey string
		talbename  string
	}{
		{"../etc/salesforce_order.csv", "Id", "pingcap_salesforce_order"},
		{"../etc/salesforce_opportunity.csv", "Id", "pingcap_salesforce_opportunity"},
		{"../etc/salesforce_lead.csv", "Id", "pingcap_salesforce_lead"},
		{"../etc/salesforce_poc.csv", "PoCNumber", "pingcap_salesforce_poc"},
		{"../etc/salesforce_revrec.csv", "OrderNumber", "pingcap_salesforce_revrec"},
		{"../etc/salesforce_task.csv", "Subject", "pingcap_salesforce_task"},
	}

	for _, tpl := range tpls {
		csvData, _ := os.ReadFile(tpl.filename)
		csvReader := csv.NewReader(bytes.NewReader(csvData))
		csvReader.Read()
		ss := strings.Builder{}
		ss.WriteString(fmt.Sprintf("CREATE TABLE `%s` (", tpl.talbename))
		for {
			record, err := csvReader.Read()
			if err != nil {
				break
			}
			desc := FieldDesc{record[0], record[1], record[2], record[3]}
			typeString := "varchar(255) DEFAULT NULL"
			if strings.Contains(desc.FieldType, "Currency") ||
				strings.Contains(desc.FieldType, "Summary") {
				typeString = "double DEFAULT NULL"
			} else if desc.FieldType == "Date" {
				typeString = "date DEFAULT NULL"
			} else if desc.FieldType == "DateTime" {
				typeString = "datetime DEFAULT NULL"
			} else if desc.FieldLable == tpl.primarykey {
				typeString = "varchar(255) NOT NULL"
			}

			ss.WriteString(fmt.Sprintf("`%s` %s,", desc.FieldLable, typeString))
			ss.WriteString("\n")
		}
		ss.WriteString(fmt.Sprintf("PRIMARY KEY (`%s`)) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci", tpl.primarykey))
		fmt.Println(ss.String())
		sqlFileName := strings.TrimSuffix(tpl.filename, filepath.Ext(tpl.filename)) + ".sql"
		fd, _ := os.OpenFile(sqlFileName, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
		fd.WriteString(ss.String())
		fd.Close()
	}

}

func TestGetOpportunityFieldHistory(t *testing.T) {
	config.InitConfig("config.yml", "yml", "./etc")
	gdb, err := db.InitDb(config.GetString("db"))
	if err != nil {
		t.Fatal(err)
	}
	gdb.AutoMigrate(&model.PingcapSalesforceOpportunityFieldHistory{})
	historys, err := GetOpportunityFieldHistory(true)
	if err != nil {
		t.Fatal(err)
	}

	err = gdb.Save(historys).Error
	if err != nil {
		t.Fatal(err)
	}
}
