package suite

import (
	"strings"

	"github.com/gookit/color"
	"k8s.io/apimachinery/pkg/labels"

	"github.com/tidbcloud/eks-provider/tests/e2e/label"
)

type Reporter interface {
	Summary() *Summary
}

type Summary struct {
	Total   int
	Succeed int
	Failed  int
	Skipped int

	Reports []EnvReport
}

type EnvReport struct {
	Desc   string
	Labels labels.Labels
	Env    string

	ParentEnvs []string
	Cases      []CaseReport

	State label.State

	FailedError error
}

type CaseReport struct {
	Desc   string
	Labels labels.Labels

	State label.State
}

func NewReporter(envMap EnvMap) Reporter {
	return &reporter{
		envMap: envMap,
	}
}

type reporter struct {
	envMap EnvMap
}

func (r *reporter) Summary() *Summary {
	s := Summary{}
	for _, name := range r.envMap.EnvNames() {
		e := r.envMap.GetEnv(name)
		er := EnvReport{
			Desc:        e.GetDesc(),
			Labels:      e.GetLabels(),
			Env:         name,
			ParentEnvs:  r.envMap.GetEnvParent(name, true),
			State:       e.GetState(),
			FailedError: e.Error(),
		}
		cases := r.envMap.GetCases(name)
		for _, c := range cases {
			er.Cases = append(er.Cases, CaseReport{
				Desc:   c.GetDesc(),
				Labels: c.GetLabels(),
				State:  c.GetState(),
			})
			s.Total++
			switch c.GetState() {
			case label.StateFailed:
				s.Failed++
			case label.StateSkipped:
				s.Skipped++
			case label.StateSucceed:
				s.Succeed++
			default:
			}

		}
		s.Reports = append(s.Reports, er)
	}

	return &s
}

func (s *Summary) String() string {
	b := strings.Builder{}

	white := color.HEXStyle("#f8f8f0")
	white.SetOpts(color.Opts{color.OpBold})
	red := color.HEXStyle("#e95678")
	red.SetOpts(color.Opts{color.OpBold})
	green := color.HEXStyle("#a6e22e")
	green.SetOpts(color.Opts{color.OpBold})
	orange := color.HEXStyle("#fd971f")
	orange.SetOpts(color.Opts{color.OpBold})

	b.WriteByte('\n')
	b.WriteString(white.Sprintf("Total: %v\t", s.Total))
	b.WriteString(green.Sprintf("Succeed: %v\t", s.Succeed))
	b.WriteString(red.Sprintf("Failed: %v\t", s.Failed))
	b.WriteString(orange.Sprintf("Skipped: %v\n", s.Skipped))
	b.WriteByte('\n')

	for _, r := range s.Reports {
		switch r.State {
		case label.StateFailed:
			b.WriteString(red.Sprintf("[ENV] %s is failed to setup: %v\n", r.Env, r.FailedError))
		case label.StateSkipped:
			b.WriteString(orange.Sprintf("[ENV] %s is skipped\n", r.Env))
		}
	}

	return b.String()
}
