package jumpservercli

import (
	"context"
	"fmt"
	"os"
	"strings"
	"testing"

	"github.com/tidbcloud/devops/pkg/infra/utils/test"
	"tailscale.com/client/tailscale/v2"

	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
)

func TestJiraClient(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "JumpServerClient Suite")
}

var _ = Describe("[JumpServerClient]", func() {

	var cli JumpServerCli

	BeforeEach(func() {
		var err error

		config := Config{
			Scheme:        "https",
			Addr:          os.Getenv("JUMPSERVER_HOST"),
			AccessKey:     os.Getenv("JUMPSERVER_ACCESS_KEY"),
			SecretKey:     os.Getenv("JUMPSERVER_SECRET_KEY"),
			BaseAssetName: "jump-cluster",
		}
		cli, err = NewJumpServerCli(config)
		Expect(err).To(BeNil())
	})

	Describe("[Client]", func() {
		PIt("[UpdateAccountToken]", func() {
			ctx := context.TODO()
			token := "123"
			email := "sihao.yu@pingcap.com"
			err := cli.UpdateAccountToken(ctx, email, token)
			Expect(err).To(BeNil())

		})

	})

	PIt("Byoc", func() {
		ts := &tailscale.Client{
			Tailnet: "pingcap.com",
			HTTP: tailscale.OAuthConfig{
				ClientID:     os.Getenv("TAILSCALE_CLIENT_ID"),
				ClientSecret: os.Getenv("TAILSCALE_CLIENT_SECRET"),
				Scopes:       []string{"all:write"},
			}.HTTPClient(),
		}

		req := tailscale.CreateKeyRequest{}
		req.Capabilities.Devices.Create.Ephemeral = true
		req.Capabilities.Devices.Create.Tags = []string{"tag:jump-pod-dev"}
		key, err := ts.Keys().CreateAuthKey(context.TODO(), req)
		Expect(err).To(BeNil())

		fmt.Println(test.MarshalIndentOrDie(key))
	})

	Describe("[Raw]", func() {
		Context("[Account]", func() {
			PIt("[CreateAccount]", func() {
				ctx := context.TODO()

				query := map[string]string{
					"name": "base-us-west-2",
				}
				assetsResp, err := cli.(*client).raw.ListAssets(ctx, query, Page{})
				Expect(err).To(BeNil())
				Expect(len(assetsResp.Results)).To(Equal(1))

				param := CreateAccountReq{
					Name:     "sihao.yu@pingcap.com-2",
					Username: "sihao.yu@pingcap.com-2",
					Asset: &Asset{
						ID: assetsResp.Results[0].ID,
					},
					SecretType: AccountSecretType{
						Value: "token",
					},
				}
				account, err := cli.(*client).raw.CreateAccount(ctx, param)
				Expect(err).To(BeNil())
				fmt.Println(test.MarshalIndentOrDie(account))
			})

			PIt("[ListAccounts]", func() {
				ctx := context.TODO()
				query := map[string]string{
					"username": "huangjiajun@pingcap.com",
				}
				account, err := cli.(*client).raw.ListAccounts(ctx, query, Page{})
				Expect(err).To(BeNil())
				fmt.Println(test.MarshalIndentOrDie(account))
			})
		})

		Context("[User]", func() {
			PIt("[CreateUser]", func() {
				ctx := context.TODO()

				query := map[string]string{
					"name": "Default",
				}
				groupsResp, err := cli.(*client).raw.ListUserGroups(ctx, query, Page{})
				Expect(err).To(BeNil())
				Expect(len(groupsResp.Results)).To(Equal(1))

				param := CreateUserReq{
					Name:     "sihao.yu@pingcap.com",
					Username: "sihao.yu@pingcap.com",
					Email:    "sihao.yu@pingcap.com",
					Groups: []UserGroup{
						{
							ID: groupsResp.Results[0].ID,
						},
					},
					PasswordStrategy: UserPasswordStrategy{
						Value: "email",
					},
					MFALevel: UserMFALevel{
						Value: 2,
					},
				}
				user, err := cli.(*client).raw.CreateUser(ctx, param)
				Expect(err).To(BeNil())
				fmt.Println(test.MarshalIndentOrDie(user))
			})

			PIt("[GetUser]", func() {
				for i := 0; i < 10; i++ {
					ctx := context.TODO()
					user, err := cli.GetUser(ctx, "test")
					Expect(err).To(BeNil())
					if user == nil {
						fmt.Println("i", ": ", nil)
						continue
					}
					fmt.Println("i", ": ", user.ID)
				}
			})
		})

		Context("[UserGroup]", func() {
			PIt("[ListUserGroup]", func() {
				ctx := context.TODO()
				query := map[string]string{
					"name": "Default",
				}
				groups, err := cli.(*client).raw.ListUserGroups(ctx, query, Page{})
				Expect(err).To(BeNil())
				fmt.Println(test.MarshalIndentOrDie(groups))
			})
		})

		Context("[Asset]", func() {
			PIt("[ListAssets]", func() {
				ctx := context.TODO()
				query := map[string]string{
					"name": "base-us-west-2",
				}
				assets, err := cli.(*client).raw.ListAssets(ctx, query, Page{})
				Expect(err).To(BeNil())
				fmt.Println(test.MarshalIndentOrDie(assets))
			})
		})

		Context("[Misc]", func() {
			PIt("[CreateConnectionToken]", func() {
				ctx := context.TODO()

				email := "sihao.yu@pingcap.com"

				usersResp, err := cli.(*client).raw.ListUsers(ctx, map[string]string{
					"username": "sihao.yu@pingcap.com",
				}, Page{})
				Expect(err).To(BeNil())
				Expect(len(usersResp.Results)).To(Equal(1))

				assetsResp, err := cli.(*client).raw.ListAssets(ctx, map[string]string{
					"name": "base-us-west-2",
				}, Page{})
				Expect(err).To(BeNil())
				Expect(len(assetsResp.Results)).To(Equal(1))

				req := CreateConnectionTokenReq{
					UserID:        usersResp.Results[0].ID,
					AssetID:       assetsResp.Results[0].ID,
					Account:       email,
					Protocol:      AssetTypeKubernetes,
					InputUserName: email,
					InputSecret:   "",
					ConnectMethod: ConnectMethodWebCli,
				}
				token, err := cli.(*client).raw.CreateConnectionToken(ctx, req)
				Expect(err).To(BeNil())
				fmt.Println(test.MarshalIndentOrDie(token))
			})

			PIt("Update User Email to pingcap cn", func() {
				ctx := context.TODO()

				resp, err := cli.(*client).raw.ListUsers(ctx, map[string]string{}, Page{})
				Expect(err).To(BeNil())

				for _, userB := range resp.Results {
					fmt.Println("before update ==")
					fmt.Println(test.MarshalIndentOrDie(userB))

					if strings.Contains(userB.Email, "@pingcap.cn") {
						continue
					}

					req := map[string]any{
						"email": strings.Replace(userB.Email, "@pingcap.com", "@pingcap.cn", 1),
					}
					userA, err := cli.(*client).raw.PatchUser(ctx, userB.ID, req)
					Expect(err).To(BeNil())

					fmt.Println("after update ==")
					fmt.Println(test.MarshalIndentOrDie(userA))
				}
			})

			PIt("DevOpsMigrate: Update User Account to New Asset", func() {
				ctx := context.TODO()

				query := map[string]string{
					"name": "jump-cluster",
				}
				assets, err := cli.(*client).raw.ListAssets(ctx, query, Page{})
				Expect(err).To(BeNil())
				fmt.Println(test.MarshalIndentOrDie(assets))

				resp, err := cli.(*client).raw.ListUsers(ctx, map[string]string{}, Page{
					Limit: 150,
				})
				Expect(err).To(BeNil())
				fmt.Println(test.MarshalIndentOrDie(resp))

				for _, account := range resp.Results {
					// // delete current account
					// err := cli.(*client).raw.DeleteAccount(ctx, account.ID)
					// Expect(err).To(BeNil())

					// create new account with new asset
					acctToCreate := CreateAccountReq{
						Name:     account.Name,
						Username: account.Username,
						SecretType: AccountSecretType{
							Value: AccountSecretTypeToken,
						},
						Asset: &Asset{
							ID: assets.Results[0].ID,
						},
					}
					resp, err := cli.(*client).raw.CreateAccount(ctx, acctToCreate)
					Expect(err).To(BeNil())
					fmt.Println("after create ==")
					fmt.Println(test.MarshalIndentOrDie(resp))
				}

				// for _, userB := range resp.Results {
				// 	fmt.Println("before update ==")
				// 	fmt.Println(test.MarshalIndentOrDie(userB))

				// 	if strings.Contains(userB.Email, "@pingcap.cn") {
				// 		continue
				// 	}

				// 	req := map[string]any{
				// 		"email": strings.Replace(userB.Email, "@pingcap.com", "@pingcap.cn", 1),
				// 	}
				// 	userA, err := cli.(*client).raw.PatchUser(ctx, userB.ID, req)
				// 	Expect(err).To(BeNil())

				// 	fmt.Println("after update ==")
				// 	fmt.Println(test.MarshalIndentOrDie(userA))
				// }
			})
		})
	})

})
