package bigquery

import (
	"bytes"
	"context"
	"io/ioutil"
	"log"
	"reflect"
	"testing"
	"text/template"

	googlebq "cloud.google.com/go/bigquery"
	"cloud.google.com/go/storage"
	"google.golang.org/api/iterator"
	"google.golang.org/api/option"

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

func TestModelTransfer(t *testing.T) {
	config.InitConfig("config.yml", "yml", "./etc")
	ctx := context.Background()
	client, err := googlebq.NewClient(ctx, config.GetString("bigquery.projectid"),
		option.WithCredentialsFile(config.GetString("bigquery.credentialsfilepath")))
	if err != nil {
		t.Fatal(err)
	}
	defer client.Close()

	datasetID := "salesforce"

	for _, m := range models {
		err := CreateTable(client, datasetID, m.TableName(), m)
		if err != nil {
			log.Println("[error] createtable ", err)
		}
	}
	//
	//tpls := []BigQuerySFTpl{
	//	{
	//		salesforce.SFTpl{map[string]string{"q": "SELECT name, LastModifiedDate from Lead Order by LastModifiedDate desc limit 10"},
	//			"../etc/salesforce_lead.csv",
	//			salesforce.GetObejctByQuery,
	//			"pingcap-salesforce-lead",
	//			reflect.TypeOf(model.PingcapSalesforceLead{}),
	//			"",
	//			false,
	//			map[string]string{},
	//		},
	//		reflect.TypeOf([]PingcapSalesforceLead{}),
	//		PingcapSalesforceLead{}.TableName(),
	//	},
	//	{
	//		salesforce.SFTpl{map[string]string{"q": "SELECT name, LastModifiedDate from Opportunity Order by LastModifiedDate desc limit 10"},
	//			"../etc/salesforce_opportunity.csv",
	//			salesforce.GetObejctByQuery,
	//			"pingcap-salesforce-opportunity",
	//			reflect.TypeOf(model.PingcapSalesforceOpportunity{}),
	//			"",
	//			false,
	//			map[string]string{},
	//		},
	//		reflect.TypeOf([]PingcapSalesforceOpportunity{}),
	//		PingcapSalesforceOpportunity{}.TableName(),
	//	},
	//	{
	//		salesforce.SFTpl{
	//			Object:         map[string]string{"q": "SELECT name, LastModifiedDate from Account Order by LastModifiedDate desc limit 5"},
	//			FilterFile:     "../etc/salesforce_account.csv",
	//			Fn:             salesforce.GetObejctByQuery,
	//			Topic:          "m",
	//			Type:           reflect.TypeOf(model.CRMAccount{}),
	//			LastUpdateTime: "",
	//			Delete:         false,
	//		},
	//		reflect.TypeOf([]CRMAccount{}),
	//		CRMAccount{}.TableName(),
	//	},
	//}
	//
	//defaultCmpTime := "" // time.Now().AddDate(0, 0, -6).Format(time.RFC3339)
	//for i := range tpls {
	//	tpl := &tpls[i]
	//	if tpl.LastUpdateTime == "" &&
	//		!tpl.Delete {
	//		tpl.LastUpdateTime = defaultCmpTime
	//	}
	//	data := salesforce.CrmData(&tpl.SFTpl)
	//	if data == nil || len(data) == 0 {
	//		continue
	//	}
	//
	//	step := 2000
	//	for idx := 0; idx < len(data); idx += step {
	//		var dataBytes []byte
	//		if idx+step >= len(data) {
	//			dataBytes, _ = json.Marshal(data[idx:])
	//		} else {
	//			dataBytes, _ = json.Marshal(data[idx : idx+step])
	//		}
	//
	//		sliT := reflect.SliceOf(tpl.Type)
	//		SliceValue := reflect.New(sliT).Interface()
	//		json.Unmarshal(dataBytes, SliceValue)
	//		// SliceValue is a pointer, so need Elem()
	//		newData := reflect.ValueOf(SliceValue).Elem().Convert(sliT).Interface()
	//
	//		bqAccounts, _ := ModelConvert(newData, tpl.DstType)
	//		bqAccounts = reflect.ValueOf(bqAccounts).Convert(tpl.DstType).Interface()
	//		t.Logf("%+v\n", bqAccounts)
	//
	//		err := InsertTable(client, datasetID, tpl.BQTableName, bqAccounts)
	//		if err != nil {
	//			t.Fatal(err)
	//		}
	//	}
	//}
}

func TestGenMergeSQL(t *testing.T) {
	config.InitConfig("config.yml", "yml", "./etc")
	ctx := context.Background()
	client, err := googlebq.NewClient(ctx, config.GetString("bigquery.projectid"),
		option.WithCredentialsFile(config.GetString("bigquery.credentialsfilepath")))
	if err != nil {
		t.Fatal(err)
	}
	defer client.Close()

	var models []IModel
	models = append(models, &CRMAccount{}, &PingcapSalesforceLead{}, &PingcapSalesforceOpportunity{})
	funcMap := template.FuncMap{
		"dec": func(i int) int {
			return i - 1
		},
	}

	tplbytes, _ := ioutil.ReadFile("./tpl/merge.tpl")
	tpl, err := template.New("merge").Funcs(funcMap).Parse(string(tplbytes))
	if err != nil {
		t.Fatal(err)
	}

	for _, model := range models {
		reftype := reflect.TypeOf(model)
		reftype = reftype.Elem()
		fields := make([]interface{}, reftype.NumField())
		for i := 0; i < reftype.NumField(); i++ {
			fields[i] = reftype.Field(i).Name
		}

		buf := bytes.NewBuffer(nil)
		err = tpl.Execute(buf, struct {
			DataSet     string
			SourceTable string
			TmpTable    string
			PrimaryKey  string
			Fields      []interface{}
		}{"metadb_poc", model.TableName(),
			model.TableName() + "_tmp", model.PrimaryId(), fields})
		if err != nil {
			t.Fatal(err)
		}
		t.Log(buf.String())
		err = Exec(client, buf.String())
		if err != nil {
			log.Fatal(err, model.TableName())
		}
	}
}

func TestListGCS(t *testing.T) {
	config.InitConfig("config.yml", "yml", "./etc")
	ctx := context.Background()
	storageClient, err := storage.NewClient(ctx,
		option.WithCredentialsFile(config.GetString("bigquery.credentialsfilepath")))
	if err != nil {
		t.Errorf("storage.NewClient: %v", err)
	}
	defer storageClient.Close()

	it := storageClient.Bucket("metadb").Objects(ctx, &storage.Query{
		Prefix: "pingcap/tidbcloud/metadb/dbaas",
	})
	for {
		attrs, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			t.Errorf("Bucket(%q).Objects: %v", "metadb/pingcap/tidbcloud/metadb/dbaas", err)
		}
		t.Log(attrs)
		t.Log(attrs.Name)
	}
}

func TestCreateTableFromGCS(t *testing.T) {
	t.Log(UpdateTablesByGCS("pingcap/tidbcloud/metadb/dbaas"))
}

func TestOppoFieldHistory(t *testing.T) {
	historys, err := salesforce.GetOpportunityFieldHistory(true)
	if err != nil {
		t.Fatal(err)
	}

	_, err = ModelConvert(historys, reflect.TypeOf([]PingcapSalesforceOpportunityFieldHistory{}))
	if err != nil {
		t.Fatal(err)
	}
}

func TestReadOnlyQuery(t *testing.T) {
	config.InitConfig("config.yml", "yml", "./etc")
	ctx := context.Background()
	client, err := googlebq.NewClient(ctx, config.GetString("bigquery.projectid"),
		option.WithCredentialsFile("/Users/jianlinchen/cjl/work/pingcap/Digital Platform/gcpbigquery-readonly-af6f8dbfb2b8.json"))

	if err != nil {
		t.Fatal(err)
	}
	defer client.Close()

	q := client.Query("SELECT * FROM `metadb.dbaas_monthly_billing` LIMIT 1000")
	it, err := q.Read(context.Background())
	if err != nil {
		t.Fatal(err)
	}
	log.Println(it)
}

func TestCalNonProdAccountsBilling(t *testing.T) {
	config.InitConfig("config.yml", "yml", "./etc")
	err := CalNonProdAccountsBilling()
	if err != nil {
		t.Fatal(err)
	}
}
