package domain

import (
	"strings"
	"time"
)

// OperationType represents the type of operation.
type OperationType string

const (
	OperationTypeProjectCreate     OperationType = "project.create"
	OperationTypeComponentAdd      OperationType = "component.add"
	OperationTypeBuild             OperationType = "build"
	OperationTypeCIBuild           OperationType = "ci.build"
	OperationTypeResourceProvision OperationType = "resource.provision"
)

// IsValid returns true if the operation type is known.
func (t OperationType) IsValid() bool {
	switch t {
	case OperationTypeProjectCreate, OperationTypeComponentAdd,
		OperationTypeBuild, OperationTypeCIBuild, OperationTypeResourceProvision:
		return true
	}
	return false
}

// OperationStatus represents the status of an operation.
type OperationStatus string

const (
	OperationStatusPending   OperationStatus = "pending"
	OperationStatusRunning   OperationStatus = "running"
	OperationStatusCompleted OperationStatus = "completed"
	OperationStatusFailed    OperationStatus = "failed"
)

// IsValid returns true if the status is known.
func (s OperationStatus) IsValid() bool {
	switch s {
	case OperationStatusPending, OperationStatusRunning,
		OperationStatusCompleted, OperationStatusFailed:
		return true
	}
	return false
}

// IsTerminal returns true if the status is a final state.
func (s OperationStatus) IsTerminal() bool {
	return s == OperationStatusCompleted || s == OperationStatusFailed
}

// OperationStep represents a single step within an operation.
type OperationStep struct {
	// Name is the step identifier (e.g., "git", "build-api", "deploy-web").
	Name string `json:"name"`

	// Status is the step status.
	Status OperationStatus `json:"status"`

	// StartedAt is when the step started.
	StartedAt time.Time `json:"started_at"`

	// DurationMs is the step duration in milliseconds.
	DurationMs int64 `json:"duration_ms,omitempty"`

	// Output contains step-specific output data.
	Output map[string]any `json:"output,omitempty"`

	// Error is a one-line error summary.
	Error string `json:"error,omitempty"`

	// ErrorDetail is the full error detail.
	ErrorDetail string `json:"error_detail,omitempty"`
}

// Operation represents a tracked project operation.
type Operation struct {
	// ID is the unique operation identifier.
	ID string `json:"id"`

	// ProjectID is the project this operation belongs to.
	ProjectID string `json:"project_id"`

	// Type is the operation type.
	Type OperationType `json:"type"`

	// Status is the current operation status.
	Status OperationStatus `json:"status"`

	// RequestID is the HTTP request that initiated this operation.
	RequestID string `json:"request_id,omitempty"`

	// TriggeredBy is the ID of the parent operation that triggered this one.
	TriggeredBy string `json:"triggered_by,omitempty"`

	// CommitSHA is the git commit this operation created or was triggered by.
	CommitSHA string `json:"commit_sha,omitempty"`

	// ExternalRef is an external reference (e.g., "build#42").
	ExternalRef string `json:"external_ref,omitempty"`

	// StartedAt is when the operation started.
	StartedAt time.Time `json:"started_at"`

	// CompletedAt is when the operation finished.
	CompletedAt *time.Time `json:"completed_at,omitempty"`

	// DurationMs is the total operation duration in milliseconds.
	DurationMs int64 `json:"duration_ms,omitempty"`

	// Input contains the operation input parameters.
	Input map[string]any `json:"input,omitempty"`

	// Output contains the operation output/result.
	Output map[string]any `json:"output,omitempty"`

	// Error is a one-line error summary.
	Error string `json:"error,omitempty"`

	// ErrorDetail is the full error detail (truncated to 10KB).
	ErrorDetail string `json:"error_detail,omitempty"`

	// Steps contains the operation steps.
	Steps []OperationStep `json:"steps,omitempty"`

	// CreatedAt is when the record was created.
	CreatedAt time.Time `json:"created_at"`
}

// StepsSummary returns a human-readable summary of step statuses.
// Example: "git ✓ → build-web ✓ → build-api ✗"
func (o *Operation) StepsSummary() string {
	if len(o.Steps) == 0 {
		return ""
	}

	var parts []string
	for _, step := range o.Steps {
		symbol := "?"
		switch step.Status {
		case OperationStatusCompleted:
			symbol = "✓"
		case OperationStatusFailed:
			symbol = "✗"
		case OperationStatusRunning:
			symbol = "…"
		case OperationStatusPending:
			symbol = "○"
		}
		parts = append(parts, step.Name+" "+symbol)
	}
	return strings.Join(parts, " → ")
}

// FailedStep returns the first failed step, or nil if none failed.
func (o *Operation) FailedStep() *OperationStep {
	for i := range o.Steps {
		if o.Steps[i].Status == OperationStatusFailed {
			return &o.Steps[i]
		}
	}
	return nil
}

// OperationFilters specifies criteria for listing operations.
type OperationFilters struct {
	// ProjectID filters by project (required for List).
	ProjectID string

	// Type filters by operation type.
	Type OperationType

	// Status filters by operation status.
	Status OperationStatus

	// CommitSHA filters by commit SHA.
	CommitSHA string

	// Since filters operations started after this time.
	Since time.Time

	// Limit is the maximum number of operations to return.
	Limit int
}

// DefaultOperationFilters returns filters with default values.
func DefaultOperationFilters() OperationFilters {
	return OperationFilters{
		Limit: 50,
	}
}

// Normalize applies defaults and limits to the filters.
func (f *OperationFilters) Normalize() {
	if f.Limit <= 0 {
		f.Limit = 50
	}
	if f.Limit > 200 {
		f.Limit = 200
	}
}

// MaxErrorDetailSize is the maximum size of error_detail (10KB).
const MaxErrorDetailSize = 10 * 1024

// TruncateErrorDetail truncates error detail to the maximum allowed size.
func TruncateErrorDetail(detail string) string {
	if len(detail) <= MaxErrorDetailSize {
		return detail
	}
	return detail[:MaxErrorDetailSize-3] + "..."
}
