// Package domain contains pure domain models with no external dependencies.
// These types represent the core business concepts of the application.
package domain

import "regexp"

// ProjectID is a strongly-typed identifier for projects.
type ProjectID string

// Project name/ID constraints.
const (
	// MaxProjectNameLen is the maximum length for project names (K8s name limit).
	MaxProjectNameLen = 63
)

// projectIDRegex validates project IDs used for referencing existing projects.
// Allows uppercase, lowercase, digits, dashes, and underscores. Must start with a letter.
var projectIDRegex = regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9_-]*$`)

// projectNameRegex validates project names for DNS/K8s resource creation.
// Lowercase only, digits, dashes. Must start with a lowercase letter.
var projectNameRegex = regexp.MustCompile(`^[a-z][a-z0-9-]*$`)

// reservedProjectNames are names that cannot be used for new projects.
var reservedProjectNames = map[string]bool{
	"www": true, "api": true, "git": true, "ci": true,
	"registry": true, "admin": true, "root": true,
	"rdev": true, "pantheon": true,
}

// ValidateProjectID validates a project ID for referencing existing projects.
// Allows letters, digits, dashes, underscores. Must start with a letter. Max 63 chars.
func ValidateProjectID(id string) error {
	if id == "" {
		return ErrInvalidProjectName
	}
	if len(id) > MaxProjectNameLen {
		return ErrInvalidProjectName
	}
	if !projectIDRegex.MatchString(id) {
		return ErrInvalidProjectName
	}
	return nil
}

// ValidateProjectName validates a project name for DNS/K8s resource creation.
// Lowercase letters, digits, dashes only. Must start with a lowercase letter.
// Max 63 chars. Rejects reserved names.
func ValidateProjectName(name string) error {
	if name == "" {
		return ErrInvalidProjectName
	}
	if len(name) > MaxProjectNameLen {
		return ErrInvalidProjectName
	}
	if !projectNameRegex.MatchString(name) {
		return ErrInvalidProjectName
	}
	if reservedProjectNames[name] {
		return ErrInvalidProjectName
	}
	return nil
}

// Project represents a claudebox project that can execute commands.
type Project struct {
	ID          ProjectID
	Name        string
	Description string
	PodName     string
	Status      ProjectStatus
	Workspace   string

	// AgentProvider specifies which code agent to use for this project.
	// Empty string means use the system default (typically Claude Code).
	AgentProvider AgentProvider
}

// ProjectStatus represents the current state of a project's pod.
type ProjectStatus string

const (
	ProjectStatusRunning  ProjectStatus = "running"
	ProjectStatusPending  ProjectStatus = "pending"
	ProjectStatusFailed   ProjectStatus = "failed"
	ProjectStatusNotFound ProjectStatus = "not_found"
	ProjectStatusUnknown  ProjectStatus = "unknown"
	ProjectStatusError    ProjectStatus = "error"
)

// IsAvailable returns true if the project can accept commands.
func (s ProjectStatus) IsAvailable() bool {
	return s == ProjectStatusRunning
}

// IsTerminal returns true if the status is a final state.
func (s ProjectStatus) IsTerminal() bool {
	return s == ProjectStatusFailed || s == ProjectStatusNotFound
}

// K8s label and annotation constants for project discovery.
// Pods with these labels are discovered as rdev projects.
const (
	// LabelProject marks a pod as an rdev project when set to "true".
	LabelProject = "rdev.orchard9.ai/project"

	// LabelName specifies the project name (used as project ID).
	LabelName = "rdev.orchard9.ai/name"

	// LabelWorkspace specifies the workspace path inside the pod.
	LabelWorkspace = "rdev.orchard9.ai/workspace"

	// LabelAgentProvider specifies which code agent to use ("claudecode", "opencode").
	LabelAgentProvider = "rdev.orchard9.ai/agent-provider"

	// AnnotDescription provides a human-readable description of the project.
	AnnotDescription = "rdev.orchard9.ai/description"
)
