package main

import (
	"context"
	"encoding/json"
	"fmt"

	"github.com/spf13/cobra"
	pb "github.com/tidbcloud/config-center/proto/config_center"
	"google.golang.org/grpc"
	"k8s.io/utils/ptr"
)

// clusterConfigCmd represents the cluster_config command
var clusterConfigCmd = &cobra.Command{
	Use:   "cluster-config",
	Short: "manage cluster configuration files",
	Long:  `manage cluster configuration files`,
}

func init() {
	rootCmd.AddCommand(clusterConfigCmd)

	// clusterConfigCmd.AddCommand(newConfigAutoCreateCmd())
	clusterConfigCmd.AddCommand(newConfigGetCmd())
	clusterConfigCmd.AddCommand(newConfigListCmd())
	clusterConfigCmd.AddCommand(newConfigUpdateCmd())
	clusterConfigCmd.AddCommand(newConfigUpsertCmd())
	clusterConfigCmd.AddCommand(newConfigAutoUpdateCmd())
	clusterConfigCmd.AddCommand(newConfigDeleteCmd())
}

/*
func newConfigAutoCreateCmd() *cobra.Command {
	var clusterType, clusterID, version, cloudProvider, nodeInstance string
	var tenantID uint64
	cmd := &cobra.Command{
		Use:   "autocreate <filename>",
		Short: "autocreate cluster configuration file",
		Long:  `autocreate cluster configuration file`,
		RunE: func(cmd *cobra.Command, args []string) error {
			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.Dial(configCenterEndpoint, opts...)
			if err != nil {
				panic(err)
			}
			defer conn.Close()
			client := pb.NewConfigCenterServiceClient(conn)

			filename := args[0]
			t, err := client.AutoCreateClusterConfigurationFile(context.Background(), &pb.AutoCreateClusterConfigurationFileRequest{
				ClusterType:           pb.ClusterType(pb.ClusterType_value[clusterType]),
				ClusterId:             clusterID,
				ConfigurationFilename: filename,
				Format:                pb.Format_TOML,
				Version:               version,
				CloudProvider:         cloudProvider,
				NodeInstance:          nodeInstance,
				TenantId:              &tenantID,
			})
			if err == nil {
				txt, _ := json.MarshalIndent(t, "", "    ")
				fmt.Println(string(txt))
			}
			return err
		},
	}

	cmd.Flags().StringVarP(&clusterType, "cluster-type", "T", pb.ClusterType_DEDICATED_TIDB.String(), "cluster type")
	cmd.Flags().StringVarP(&clusterID, "cluster-id", "c", "", "cluster id")
	cmd.Flags().StringVarP(&version, "version", "v", "", "version")
	cmd.Flags().StringVarP(&cloudProvider, "cloud-provider", "p", "", "cloud provider")
	cmd.Flags().StringVarP(&nodeInstance, "node-instance", "n", "", "node instance")
	cmd.Flags().Uint64VarP(&tenantID, "tenant-id", "t", 0, "tenant id")

	return cmd
}
*/

func newConfigGetCmd() *cobra.Command {
	var clusterType, clusterID string
	cmd := &cobra.Command{
		Use:   "get <filename>",
		Short: "get cluster configuration file",
		Long:  `get cluster configuration file`,
		RunE: func(cmd *cobra.Command, args []string) error {
			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.Dial(configCenterEndpoint, opts...)
			if err != nil {
				panic(err)
			}
			defer conn.Close()
			client := pb.NewConfigCenterServiceClient(conn)

			filename := args[0]
			t, err := client.GetClusterConfigurationFile(context.Background(), &pb.GetClusterConfigurationFileRequest{
				ClusterType:           pb.ClusterType(pb.ClusterType_value[clusterType]),
				ClusterId:             clusterID,
				ConfigurationFilename: filename,
			})
			if err == nil {
				txt, _ := json.MarshalIndent(t, "", "    ")
				fmt.Println(string(txt))
			}
			return err
		},
	}

	cmd.Flags().StringVarP(&clusterType, "cluster-type", "T", pb.ClusterType_DEDICATED_TIDB.String(), "cluster type")
	cmd.Flags().StringVarP(&clusterID, "cluster-id", "c", "", "cluster id")

	return cmd
}

func newConfigListCmd() *cobra.Command {
	var clusterType, clusterID string
	cmd := &cobra.Command{
		Use:   "list",
		Short: "list cluster configuration files",
		Long:  `list cluster configuration files`,
		RunE: func(cmd *cobra.Command, args []string) error {
			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.Dial(configCenterEndpoint, opts...)
			if err != nil {
				panic(err)
			}
			defer conn.Close()
			client := pb.NewConfigCenterServiceClient(conn)

			t, err := client.ListClusterConfigurationFiles(context.Background(), &pb.ListClusterConfigurationFilesRequest{
				ClusterType: pb.ClusterType(pb.ClusterType_value[clusterType]),
				ClusterId:   clusterID,
			})
			if err == nil {
				txt, _ := json.MarshalIndent(t, "", "    ")
				fmt.Println(string(txt))
			}
			return err
		},
	}

	cmd.Flags().StringVarP(&clusterType, "cluster-type", "T", pb.ClusterType_DEDICATED_TIDB.String(), "cluster type")
	cmd.Flags().StringVarP(&clusterID, "cluster-id", "c", "", "cluster id")

	return cmd
}

func newConfigUpdateCmd() *cobra.Command {
	var clusterType, clusterID string
	cmd := &cobra.Command{
		Use:   "update <filename>",
		Short: "update cluster configuration file",
		Long:  `update cluster configuration file`,
		RunE: func(cmd *cobra.Command, args []string) error {
			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.Dial(configCenterEndpoint, opts...)
			if err != nil {
				panic(err)
			}
			defer conn.Close()
			client := pb.NewConfigCenterServiceClient(conn)

			filename := args[0]
			// value, _ := pb.NewValue("example_value")
			t, err := client.UpdateClusterConfigurationFile(context.Background(), &pb.UpdateClusterConfigurationFileRequest{
				ClusterType:           pb.ClusterType(pb.ClusterType_value[clusterType]),
				ClusterId:             clusterID,
				ConfigurationFilename: filename,
				CustomParams: map[string]*pb.ParamItem{/*
					"example_param": {
						Value:   value,
						Comment: "This is an example parameter",
					},
					"example_param2": {
						Value:   value,
						Comment: "This is an example parameter2",
					},*/
				},
				ClearCustomParams: false,
			})
			if err == nil {
				txt, _ := json.MarshalIndent(t, "", "    ")
				fmt.Println(string(txt))
			}
			return err
		},
	}

	cmd.Flags().StringVarP(&clusterType, "cluster-type", "T", pb.ClusterType_DEDICATED_TIDB.String(), "cluster type")
	cmd.Flags().StringVarP(&clusterID, "cluster-id", "c", "", "cluster id")

	return cmd
}

func newConfigAutoUpdateCmd() *cobra.Command {
	var clusterType, clusterID, version, cloudProvider, nodeInstance string
	cmd := &cobra.Command{
		Use:   "autoupdate <filename>",
		Short: "autoupdate cluster configuration file",
		Long:  `autoupdate cluster configuration file`,
		RunE: func(cmd *cobra.Command, args []string) error {
			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.Dial(configCenterEndpoint, opts...)
			if err != nil {
				panic(err)
			}
			defer conn.Close()
			client := pb.NewConfigCenterServiceClient(conn)

			filename := args[0]
			t, err := client.AutoUpdateClusterConfigurationFile(context.Background(), &pb.AutoUpdateClusterConfigurationFileRequest{
				ClusterType:           pb.ClusterType(pb.ClusterType_value[clusterType]),
				ClusterId:             clusterID,
				ConfigurationFilename: filename,
				Version:               version,
				CloudProvider:         cloudProvider,
				NodeInstance:          nodeInstance,
				Format:                ptr.To(pb.Format_TOML),
			})
			if err == nil {
				txt, _ := json.MarshalIndent(t, "", "    ")
				fmt.Println(string(txt))
			}
			return err
		},
	}

	cmd.Flags().StringVarP(&clusterType, "cluster-type", "T", pb.ClusterType_DEDICATED_TIDB.String(), "cluster type")
	cmd.Flags().StringVarP(&clusterID, "cluster-id", "c", "", "cluster id")
	cmd.Flags().StringVarP(&version, "version", "v", "", "version")
	cmd.Flags().StringVarP(&cloudProvider, "cloud-provider", "p", "", "cloud provider")
	cmd.Flags().StringVarP(&nodeInstance, "node-instance", "n", "", "node instance")

	return cmd
}

func newConfigUpsertCmd() *cobra.Command {
	var clusterType, clusterID string
	cmd := &cobra.Command{
		Use:   "upsert <filename>",
		Short: "upsert cluster configuration file",
		Long:  `upsert cluster configuration file`,
		RunE: func(cmd *cobra.Command, args []string) error {
			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.Dial(configCenterEndpoint, opts...)
			if err != nil {
				panic(err)
			}
			defer conn.Close()
			client := pb.NewConfigCenterServiceClient(conn)

			filename := args[0]
			value, err := pb.NewValue("example_value")
			if err != nil {
				return err
			}
			t, err := client.UpsertClusterCustomParams(context.Background(), &pb.UpsertClusterCustomParamsRequest{
				ClusterType:           pb.ClusterType(pb.ClusterType_value[clusterType]),
				ClusterId:             clusterID,
				ConfigurationFilename: filename,
				UpsertedParams: map[string]*pb.ParamItem{
					"example_param": {
						Value:   value,
						Comment: "This is an example parameter",
					},
					"example_param2": {
						Value:   value,
						Comment: "This is an example parameter2",
					},
				},
			})
			if err == nil {
				txt, _ := json.MarshalIndent(t, "", "    ")
				fmt.Println(string(txt))
			}
			return err
		},
	}

	cmd.Flags().StringVarP(&clusterType, "cluster-type", "T", pb.ClusterType_DEDICATED_TIDB.String(), "cluster type")
	cmd.Flags().StringVarP(&clusterID, "cluster-id", "c", "", "cluster id")

	return cmd
}

func newConfigDeleteCmd() *cobra.Command {
	var clusterType, clusterID string
	cmd := &cobra.Command{
		Use:   "delete",
		Short: "delete cluster configuration file",
		Long:  `delete cluster configuration file`,
		RunE: func(cmd *cobra.Command, args []string) error {
			var opts []grpc.DialOption
			opts = append(opts, grpc.WithInsecure())
			conn, err := grpc.Dial(configCenterEndpoint, opts...)
			if err != nil {
				panic(err)
			}
			defer conn.Close()
			client := pb.NewConfigCenterServiceClient(conn)

			filename := args[0]
			_, err = client.DeleteClusterConfigurationFile(context.Background(), &pb.DeleteClusterConfigurationFileRequest{
				ClusterType:           pb.ClusterType(pb.ClusterType_value[clusterType]),
				ClusterId:             clusterID,
				ConfigurationFilename: filename,
			})
			return err
		},
	}

	cmd.Flags().StringVarP(&clusterType, "cluster-type", "T", pb.ClusterType_DEDICATED_TIDB.String(), "cluster type")
	cmd.Flags().StringVarP(&clusterID, "cluster-id", "c", "", "cluster id")

	return cmd
}
