package model

import (
	"database/sql/driver"
	"errors"
	"fmt"
	"time"
)

type Triage struct {
	ID ID `json:"id"`

	PlanExecutionID ID   `json:"planExecutionID"`
	PlanID          ID   `json:"planID"`
	TriagingUsers   []ID `json:"triagingUsers"`

	ToTriageCaseExecIDs []ID `json:"toTriageCaseExecIDs"`
	TriagedCaseExecIDs  []ID `json:"triagedCaseExecIDs"`

	TriagePhase `json:"triagePhase"`

	CreatedAt time.Time  `json:"createdAt,omitempty"`
	UpdatedAt time.Time  `json:"updatedAt,omitempty"`
	StartedAt *time.Time `json:"startedAt,omitempty"`
	TriagedAt *time.Time `json:"triagedAt,omitempty"`

	Reasons  []CaseExecFailReason `json:"reasons,omitempty"`
	Solution ExecFailSolution     `json:"solution,omitempty"`
	Note     string               `json:"note,omitempty"`
}

type TriagePhase string

const (
	TriagePhaseToTriage TriagePhase = "TO_TRIAGE"
	TriagePhaseTriaging TriagePhase = "TRIAGING"
	TriagePhaseTriaged  TriagePhase = "TRIAGED"
)

func (t TriagePhase) Values() []string {
	return []string{
		string(TriagePhaseToTriage),
		string(TriagePhaseTriaging),
		string(TriagePhaseTriaged),
	}
}

func (t TriagePhase) Next() TriagePhase {
	switch t {
	case TriagePhaseToTriage:
		return TriagePhaseTriaging
	case TriagePhaseTriaging:
		return TriagePhaseTriaged
	case TriagePhaseTriaged:
		return TriagePhaseTriaged
	default:
		return ""
	}
}

func (t TriagePhase) IsValid() bool {
	return t.Validate() == nil
}

func (t TriagePhase) Validate() error {
	values := []TriagePhase{
		TriagePhaseToTriage,
		TriagePhaseTriaging,
		TriagePhaseTriaged,
	}

	for _, value := range values {
		if value == t {
			return nil
		}
	}
	return fmt.Errorf("triage-phase should be one of %v", values)
}

type ExecFailReason string

const (
	ExecFailReasonNone    ExecFailReason = "NONE"
	ExecFailReasonCase    ExecFailReason = "CASE"
	ExecFailReasonProduct ExecFailReason = "PRODUCT"
	ExecFailReasonEnv     ExecFailReason = "ENV"
)

var ReasonList = []ExecFailReason{
	ExecFailReasonNone,
	ExecFailReasonCase,
	ExecFailReasonProduct,
	ExecFailReasonEnv,
}

func (t *ExecFailReason) Scan(value interface{}) error {
	if value == nil {
		return errors.New("value of field reason error")
	}
	var reason int64
	if iv, err := driver.Int32.ConvertValue(value); err == nil {
		if v, ok := iv.(int64); ok {
			reason = v
		}
	}
	if reason >= 0 && reason < int64(len(ReasonList)) {
		*t = ReasonList[reason]
		return nil
	} else {
		return errors.New("unsupported ExecFailReason in sql Scan()")
	}
}

func (t ExecFailReason) Value() (driver.Value, error) {
	for i := 0; i < len(ReasonList); i++ {
		if t == ReasonList[i] {
			return int64(i), nil
		}
	}
	return int64(0), errors.New("unsupported ExecFailReason: " + string(t))
}

type ExecFailSolution string

const (
	ExecFailSolutionKEEP  ExecFailSolution = "KEEP"
	ExecFailSolutionFIX   ExecFailSolution = "FIX"
	ExecFailSolutionPAUSE ExecFailSolution = "PAUSE"
	ExecFailSolutionSTOP  ExecFailSolution = "STOP"
)

func (t ExecFailSolution) Values() []string {
	return []string{
		string(ExecFailSolutionKEEP),
		string(ExecFailSolutionFIX),
		string(ExecFailSolutionPAUSE),
		string(ExecFailSolutionSTOP),
	}
}

type DailySummaries []DailySummary

type DailySummary struct {
	CaseSummary DailySummaryDetails `json:"caseSummary"`
	PlanSummary DailySummaryDetails `json:"planSummary"`

	Date string `json:"date"`
}

type DailySummaryDetails struct {
	StatusSummary     map[ExecutionStatus]int `json:"statusSummary"`
	FailReasonSummary map[ExecFailReason]int  `json:"failReasonSummary"`

	FailureExecIDIncreased []ID `json:"failureExecIDIncreased"`
}

type CaseExecFailReason string

const (
	CaseExecFailReasonCase    CaseExecFailReason = "CASE"
	CaseExecFailReasonProduct CaseExecFailReason = "PRODUCT"
	CaseExecFailReasonEnv     CaseExecFailReason = "ENV"
)

func (t CaseExecFailReason) Values() []string {
	return []string{
		string(CaseExecFailReasonCase),
		string(CaseExecFailReasonProduct),
		string(CaseExecFailReasonEnv),
	}
}

type CaseTriage struct {
	ID         ID `json:"id"`
	ForkedFrom ID `json:"forkedFrom"`

	PlanExecutionID ID `json:"planExecutionID"`
	PlanID          ID `json:"planID"`
	CaseExecutionID ID `json:"caseExecutionID"`
	CaseID          ID `json:"caseID"`

	CreatedAt time.Time `json:"createdAt,omitempty"`
	UpdatedAt time.Time `json:"updatedAt,omitempty"`

	Reason    CaseExecFailReason `json:"reason,omitempty"`
	Solution  ExecFailSolution   `json:"solution,omitempty"`
	IssueLink string             `json:"issueLink,omitempty"`
	Note      string             `json:"note,omitempty"`
}
