package domain

import "time"

// WorkTaskStatus represents the status of a work task.
type WorkTaskStatus string

const (
	WorkTaskStatusPending   WorkTaskStatus = "pending"
	WorkTaskStatusRunning   WorkTaskStatus = "running"
	WorkTaskStatusCompleted WorkTaskStatus = "completed"
	WorkTaskStatusFailed    WorkTaskStatus = "failed"
	WorkTaskStatusCancelled WorkTaskStatus = "cancelled"
)

// WorkErrorCode represents a categorized error type for failed tasks.
// This enables clients to distinguish between different failure modes
// and take appropriate action (e.g., retry vs wait vs report).
type WorkErrorCode string

const (
	// WorkErrorCodeNone indicates no error (task succeeded or still running).
	WorkErrorCodeNone WorkErrorCode = ""

	// WorkErrorCodeRateLimited indicates the agent hit its rate limit.
	// Client should wait for the limit to reset before retrying.
	WorkErrorCodeRateLimited WorkErrorCode = "RATE_LIMITED"

	// WorkErrorCodeAuthFailed indicates authentication/authorization failure.
	// Requires manual intervention to re-authenticate the agent.
	WorkErrorCodeAuthFailed WorkErrorCode = "AUTH_FAILED"

	// WorkErrorCodeTimeout indicates the task exceeded its time limit.
	// May be retried, possibly with a longer timeout or simpler prompt.
	WorkErrorCodeTimeout WorkErrorCode = "TIMEOUT"

	// WorkErrorCodeStaleWorker indicates the worker stopped responding.
	// The task was recovered by maintenance and can be retried.
	WorkErrorCodeStaleWorker WorkErrorCode = "STALE_WORKER"

	// WorkErrorCodeAgentError indicates a generic agent execution error.
	// The error message contains details.
	WorkErrorCodeAgentError WorkErrorCode = "AGENT_ERROR"

	// WorkErrorCodeInvalidSpec indicates the task specification was invalid.
	// Should not be retried without fixing the spec.
	WorkErrorCodeInvalidSpec WorkErrorCode = "INVALID_SPEC"
)

// ClassifyAgentError examines an error message and stderr output to determine
// the appropriate error code. This enables automated handling of known failure modes.
func ClassifyAgentError(errMsg, stderr string) WorkErrorCode {
	combined := errMsg + "\n" + stderr

	// Rate limit detection - Claude Code specific messages
	rateLimitPatterns := []string{
		"You've hit your limit",
		"rate limit",
		"Rate limit",
		"too many requests",
		"Too many requests",
		"quota exceeded",
		"Quota exceeded",
	}
	for _, pattern := range rateLimitPatterns {
		if containsIgnoreCase(combined, pattern) {
			return WorkErrorCodeRateLimited
		}
	}

	// Authentication failure detection
	authPatterns := []string{
		"not authenticated",
		"authentication failed",
		"unauthorized",
		"Unauthorized",
		"invalid api key",
		"Invalid API key",
		"please log in",
		"Please log in",
		"claude login",
	}
	for _, pattern := range authPatterns {
		if containsIgnoreCase(combined, pattern) {
			return WorkErrorCodeAuthFailed
		}
	}

	// Timeout detection
	timeoutPatterns := []string{
		"context deadline exceeded",
		"context canceled",
		"timeout",
		"Timeout",
		"timed out",
	}
	for _, pattern := range timeoutPatterns {
		if containsIgnoreCase(combined, pattern) {
			return WorkErrorCodeTimeout
		}
	}

	// Default to generic agent error
	return WorkErrorCodeAgentError
}

// containsIgnoreCase checks if s contains substr (case-insensitive).
func containsIgnoreCase(s, substr string) bool {
	return len(s) >= len(substr) &&
		(s == substr ||
			len(substr) == 0 ||
			findIgnoreCase(s, substr) >= 0)
}

// findIgnoreCase finds substr in s (case-insensitive), returns -1 if not found.
func findIgnoreCase(s, substr string) int {
	if len(substr) == 0 {
		return 0
	}
	if len(s) < len(substr) {
		return -1
	}
	// Simple linear search with case-insensitive comparison
	for i := 0; i <= len(s)-len(substr); i++ {
		match := true
		for j := 0; j < len(substr); j++ {
			sc := s[i+j]
			pc := substr[j]
			// ASCII lowercase conversion
			if sc >= 'A' && sc <= 'Z' {
				sc += 'a' - 'A'
			}
			if pc >= 'A' && pc <= 'Z' {
				pc += 'a' - 'A'
			}
			if sc != pc {
				match = false
				break
			}
		}
		if match {
			return i
		}
	}
	return -1
}

// IsValid returns true if the status is a known valid status.
func (s WorkTaskStatus) IsValid() bool {
	switch s {
	case WorkTaskStatusPending, WorkTaskStatusRunning, WorkTaskStatusCompleted,
		WorkTaskStatusFailed, WorkTaskStatusCancelled:
		return true
	}
	return false
}

// WorkTaskType represents the type of work task.
type WorkTaskType string

const (
	WorkTaskTypeBuild  WorkTaskType = "build"
	WorkTaskTypeTest   WorkTaskType = "test"
	WorkTaskTypeDeploy WorkTaskType = "deploy"
	WorkTaskTypeCustom WorkTaskType = "custom"
	WorkTaskTypeVerify WorkTaskType = "verify"
	WorkTaskTypeSDLC   WorkTaskType = "sdlc"
)

// IsValid returns true if the task type is a known valid type.
func (t WorkTaskType) IsValid() bool {
	switch t {
	case WorkTaskTypeBuild, WorkTaskTypeTest, WorkTaskTypeDeploy, WorkTaskTypeCustom, WorkTaskTypeVerify, WorkTaskTypeSDLC:
		return true
	}
	return false
}

// SDLCTaskSpec defines parameters for SDLC CLI commands via worker pool.
// Used for skeleton/monorepo projects that don't have a dedicated pod.
type SDLCTaskSpec struct {
	// Command is the SDLC CLI command to execute (e.g., "feature-create", "artifact-approve").
	Command string `json:"command"`

	// Args contains CLI arguments for the command.
	Args []string `json:"args"`

	// GitCloneURL is the repository URL for cloning (required for worker execution).
	GitCloneURL string `json:"git_clone_url"`

	// AutoCommit indicates whether to commit .sdlc/ changes after execution.
	AutoCommit bool `json:"auto_commit"`

	// AutoPush indicates whether to push commits after commit.
	AutoPush bool `json:"auto_push"`
}

// WorkTask represents a task in the work queue.
type WorkTask struct {
	// ID is the unique task identifier.
	ID string

	// ProjectID is the project this task belongs to.
	ProjectID string

	// Type is the task type (build, test, deploy, custom).
	Type WorkTaskType

	// Spec contains task-specific parameters.
	// For build tasks: template, prompt, variables, auto_deploy, git_url
	// For test tasks: test_command, git_url
	// For deploy tasks: image, replicas, env
	Spec map[string]any

	// Status is the current task status.
	Status WorkTaskStatus

	// Priority determines execution order (higher = more urgent).
	Priority int

	// WorkerID is the ID of the worker that claimed this task.
	WorkerID string

	// CallbackURL is the webhook URL for completion notification.
	CallbackURL string

	// CreatedAt is when the task was created.
	CreatedAt time.Time

	// StartedAt is when a worker started executing the task.
	StartedAt *time.Time

	// CompletedAt is when the task finished (success or failure).
	CompletedAt *time.Time

	// Result contains the task output (if completed).
	Result *WorkResult

	// Error contains the error message (if failed).
	Error string

	// ErrorCode categorizes the failure type for programmatic handling.
	// Only set when Status is WorkTaskStatusFailed.
	ErrorCode WorkErrorCode

	// RetryCount is the number of retry attempts.
	RetryCount int

	// MaxRetries is the maximum allowed retry attempts.
	MaxRetries int
}

// WorkResult contains the result of a completed task.
type WorkResult struct {
	// Output is the main output from task execution.
	Output string `json:"output,omitempty"`

	// Artifacts contains named artifacts from the task.
	// For build tasks: commit_sha, deploy_url, etc.
	Artifacts map[string]string `json:"artifacts,omitempty"`
}

// WorkQueueStats contains queue statistics.
type WorkQueueStats struct {
	// Pending is the count of pending tasks.
	Pending int64 `json:"pending"`

	// Running is the count of running tasks.
	Running int64 `json:"running"`

	// Completed is the count of completed tasks (last 24h).
	Completed int64 `json:"completed"`

	// Failed is the count of failed tasks (last 24h).
	Failed int64 `json:"failed"`

	// Cancelled is the count of cancelled tasks (last 24h).
	Cancelled int64 `json:"cancelled"`

	// OldestPending is the age of the oldest pending task.
	OldestPending *time.Duration `json:"oldest_pending,omitempty"`
}

// WorkListOptions contains pagination options for listing tasks.
type WorkListOptions struct {
	// Limit is the maximum number of tasks to return (default: 50, max: 100).
	Limit int

	// Offset is the number of tasks to skip (for pagination).
	Offset int
}

// DefaultWorkListOptions returns options with default values.
func DefaultWorkListOptions() WorkListOptions {
	return WorkListOptions{
		Limit:  50,
		Offset: 0,
	}
}

// Normalize applies defaults and limits to the options.
func (o *WorkListOptions) Normalize() {
	if o.Limit <= 0 {
		o.Limit = 50
	}
	if o.Limit > 100 {
		o.Limit = 100
	}
	if o.Offset < 0 {
		o.Offset = 0
	}
}

// WorkListResult contains paginated task results.
type WorkListResult struct {
	// Tasks is the list of tasks.
	Tasks []*WorkTask

	// Total is the total count of matching tasks (for pagination metadata).
	Total int64

	// Limit is the limit that was applied.
	Limit int

	// Offset is the offset that was applied.
	Offset int
}
