package cmd

import (
	"bufio"
	"fmt"
	"io"
	"os"

	log_reporter "github.com/pingcap-inc/alioth/reporter"
	"github.com/pingcap-inc/alioth/storage"
	"github.com/pingcap/log"
	"github.com/spf13/cobra"
	"go.uber.org/zap"
)

var (
	LogCoverage string
	OutReport   string
	Template    string
	GitVersion  string
	ReportKind  string
)

func NewAnalyzeCmd() *cobra.Command {
	cmdAnalyze := &cobra.Command{
		Use:   "analyze",
		Short: "Analyze the coverage result and output the analysis result report",
		//Args:  cobra.MinimumNArgs(1),
		RunE: func(cmd *cobra.Command, args []string) error {
			//Report("/Users/ianz/Work/go/src/github.com/pingcap-inc/alioth/tmp/", OutReport)
			if !Exists(LogCoverage) {
				return fmt.Errorf("log coverage does't not exist")
			}

			var (
				fd  *os.File
				err error
			)
			if len(Template) > 0 && !isFile(Template) {
				log.Fatal("template file not found")
			}

			if len(OutReport) > 0 {
				fd, err = os.OpenFile(OutReport, os.O_RDWR|os.O_CREATE, 0600)
				if err != nil {
					return err
				}
			} else {
				fd = os.Stdout
			}

			writer := bufio.NewWriter(fd)
			writer.Flush()

			Report(LogCoverage, writer)
			return writer.Flush()
		},
	}

	cmdAnalyze.Flags().StringVar(&LogCoverage, "log-coverage", "", "the log coverage directory (contain log coverage, reference code information)")
	cmdAnalyze.Flags().StringVar(&OutReport, "output", "", "output report of log coverage analysis results (default stdout)")
	cmdAnalyze.Flags().StringVar(&Template, "template", "", "output report template")
	cmdAnalyze.Flags().StringVar(&GitVersion, "version", "", "git hash/tag for log pattern/coverage(not for unknown)")
	cmdAnalyze.Flags().StringVar(&ReportKind, "kind", "text", "report kind, support `text` or `cov`. you can use --template to specify text template in `test`; it will generate coverage profile in `cov`")
	cmdAnalyze.MarkFlagRequired("log-coverage")
	return cmdAnalyze
}

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

	reporter, err := log_reporter.NewReporter(store, output, GitVersion)
	if err != nil {
		log.Fatal("create coverage failed", zap.Error(err))
	}

	err = reporter.Render(Template, ReportKind, defaultTemplate)
	if err != nil {
		log.Fatal("output coverage failed", zap.Error(err))

	}
}

func isFile(path string) bool {
	s, err := os.Stat(path)
	if err != nil {
		return false
	}
	return !s.IsDir()
}

var defaultTemplate = `
total error log {{.Total}}, covered error log {{.Cov}}
{{- println }}
{{- range $path, $cov := .Details -}}
{{if $cov.Coverage }}
path {{$path}} coverrd count {{$cov.Coverage.CovCount}}
log level {{$cov.Pattern.Level}} signatures {{- $cov.Pattern.Signature}}
coverage detail:
{{- range $addr, $count := $cov.Coverage.CovCountByLog}}
file {{$addr}} cover count {{$count}}
{{- end}}
{{- println }}
{{- else}} {{- end}}
{{- end}}
`
