package charset_gbk

import (
	"database/sql"
	"flag"
	"net/url"

	_ "github.com/go-sql-driver/mysql"
	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"

	"github.com/pingcap/test-infra/caselib/pkg/host"
	"github.com/pingcap/test-infra/sdk/core"
	"github.com/pingcap/test-infra/sdk/resource"
	_ "github.com/pingcap/test-infra/sdk/resource/impl/k8s"

	. "github.com/pingcap/endless/pkg/matcher"
	. "github.com/pingcap/endless/pkg/util"
)

func must(err error) {
	if err != nil {
		Fail(err.Error())
	}
}

var tiupTopo = `
global:
  user: "tidb"
  ssh_port: 22
  deploy_dir: "/tiup/deploy"
  data_dir: "/tiup/data"
  arch: "amd64"

monitored:
  node_exporter_port: 19100
  blackbox_exporter_port: 19115

server_configs:
  tikv:
    coprocessor.region-max-size: 16MB
    coprocessor.region-split-size: 4MB
    raftstore.region-split-check-diff: 1MB
    storage.block-cache.capacity: 1GB

pd_servers:
  - host: pd-peer
    client_port: 12379
    peer_port: 12380

tidb_servers:
  - host: tidb-peer
    port: 14000
    status_port: 20080

tikv_servers:
  - host: tikv1-peer
    port: 30160
    status_port: 30180

monitoring_servers:
  - host: tiup-peer
    port: 19090

grafana_servers:
  - host: tiup-peer
    port: 13000
`

var tiupTopoWithNewCollation = `
global:
  user: "tidb"
  ssh_port: 22
  deploy_dir: "/tiup/deploy"
  data_dir: "/tiup/data"
  arch: "amd64"

monitored:
  node_exporter_port: 19100
  blackbox_exporter_port: 19115

server_configs:
  tidb:
    new_collations_enabled_on_first_bootstrap: true
  tikv:
    coprocessor.region-max-size: 16MB
    coprocessor.region-split-size: 4MB
    raftstore.region-split-check-diff: 1MB
    storage.block-cache.capacity: 1GB

pd_servers:
  - host: pd-peer
    client_port: 12379
    peer_port: 12380

tidb_servers:
  - host: tidb-peer
    port: 14000
    status_port: 20080

tikv_servers:
  - host: tikv1-peer
    port: 30160
    status_port: 30180

monitoring_servers:
  - host: tiup-peer
    port: 19090

grafana_servers:
  - host: tiup-peer
    port: 13000
`

var (
	ctx            core.TestContext
	workloadNode   resource.WorkloadNode
	cluster        *host.TiUPCluster
	dbURL          *url.URL
	targetVersion  string
	installVersion string
)

// 1 tiup
// 1 pd
// 1 tikv
// 1 tidb
// 1 wkload
var _ = ParameterizedDescribe("TiKV", func(flagSet *flag.FlagSet) {
	// targetVersion = "v6.0.0"
	ctx = suiteTestCtx
	targetVersion = ctx.Param("target_version")
	installVersion = ctx.Param("init_version")

	// ctx, _ = utils.GetCtxAndLogger()
	workloadNode = ctx.Resource("tiup").(resource.WorkloadNode)

	// create v4.0.10 tidb cluster
	Context("cluster install", func() {
		It("[precheck]upgrade_test, should pass if you install a cluster with tiup #precheck_install#", func() {
			TiupCreate(workloadNode, installVersion, tiupTopo)
		})
	})

	Context("[precheck]charset_gbk upgrade test", func() {
		TestCase("charset gbk update", "gbk001", func() {
			GBKBeforeUpdateTest()
		})
	})

	Context("[postcheck]charset_gbk upgrate test, tiup upgrade", func() {
		TestCase("upgrade", "tiup_upgrade_01", func() {
			TiupUpdate("new_collations_enabled_on_first_bootstrap = true")
		})
	})

	Context("[postcheck]charset_gbk upgrade test", func() {
		TestCase("charset gbk update", "gbk002", func() {
			GBKAfterUpdateTest(false)
		})
	})

	Context("[postcheck]charset_gbk upgrade test, tiup destroy", func() {
		TestCase("destory", "tiup_destory_01", func() {
			TiupDestroy()
		})
	})

	// creat a v4.0.10 tidb cluster with new_collations_enabled_on_first_bootstrap = true
	Context("cluster install", func() {
		It("[precheck]upgrade_test, should pass if you install a cluster with tiup #precheck_install#", func() {
			TiupCreate(workloadNode, installVersion, tiupTopoWithNewCollation)
		})
	})

	Context("[precheck]charset_gbk upgrade test", func() {
		TestCase("charset gbk update", "gbk003", func() {
			GBKBeforeUpdateTest()
		})
	})

	Context("[postcheck]charset_gbk upgrate test, tiup upgrade", func() {
		TestCase("upgrade", "tiup_upgrade_02", func() {
			TiupUpdate("")
		})
	})

	Context("[postcheck]charset_gbk upgrade test", func() {
		TestCase("charset gbk update", "gbk004", func() {
			GBKAfterUpdateTest(true)
		})
	})

	Context("[postcheck]charset_gbk upgrade test, tiup destroy", func() {
		TestCase("destory", "tiup_destory_02", func() {
			TiupDestroy()
		})
	})

	// creat a v3.0.11 tidb cluster
	Context("cluster install", func() {
		It("[precheck]upgrade_test, should pass if you install a cluster with tiup #precheck_install#", func() {
			TiupCreate(workloadNode, "v3.0.11", tiupTopo)
		})
	})

	Context("[precheck]charset_gbk upgrade test", func() {
		TestCase("charset gbk update", "gbk005", func() {
			GBKBeforeUpdateTest()
		})
	})

	Context("[postcheck]charset_gbk upgrate test, tiup upgrade", func() {
		TestCase("upgrade", "tiup_upgrade_03", func() {
			TiupUpdate("new_collations_enabled_on_first_bootstrap = true")
		})
	})

	Context("[postcheck]charset_gbk upgrade test", func() {
		TestCase("charset gbk update", "gbk006", func() {
			GBKAfterUpdateTest(false)
		})
	})

	Context("[postcheck]charset_gbk upgrade test, tiup destroy", func() {
		TestCase("destory", "tiup_destory_03", func() {
			TiupDestroy()
		})
	})

})

func GBKBeforeUpdateTest() {
	db := Try(cluster.GetDB("test")).(*sql.DB)
	defer db.Close()

	Try(db.Query("drop table if exists t1, t2;"))
	Try(db.Query("create table t1 (a varchar(256));"))
	_, err := db.Query("create table t2 (a varchar(256)) character set gbk")
	Expect(err.Error()).Should(ContainSubstring("Unknown character set: 'gbk'"))
	_, err = db.Query("set names gbk")
	Expect(err.Error()).Should(ContainSubstring("Unknown character set: 'gbk'"))
}

func GBKAfterUpdateTest(withNewCollation bool) {
	db := Try(cluster.GetDB("test")).(*sql.DB)
	defer db.Close()

	Try(db.Query("drop table if exists t1, t2;"))
	Try(db.Query("create table t1 (a varchar(256));"))
	_, err := db.Query("create table t2 (a varchar(256)) character set gbk")
	must(err)
	_, err = db.Query("set names gbk")
	must(err)
	var u int
	Try(db.QueryRow("SELECT count(*) FROM information_schema.COLLATIONS where CHARACTER_SET_NAME='gbk';").Scan(&u))
	if withNewCollation && u == 1 {
		Fail("Should support gbk related collations")
	}
	if !withNewCollation && u != 1 {
		Fail("Shouldn't support gbk related collations")
	}
}
