package main

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

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

// templateCmd represents the template command
var templateCmd = &cobra.Command{
	Use:   "template",
	Short: "manage temlates",
	Long:  `manage temlates`,
}

func init() {
	rootCmd.AddCommand(templateCmd)

	templateCmd.AddCommand(newTemplateSearchCmd())
	templateCmd.AddCommand(newTemplateGetCmd())
	templateCmd.AddCommand(newTemplateDeleteCmd())
	templateCmd.AddCommand(newTemplateUsageCmd())
	templateCmd.AddCommand(newTemplateCleanCmd())
	templateCmd.AddCommand(newTemplateListBindingCmd())
}

func newTemplateSearchCmd() *cobra.Command {
	var clusterType, version, cloudProvider, instance string
	cmd := &cobra.Command{
		Use:   "search <filename>",
		Short: "search templates",
		Long:  `search templates`,
		RunE: func(cmd *cobra.Command, args []string) error {
			filename := args[0]
			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.SearchDefaultConfigurationTemplate(context.Background(), &pb.SearchDefaultConfigurationTemplateRequest{
				ClusterType:       pb.ClusterType(pb.ClusterType_value[clusterType]),
				ConfigurationType: filename,
				Version:           version,
				CloudProvider:     cloudProvider,
				NodeInstance:      instance,
			})
			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(&version, "version", "v", "", "version")
	cmd.Flags().StringVarP(&cloudProvider, "cloud-provider", "p", "", "cloud provider")
	cmd.Flags().StringVarP(&instance, "node-instance", "n", "", "node instance")
	return cmd
}

func newTemplateGetCmd() *cobra.Command {
	var clusterType, filename string
	cmd := &cobra.Command{
		Use:   "get <id>",
		Short: "get template by id",
		Long:  `get template by id`,
		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()

			id, err := strconv.Atoi(args[0])
			if err != nil {
				return err
			}
			client := pb.NewConfigCenterServiceClient(conn)
			t, err := client.GetConfigurationTemplate(context.Background(), &pb.GetConfigurationTemplateRequest{
				ClusterType:       pb.ClusterType(pb.ClusterType_value[clusterType]),
				ConfigurationType: filename,
				TemplateId:        int64(id),
			})
			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(&filename, "filename", "f", "", "filename")

	return cmd
}

func newTemplateDeleteCmd() *cobra.Command {
	var clusterType string
	cmd := &cobra.Command{
		Use:   "delete <id>",
		Short: "delete template by id",
		Long:  `delete template by id`,
		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)

			id, err := strconv.Atoi(args[0])
			if err != nil {
				return err
			}
			_, err = client.DeleteConfigurationTemplate(context.Background(), &pb.DeleteConfigurationTemplateRequest{
				TemplateId: int64(id),
			})
			return err
		},
	}

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

	return cmd
}

func newTemplateUsageCmd() *cobra.Command {
	var clusterType, filename string
	cmd := &cobra.Command{
		Use:   "usage <id>",
		Short: "get template usage by id",
		Long:  `get template usage by id`,
		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()

			id, err := strconv.Atoi(args[0])
			if err != nil {
				return err
			}
			client := pb.NewConfigCenterServiceClient(conn)
			u, err := client.GetTemplateUsage(context.Background(), &pb.GetTemplateUsageRequest{
				ClusterType:       pb.ClusterType(pb.ClusterType_value[clusterType]),
				ConfigurationType: filename,
				TemplateId:        int64(id),
			})
			if err == nil {
				txt, _ := json.MarshalIndent(u, "", "    ")
				fmt.Println(string(txt))
			}
			return err
		},
	}

	cmd.Flags().StringVarP(&clusterType, "cluster-type", "T", pb.ClusterType_DEDICATED_TIDB.String(), "cluster type")
	cmd.Flags().StringVarP(&filename, "filename", "f", "", "filename")

	return cmd
}

func newTemplateCleanCmd() *cobra.Command {
	var clusterType, filename string
	cmd := &cobra.Command{
		Use:   "clean",
		Short: "clean unused template",
		Long:  `clean unused template`,
		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)
			for id := 1; id <= 1000; id++ {
				u, err := client.GetTemplateUsage(context.Background(), &pb.GetTemplateUsageRequest{
					ClusterType:       pb.ClusterType(pb.ClusterType_value[clusterType]),
					ConfigurationType: filename,
					TemplateId:        int64(id),
				})
				if err == nil {
					txt, _ := json.MarshalIndent(u, "", "    ")
					fmt.Println(string(txt))
				}
				if len(u.GetClusterIds()) == 0 && len(u.GetDefaultCases()) == 0 {
					fmt.Printf("template %d is unused\n", id)
					// delete api
				}
			}
			return err
		},
	}

	cmd.Flags().StringVarP(&clusterType, "cluster-type", "T", pb.ClusterType_DEDICATED_TIDB.String(), "cluster type")
	cmd.Flags().StringVarP(&filename, "filename", "f", "", "filename")

	return cmd
}

func newTemplateListBindingCmd() *cobra.Command {
	var clusterType, configType, version string
	var pageSize, pageNum int32
	cmd := &cobra.Command{
		Use:   "list-binding",
		Short: "list DefaultCase bindings",
		Long:  `list DefaultCase bindings`,
		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)
			resp, err := client.ListConfigurationTemplateDefaultCaseBindings(context.Background(), &pb.ListConfigurationTemplateDefaultCaseBindingsRequest{
				ClusterType:       pb.ClusterType(pb.ClusterType_value[clusterType]),
				ConfigurationType: configType,
				Version:           version,
				PageSize:          pageSize,
				PageNum:           pageNum,
			})
			if err != nil {
				return err
			}
			for _, b := range resp.GetTemplateDefaultCaseBindings() {
				fmt.Printf("%-10s %-10s %-7s %-20s %d\n", b.DefaultCase.ConfigurationType, "\""+b.DefaultCase.Version+"\"", "\""+b.DefaultCase.CloudProvider+"\"", "\""+b.DefaultCase.NodeInstance+"\"", b.TemplateId)
			}
			fmt.Println("----------")
			fmt.Printf("count: %d, total: %d\n", len(resp.TemplateDefaultCaseBindings), resp.GetTotal())
			return err
		},
	}

	cmd.Flags().StringVarP(&clusterType, "cluster-type", "T", pb.ClusterType_DEDICATED_TIDB.String(), "cluster type")
	cmd.Flags().StringVarP(&configType, "config-type", "", "", "config type")
	cmd.Flags().StringVarP(&version, "version", "v", "", "version")
	cmd.Flags().Int32VarP(&pageNum, "page-num", "", 1, "page number")
	cmd.Flags().Int32VarP(&pageSize, "page-size", "", 200, "page size")

	return cmd
}
