/*
 * Copyright 2021 PingCAP, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package main

import (
	"crypto/tls"
	"fmt"
	"io/ioutil"
	"os"
	"path"
	"strings"
	"time"

	"github.com/pingcap/mimir/util"

	"github.com/spf13/cobra"
	"github.com/spf13/pflag"

	"github.com/pingcap/mimir/client"
	"github.com/pingcap/mimir/pkg/cert"
	"github.com/pingcap/mimir/pkg/constant"
)

var (
	// To test it in dev env, you should bind fowllowing domain to 127.0.0.1 via /etc/hosts
	endpoint = "https://mimir.pingcap.com"
)

func newClient() (*client.Client, error) {
	baseDir := path.Join(constant.HomeDir(), "tls")

	endpoint = getEndpoint(baseDir)

	var tlsCfg *tls.Config
	if strings.HasPrefix(endpoint, "https") {
		var err error
		tlsCfg, err = cert.LoadClientCert(baseDir)
		if err != nil {
			return nil, err
		}
		for _, cert := range tlsCfg.Certificates {
			period := time.Until(cert.Leaf.NotAfter)
			if period < time.Hour*24*7 {
				fmt.Printf(
					"- the cert of %s issued by %s will expire after %s, please update it as soon as possible!\n",
					cert.Leaf.Subject.CommonName, cert.Leaf.Issuer.CommonName, period,
				)
			}
		}
	}

	client := client.New(endpoint, tlsCfg)
	return client, nil
}

func main() {
	command().Execute() //nolint:errcheck
}

func getEndpoint(baseDir string) string {
	host := path.Join(baseDir, "host")
	if util.IsExist(host) {
		ep, err := ioutil.ReadFile(host)
		if err == nil && ep != nil && len(ep) > 0 {
			return strings.TrimSpace(string(ep))
		}

		fmt.Printf("read host from tls directory failed, err=%v \n", err)
	}

	if os.Getenv(constant.EnvNameEndpoint) != "" {
		return os.Getenv(constant.EnvNameEndpoint)
	}

	return endpoint
}

func command() *cobra.Command {
	cmd := &cobra.Command{
		Use:  `mim`,
		Long: `mim is a command-line client for mimir, the warehouse for PingCAP`,
		PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
			cmd.Flags().Visit(func(flag *pflag.Flag) {
				if flag.Name == "endpoint" {
					os.Setenv(constant.EnvNameEndpoint, "")
				}
			})
			return nil
		},
		RunE: func(cmd *cobra.Command, args []string) error {
			return cmd.Help()
		},
		SilenceUsage: true,
	}

	cmd.PersistentFlags().StringVarP(&endpoint, "endpoint", "", endpoint, "the mimir service endpoint")
	cmd.AddCommand(
		newPlayCmd(),
		newSubmitCmd(),
		newListCmd(),
		newStopCmd(),
		newResumeCmd(),
		newLogsCmd(),
		newRmCmd(),
		newLoginCmd(),
		newShowSqlCmd(),
		newCreateIngress(),
		newCreateSinkCmd(),
		newListSinkCmd(),
		newRmSinkCmd(),
		newSubmitV2Cmd(),
		newRmIngress(),
		newListIngressCmd(),
	)
	return cmd
}
