package cmd

import (
	"context"
	"fmt"
	"strings"

	"github.com/pingcap-inc/alioth/pkg/util"
	"github.com/pingcap-inc/alioth/pkg/worker"
	log_scanner "github.com/pingcap-inc/alioth/scanner"
	"github.com/pingcap-inc/alioth/storage"
	"github.com/pingcap/log"
	"github.com/spf13/cobra"
	"go.uber.org/zap"
)

var (
	LogPattern      string
	LogFile         string
	ScanConcurrency int
	ScanKind        string
)

func NewScanCmd() *cobra.Command {
	cmdScan := &cobra.Command{
		Use:   "scan",
		Short: "Scan program log files and calculate the log coverage result",
		//Args:  cobra.MinimumNArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			/*ScanLog("/Users/ianz/Work/go/src/github.com/pingcap-inc/alioth/tmp/", []string{
				"/Users/ianz/Work/go/src/github.com/pingcap/dm/log/dm-master-0.log",
				"/Users/ianz/Work/go/src/github.com/pingcap/dm/log/dm-master-1.log",
				"/Users/ianz/Work/go/src/github.com/pingcap/dm/log/dm-master-2.log",
				"/Users/ianz/Work/go/src/github.com/pingcap/dm/log/dm-worker-0.log",
				"/Users/ianz/Work/go/src/github.com/pingcap/dm/log/dm-worker-1.log",
				"/Users/ianz/Work/go/src/github.com/pingcap/dm/log/dm-worker-2.log",
				"/Users/ianz/Work/go/src/github.com/pingcap/dm/log/dm-worker-3.log",
			})*/

			if !Exists(LogPattern) {
				return fmt.Errorf("log pattern set doesn't exist")
			}

			files := strings.Split(LogFile, ",")
			if len(files) <= 0 {
				return fmt.Errorf("log files don't exist")
			}

			if ScanKind == "logfile" {
				ScanLog(LogPattern, files)
			} else if ScanKind == "covprofile" {
				ScanCoverage(LogPattern, files)
			} else {
				log.Fatal("please set right `kind` flag, e.g. logcov scan --kind=logfile/covprofile")
			}

			return nil
		},
	}

	cmdScan.Flags().StringVar(&LogPattern, "log-pattern", "", "the directory that stores the extracted log pattern information, `log scan` would also add log coverage into it")
	cmdScan.Flags().StringVar(&LogFile, "logs", "", " the program runtime log files, files are separated by commas")
	cmdScan.Flags().StringVar(&ScanKind, "kind", "logfile", "logcov scan support scan logfile  and covprofile which is coverage profile")
	cmdScan.Flags().IntVar(&ScanConcurrency, "concurrency", defaultConcurrency, "scan log pipeline concurrency")

	cmdScan.MarkFlagRequired("log-pattern")
	cmdScan.MarkFlagRequired("logs")
	return cmdScan
}

func ScanLog(storePath string, logs []string) {
	poolWorker := worker.NewPool(ExtractConcurrency, "scan")

	store, err := storage.NewStore(storePath)
	if err != nil {
		log.Fatal("open log pattern store failed", zap.Error(err))
	}

	rule, err := util.GetLogPatternRule(store)
	if err != nil {
		log.Fatal("get log pattern rule from store failed", zap.Error(err))
	}

	p, err := log_scanner.NewLogProcessor(store, logs)
	if err != nil {
		log.Fatal("new scanner pipeline failed", zap.Error(err))
	}

	err = p.Run(context.Background(), rule, poolWorker)
	if err != nil {
		log.Fatal("scanner run failed", zap.Error(err))
	}
}

func ScanCoverage(storePath string, logs []string) {
	store, err := storage.NewStore(storePath)
	if err != nil {
		log.Fatal("open log pattern store failed", zap.Error(err))
	}

	p, err := log_scanner.NewCPProcessor(store, logs[0])
	if err != nil {
		log.Fatal("new coverage profile scanner failed", zap.Error(err))
	}

	err = p.Run(context.Background())
	if err != nil {
		log.Fatal("scanner run failed", zap.Error(err))
	}
}
