package tiup_upgrade

import (
	"net/url"
	"time"

	"github.com/coreos/go-semver/semver"
	_ "github.com/go-sql-driver/mysql"
	. "github.com/onsi/ginkgo"
	"github.com/pingcap/test-infra/sdk/core"
	"github.com/pingcap/test-infra/sdk/resource"
	_ "github.com/pingcap/test-infra/sdk/resource/impl/k8s" // register k8s impl

	_ "github.com/pingcap/endless/pkg/client/tidb"
	. "github.com/pingcap/endless/pkg/util"
	. "github.com/pingcap/endless/pkg/workloadnode/tiup"
)

var tiupScaleoutTikv = `
tikv_servers:
  - host: tikv-peer
    port: 20560
    status_port: 20580
`
var tiupScaleoutTikvSec = `
tikv_servers:
  - host: tikv-peer
    port: 20560
    status_port: 20580
    config: 
      server.labels: {zone: "z1", host: "h5"}
      security.encryption.data-encryption-method: aes256-ctr
      security.encryption.master-key.path: /tiup/deploy/master_key
      security.encryption.master-key.type: file
`
var tiupScaleoutPD = `
pd_servers:
  - host: pd-peer
    client_port: 13379
    peer_port: 13380
`
var tiupScaleoutTidb = `
tidb_servers:
  - host: tidb-peer
    port: 5000
    status_port: 21080
`

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

var (
	ctx            core.TestContext
	workloadNode   resource.WorkloadNode
	cluster        *TiUPCluster
	cluster2       *TiUPCluster
	dbURL          *url.URL
	tidbIp         string
	tidbPort       string
	installVersion string
	targetVersion  string
	mysqlDsn       string
	mysqlDB        string
	cluster2Dsn    string
	preGrafana     string
	expFlag        string
	mirror         string
	tar_version    *semver.Version
)

var _ = Describe("tiup cluster deploy", func() {
	ctx = suiteTestCtx
	workloadNode = ctx.Resource("tiup").(resource.WorkloadNode)
	targetVersion = ctx.Param("target_version")
	installVersion = ctx.Param("init_version")
	cluster2Dsn = "cluster2-peer:4000"
	mysqlDsn = "mysql-peer:3306"
	expFlag = ctx.Param("expression_index")
	mirror = ctx.Param("tiup_mirror")
	src_version := semver.New(installVersion[1:])
	if targetVersion == "nightly" {
		tar_version = semver.New("6.3.0")
	} else {
		tar_version = semver.New(targetVersion[1:])
	}

	Context("[full][simple]precheck, cluster install", func() {
		if mirror == "staging" {
			TestCase("set tiup stag mirror", "install001a", func() {
				SET_TIUP_STAG_MIRROR(workloadNode)
			})
		} else {
			TestCase("set tiup product mirror", "install001b", func() {
				SET_TIUP_PRODUCT_MIRROR(workloadNode)
			})
		}
		TestCase("install cluster2", "install002", func() {
			TIUP_INSTALL_Cluster2(workloadNode)
		})
		TestCase("install cluster1", "install003", func() {
			TIUP_INSTALL_Cluster1(workloadNode)
		})
		if !src_version.LessThan(*semver.New("4.0.9")) {
			TestCase("install br", "install004", func() {
				TIUP_INSTALL_BR(workloadNode)
			})
		}

	})
	Context("[simple][full]precheck, get component configs", func() {
		TestCase("get tidb config", "cfg001", func() {
			GET_TIDB_CFG(cluster, workloadNode, "precheck")
		})
		TestCase("get pd config", "cfg002", func() {
			GET_PD_CFG(cluster, workloadNode, installVersion, "precheck")
		})
		TestCase("get sysvar config", "cfg003", func() {
			GET_SYSVAR_CFG(workloadNode, cluster, "precheck")
		})
		TestCase("get tikv config", "cfg004", func() {
			GET_TIKV_CFG(workloadNode, cluster, "precheck")
		})
		TestCase("get tiflash config", "cfg005", func() {
			GET_TIFLASH_CFG(cluster, workloadNode, "precheck")
		})

	})

	Context("[full]precheck, cdc test", func() {
		if !src_version.LessThan(*semver.New("4.0.16")) {
			TestCase("cdc", "set task", func() {
				SET_CDC_TASK(cluster)
			})
			TestCase("cdc", "sync data precheck", func() {
				SYNC_CDC_DATA(cluster)
			})
			TestCase("cdc", "check data precheck", func() {
				CHECK_CDC_DATA(cluster2, 2)
			})

		}
	})

	Context("[simple][full]precheck, init database", func() {
		TestCase("init", "init mysql", func() {
			INIT_MYSQL()
		})
		TestCase("init", "init tidb", func() {
			INIT_Cluster1()
		})

	})

	Context("[simple][full]precheck, workload test", func() {
		TestCase("run bank workload", "wk001", func() {
			WKLD_BANK_RUN(cluster, ctx, "800")
		})
		TestCase("run tptest workload", "wk002", func() {
			WKLD_TPTEST(cluster, ctx, "precheck")
		})
		TestCase("run tpch workload", "wk003", func() {
			WKLD_TPCH(cluster, ctx, "precheck")
		})
		TestCase("run randgen workload", "wk004", func() {
			WKLD_RANDGEN(cluster, ctx, "precheck")
		})
	})

	// Context("[precheck]upgrade_test, br backup", func() {
	// 	TestCase("br backup", "br_001", func() {
	// 		BR_BACKUP(workloadNode, "test")
	// 	})
	// })

	Context("[simple][full]precheck, dashboard and grafana test", func() {
		if !src_version.LessThan(*semver.New("4.0.9")) {
			TestCase("get grafana version", "ui005", func() {
				preGrafana = GET_Grafana_Version(workloadNode)
			})
			TestCase("run grafana and dashboard", "ui001", func() {
				DASHBOARD_GRAFANA(ctx, workloadNode, preGrafana, "precheck")
			})
			TestCase("run prometheus api", "ui002", func() {
				API_Prometheus(ctx, workloadNode, cluster)
			})
		}
	})

	Context("[simple][full]precheck, privileges regression test", func() {
		TestCase("grant create priv to users", "priv001", func() {
			PRIV_GRANT_001(cluster)
		})

		if !src_version.LessThan(*semver.New("5.3.0")) {
			TestCase("grant global-only privs， bug in 5.2 #26703", "priv002", func() {
				PRIV_GRANT_002(cluster)
			})
		}
		if !src_version.LessThan(*semver.New("5.1.0")) {
			TestCase("grant dynamic sysvar admin and process priv to users， only for 5.2 version", "priv003", func() {
				PRIV_GRANT_003(cluster)
			})
		}

		TestCase("show priv for users", "priv004", func() {
			PRIV_GRANT_004(cluster)
		})
		if !src_version.LessThan(*semver.New("5.3.0")) {
			TestCase("grant global-only privs， bug in 5.2 #26703", "priv005", func() {
				PRIV_GRANT_005(cluster)
			})
		}
		if !src_version.LessThan(*semver.New("5.3.0")) {
			TestCase("#27213, show priv for users", "priv006", func() {
				PRIV_GRANT_006(cluster)
			})
		}
	})

	Context("[simple][full]precheck, sql binding regression test", func() {
		if !src_version.LessThan(*semver.New("4.0.9")) {
			TestCase("set bindings in  current db", "binding001", func() {
				SQL_BINDING_001(cluster)
			})
			TestCase("set bindings for other db", "binding002", func() {
				SQL_BINDING_003(cluster)
			})
			time.Sleep(60 * time.Second)
			TestCase("display binding result for binding001", "binding003", func() {
				SQL_BINDING_002(cluster)
			})
			TestCase("display binding result for binding003", "binding004", func() {
				SQL_BINDING_004(cluster)
			})
		}

	})

	Context("[simple][full]precheck, tiflash regression test", func() {
		TestCase("set tiflash replica", "Upgrade_tiflash_001_1", func() {
			TIFLASH_001(cluster)
		})
		time.Sleep(60 * time.Second)
		if src_version.LessThan(*semver.New("6.2.0")) {
			TestCase("query from tiflash", "Upgrade_tiflash_001_2", func() {
				TIFLASH_002(cluster)
			})
		} else {
			TestCase("query from tiflash", "Upgrade_tiflash_001_3", func() {
				TIFLASH_003(cluster)
			})
		}

	})

	Context("[simple][full]precheck, expression index regression test", func() {
		TestCase("create expression index", "Expression_001", func() {
			EXPINDEX_001(cluster)
		})
	})

	Context("[simple][full]tiup upgrade", func() {
		TestCase("upgrade", "tiup_upgrade", func() {
			TIUP_UPGRADE(cluster)
		})
	})

	Context("[simple][full]postcheck, privileges regression test", func() {
		TestCase("get tidb config", "cfg101", func() {
			GET_TIDB_CFG(cluster, workloadNode, "postcheck")
		})
		TestCase("get pd config", "cfg102", func() {
			GET_PD_CFG(cluster, workloadNode, installVersion, "postcheck")
		})
		TestCase("get sysvar config", "cfg103", func() {
			GET_SYSVAR_CFG(workloadNode, cluster, "postcheck")
		})
		TestCase("get tikv config", "cfg104", func() {
			GET_TIKV_CFG(workloadNode, cluster, "postcheck")
		})
		TestCase("get tiflash config", "cfg105", func() {
			GET_TIFLASH_CFG(cluster, workloadNode, "postcheck")
		})
	})

	Context("[simple][full]postcheck, workload test", func() {
		TestCase("run bank workload", "wk101", func() {
			WKLD_BANK_CHECK(ctx)
		})
		TestCase("run tptest workload", "wk102", func() {
			WKLD_TPTEST(cluster, ctx, "postcheck")
		})
		TestCase("run tpch workload", "wk103", func() {
			WKLD_TPCH(cluster, ctx, "postcheck")
		})
		TestCase("run randgen workload", "wk104", func() {
			WKLD_RANDGEN(cluster, ctx, "postcheck")
		})
	})

	Context("[simple][full]postcheck, dashboard and grafana test", func() {
		TestCase("run dashboard and grafana", "ui003", func() {
			DASHBOARD_GRAFANA(ctx, workloadNode, preGrafana, "postcheck")
		})
		TestCase("run prometheus api", "ui004", func() {
			API_Prometheus(ctx, workloadNode, cluster)
		})
	})

	Context("[simple][full]postcheck, privileges regression test", func() {
		TestCase("show priv for users", "priv104", func() {
			PRIV_GRANT_004(cluster)
		})
		if !src_version.LessThan(*semver.New("5.3.0")) {
			TestCase("grant global-only privs， bug in 5.2 #26703", "priv105", func() {
				PRIV_GRANT_005(cluster)
			})
		}
		if !src_version.LessThan(*semver.New("5.3.0")) {
			TestCase("#27213, show priv for users", "priv106", func() {
				PRIV_GRANT_006(cluster)
			})
		}
	})

	Context("[simple][full]postcheck, sql binding regression test", func() {
		TestCase("display binding result for binding001", "binding103", func() {
			SQL_BINDING_002(cluster)
		})
		TestCase("display binding result for binding002", "binding104", func() {
			SQL_BINDING_004(cluster)
		})

	})

	Context("[simple][full]postcheck, tiflash regression test", func() {
		if tar_version.LessThan(*semver.New("6.2.0")) {
			TestCase("query from tiflash", "Upgrade_tiflash_002_1", func() {
				TIFLASH_002(cluster)
			})
		} else {
			TestCase("query from tiflash", "Upgrade_tiflash_002_2", func() {
				TIFLASH_003(cluster)
			})
		}
	})

	Context("[simple][full]postcheck, expression index regression test", func() {
		TestCase("create expression index", "Expression_002", func() {
			EXPINDEX_002(cluster)
		})
	})

	Context("[cdctest][simple][full]postcheck, tiup scale out tikv", func() {
		TestCase("scale out", "tiup_scale_out_tikv", func() {
			TIUP_SCALE_OUT(cluster, tiupScaleoutTikv)
		})

		TestCase("scale out", "tiup_scale_out_pd", func() {
			TIUP_SCALE_OUT(cluster, tiupScaleoutPD)
		})
		TestCase("scale out", "tiup_scale_out_tidb", func() {
			TIUP_SCALE_OUT(cluster, tiupScaleoutTidb)
		})
	})

	Context("[cdctest][simple][full]postcheck, tiup scale out", func() {
		node := ""
		TestCase("scale in", "tiup_scale_in_tikv", func() {
			node = "tikv-peer:20160"
			TIUP_SCALE_IN(cluster, node)
		})
		TestCase("scale in", "tiup_scale_in_pd", func() {
			node = "pd2-peer:22379"
			TIUP_SCALE_IN(cluster, node)
		})
		TestCase("scale in", "tiup_scale_in_tidb", func() {
			node = "tidb-peer:4000"
			TIUP_SCALE_IN(cluster, node)
		})
	})

	Context("[cdctest][full][amdonly]postcheck,stmt_regression test", func() {
		// if !tar_version.LessThan(*semver.New("5.4.0")) {
		// 	TestCase("stmt", "ddl", func() {
		// 		STMT_Test(cluster, "ddl/all.jsonnet")
		// 	})
		// }
		if !tar_version.LessThan(*semver.New("5.0.0")) {
			TestCase("stmt", "sqlmode", func() {
				SET_SYSVAR(cluster2, "set global sql_mode='';")
			})
			TestCase("stmt", "clusteredindex", func() {
				SET_SYSVAR(cluster, "set global tidb_enable_clustered_index ='on';")
			})
			time.Sleep(10 * time.Second)
			TestCase("stmt", "prepare-plan-cache", func() {
				STMT_Test(cluster, "prepare-plan-cache/all.jsonnet")
			})
			// TestCase("stmt", "regression", func() {
			// 	STMT_Test(cluster, "regression/all.jsonnet")
			// })
			TestCase("stmt", "rc", func() {
				STMT_Test(cluster, "rc/all.jsonnet")
			})
			// TestCase("stmt", "clustered_index", func() {
			// 	STMT_Test(cluster, "clustered_index/all.jsonnet")
			// })

		}

	})

	Context("[full]postcheck, sync diff test", func() {
		TestCase("syncdiff", "check binlog", func() {
			SYNC_DIFF_CHECK_MySQL("bank")
		})
		if !src_version.LessThan(*semver.New("4.0.16")) {
			TestCase("syncdiff", "check cdc", func() {
				SYNC_DIFF_CHECK_TiDB("cdctest")
			})
		}
	})

	Context("[cdctest][full]postcheck, cdc test", func() {
		if !src_version.LessThan(*semver.New("4.0.16")) {

			TestCase("cdc", "sync data postcheck", func() {
				SYNC_CDC_DATA2(cluster)
			})
			TestCase("cdc", "check data postcheck", func() {
				CHECK_CDC_DATA(cluster2, 4)
			})
			TestCase("cdc", "check status", func() {
				CHECK_TASK_STATUS(cluster)
			})

		}
	})

	if !tar_version.LessThan(*semver.New("5.4.0")) {
		Context("[full][amdonly]postcheck, enable auto-tls", func() {
			TestCase("edit config", "client001", func() {
				TIUP_EDIT_CFG(cluster, "[security]\nauto-tls = true")
			})
		})

		Context("[full][amdonly]postcheck, mysql client test", func() {
			TestCase("client", "client002", func() {
				INSTALL_MYSQL_CLIENT(ctx)
			})
		})
	}
	if !tar_version.LessThan(*semver.New("6.2.0")) {
		Context("[full]postcheck, multi-schema-change-002", func() {
			TestCase("multi-schema-change", "fun001", func() {
				TC_MultiSchemaChange_systemvar_002(cluster)
			})
		})
		Context("[full]postcheck, multi-schema-change-006", func() {
			TestCase("multi-schema-change", "rollback006", func() {
				TC_MultiSchemaChange_rollback_006(cluster)
			})
		})
	}

	Context("[cdctest][simple][full]diag collect and upload", func() {
		TestCase("diag", "upload cluster2", func() {
			Clinic_Upload_Config(cluster2, "cluster2")
		})
		TestCase("diag", "upload cluster1", func() {
			Clinic_Upload_Config(cluster, "cluster1")
		})
	})

})
