package store

import (
	"context"
	_ "embed"
	"fmt"

	"github.com/pingcap/test-infra/common/model"
	"github.com/pingcap/test-infra/services/tcms/service"
	"github.com/pingcap/test-infra/services/tcms/service/common"
	"github.com/pingcap/test-infra/services/tcms/utils"
)

type reporter struct {
	p service.PlanExecutionService
	c service.CaseExecutionService
}

func (r reporter) GetPlanReport(ctx context.Context, id model.ID) (*model.TestReport, error) {
	planExec, err := r.p.Get(utils.GetUtilContext(ctx), id)
	if err != nil || planExec == nil {
		return nil, err
	}
	const MaxCaseListCnt = 100000
	cases, total, err := r.c.List(utils.GetUtilContext(ctx), common.CaseExecQueryOpts{RootPlanExecID: &planExec.ID, Count: MaxCaseListCnt})
	if err != nil {
		return nil, err
	}
	if total > MaxCaseListCnt {
		return nil, fmt.Errorf("two many cases in plan")
	}
	rt := model.TestReport{}
	rt.Suits = append(rt.Suits, toPlanReport(*planExec, cases))
	return &rt, nil
}

func toPlanReport(plan model.TestPlanExecution, cases []*model.TestCaseExecution) (suit model.SuitReport) {
	suit.Name = plan.Name
	for _, c := range cases {
		suit.Cases = append(suit.Cases, toCaseReport(*c))
	}
	failure := 0
	if plan.CompletedAt != nil && plan.StartedAt != nil {
		suit.Time = plan.CompletedAt.Time().Sub(plan.StartedAt.Time())
	}
	for _, caseReport := range suit.Cases {
		if caseReport.Failure != nil {
			failure++
		}
	}
	suit.Failure = failure
	return
}

func toCaseReport(execution model.TestCaseExecution) (report model.CaseReport) {
	report.Name = execution.Name
	if execution.CompletedAt != nil && execution.StartedAt != nil {
		report.Time = execution.CompletedAt.Time().Sub(execution.StartedAt.Time())
	}
	if execution.Status.NeedTriage() {
		f := model.CaseDetail{}
		f.Message = execution.Output
		report.Failure = &f
	}

	switch execution.Status {
	case model.ExecutionStatusCancelled:
		fallthrough
	case model.ExecutionStatusOmitted:
		fallthrough
	case model.ExecutionStatusPending:
		// to workaround pending cases bug
		fallthrough
	case model.ExecutionStatusSkipped:
		f := model.CaseDetail{}
		f.Message = execution.Output
		report.Skipped = &f
	}
	return
}

func NewReporter(p service.PlanExecutionService, c service.CaseExecutionService) service.ReportService {
	return reporter{p: p, c: c}
}
