package core

import "time"

type Repo struct {
	ID            string
	Name          string
	RemoteURL     string
	DefaultBranch string
	WorkspaceRoot string
	CredentialRef string
}

type WorkspaceLease struct {
	ID        string
	RepoID    string
	Slot      string
	Path      string
	State     WorkspaceState
	ExpiresAt *time.Time
}

type WorkspaceState string

const (
	WorkspaceAvailable WorkspaceState = "available"
	WorkspaceLeased    WorkspaceState = "leased"
	WorkspaceDirty     WorkspaceState = "dirty"
	WorkspaceError     WorkspaceState = "error"
)

type Operation struct {
	ID     string
	RepoID string
	Type   OperationType
	State  OperationState
	// IdempotencyKey is an optional globally unique create-dedupe key.
	IdempotencyKey string
	CreatedBy      string
	CreatedAt      time.Time
	UpdatedAt      time.Time
}

type OperationType string

const (
	OperationClone    OperationType = "clone"
	OperationFetch    OperationType = "fetch"
	OperationCommit   OperationType = "commit"
	OperationPush     OperationType = "push"
	OperationAgentRun OperationType = "agent_run"
)

func (t OperationType) Valid() bool {
	switch t {
	case OperationClone, OperationFetch, OperationCommit, OperationPush, OperationAgentRun:
		return true
	default:
		return false
	}
}

type OperationState string

const (
	OperationQueued    OperationState = "queued"
	OperationRunning   OperationState = "running"
	OperationSucceeded OperationState = "succeeded"
	OperationFailed    OperationState = "failed"
	OperationCancelled OperationState = "cancelled"
)

func (s OperationState) Valid() bool {
	switch s {
	case OperationQueued, OperationRunning, OperationSucceeded, OperationFailed, OperationCancelled:
		return true
	default:
		return false
	}
}

func (s OperationState) Terminal() bool {
	switch s {
	case OperationSucceeded, OperationFailed, OperationCancelled:
		return true
	default:
		return false
	}
}

func (s OperationState) CanTransitionTo(next OperationState) bool {
	if !s.Valid() || !next.Valid() || s == next {
		return false
	}
	switch s {
	case OperationQueued:
		return next == OperationRunning || next == OperationCancelled
	case OperationRunning:
		return next == OperationSucceeded || next == OperationFailed || next == OperationCancelled
	default:
		return false
	}
}

type RevisionEvent struct {
	RepoID       string
	Branch       string
	Before       string
	After        string
	ChangedFiles []ChangedFile
	ObservedAt   time.Time
}

type ChangedFile struct {
	Path       string
	ChangeType string
}

type ChangeRequestState string

const (
	ChangeRequestOpen   ChangeRequestState = "open"
	ChangeRequestMerged ChangeRequestState = "merged"
	ChangeRequestClosed ChangeRequestState = "closed"
)

func (s ChangeRequestState) Valid() bool {
	switch s {
	case ChangeRequestOpen, ChangeRequestMerged, ChangeRequestClosed:
		return true
	default:
		return false
	}
}

func (s ChangeRequestState) Terminal() bool {
	switch s {
	case ChangeRequestMerged, ChangeRequestClosed:
		return true
	default:
		return false
	}
}

type ChangeRequestAction string

const (
	ChangeRequestActionCreate        ChangeRequestAction = "create"
	ChangeRequestActionUpdate        ChangeRequestAction = "update"
	ChangeRequestActionComment       ChangeRequestAction = "comment"
	ChangeRequestActionRequestReview ChangeRequestAction = "request_review"
	ChangeRequestActionMerge         ChangeRequestAction = "merge"
	ChangeRequestActionClose         ChangeRequestAction = "close"
)

func (a ChangeRequestAction) Valid() bool {
	switch a {
	case ChangeRequestActionCreate,
		ChangeRequestActionUpdate,
		ChangeRequestActionComment,
		ChangeRequestActionRequestReview,
		ChangeRequestActionMerge,
		ChangeRequestActionClose:
		return true
	default:
		return false
	}
}

type ChangeRequest struct {
	Provider     string
	ExternalID   string
	RepoID       string
	SourceBranch string
	TargetBranch string
	Title        string
	Body         string
	Draft        bool
	State        ChangeRequestState
}

type ChangeRequestCreate struct {
	RepoID       string
	SourceBranch string
	TargetBranch string
	Title        string
	Body         string
	Draft        bool
}

type ChangeRequestUpdate struct {
	Title        *string
	Body         *string
	Draft        *bool
	TargetBranch *string
}

type ChangeRequestComment struct {
	Body string
}

type ChangeRequestReviewRequest struct {
	Reviewers []string
	Teams     []string
}

type ChangeRequestMerge struct {
	CommitTitle   string
	CommitMessage string
}

type ChangeRequestClose struct {
	Reason string
}

type BranchWatch struct {
	ID        string
	Provider  string
	RepoID    string
	Branch    string
	CreatedAt time.Time
}

type RevisionCursor struct {
	RepoID     string
	Branch     string
	Revision   string
	ObservedAt time.Time
}

type ProviderDelivery struct {
	ID         string
	Provider   string
	DeliveryID string
	DedupeKey  string
	EventID    string
	RepoID     string
	Branch     string
	Revision   string
	CreatedAt  time.Time
}

// DurableAgentRunInput is the persisted subset of agent run input that does
// not include secret values. Credential refs and raw secrets are never stored.
type DurableAgentRunInput struct {
	OperationID      string
	RepoID           string
	Branch           string
	WorkspacePath    string
	Instruction      string
	PolicyContext    map[string]any
	ExpectedRevision string
	CreatedAt        time.Time
}

type WebhookDeliveryStatus string

const (
	WebhookDeliveryPending   WebhookDeliveryStatus = "pending"
	WebhookDeliverySending   WebhookDeliveryStatus = "sending"
	WebhookDeliverySucceeded WebhookDeliveryStatus = "succeeded"
	WebhookDeliveryRetryable WebhookDeliveryStatus = "retryable"
	WebhookDeliveryFailed    WebhookDeliveryStatus = "failed"
)

func (s WebhookDeliveryStatus) Valid() bool {
	switch s {
	case WebhookDeliveryPending, WebhookDeliverySending, WebhookDeliverySucceeded, WebhookDeliveryRetryable, WebhookDeliveryFailed:
		return true
	default:
		return false
	}
}

type WebhookDelivery struct {
	ID             string
	EventID        string
	SubscriptionID string
	Status         WebhookDeliveryStatus
	AttemptCount   int
	NextAttemptAt  time.Time
	LastStatusCode int
	LastError      string
	CreatedAt      time.Time
	UpdatedAt      time.Time
}
