package db

import "time"

// PullRequestStack is the repository-scoped, explicitly persisted Stack
// resource exposed by GitHub's Stacked pull requests REST and GraphQL APIs.
// Membership and ordering live in PullRequestStackEntry; they are never
// inferred from branch names at read time.
type PullRequestStack struct {
	ID           uint                    `gorm:"primaryKey;autoIncrement"`
	RepositoryID uint                    `gorm:"not null;uniqueIndex:idx_pr_stack_repo_number;index"`
	Repository   Repository              `gorm:"foreignKey:RepositoryID"`
	Number       int                     `gorm:"not null;uniqueIndex:idx_pr_stack_repo_number"`
	BaseRef      string                  `gorm:"size:255;not null"`
	BaseSHA      string                  `gorm:"size:64"`
	Entries      []PullRequestStackEntry `gorm:"foreignKey:StackID"`
	CreatedAt    time.Time
	UpdatedAt    time.Time
}

// PullRequestStackNumberCounter allocates Stack numbers independently from
// the shared issue/pull-request number namespace.
type PullRequestStackNumberCounter struct {
	RepositoryID uint       `gorm:"primaryKey;autoIncrement:false"`
	Repository   Repository `gorm:"foreignKey:RepositoryID"`
	NextNumber   int        `gorm:"not null;default:1"`
	CreatedAt    time.Time
	UpdatedAt    time.Time
}

// PullRequestStackEntry is an ordered member of a Stack. A pull request can
// belong to at most one Stack and a Stack can have only one entry per position.
type PullRequestStackEntry struct {
	ID            uint             `gorm:"primaryKey;autoIncrement"`
	StackID       uint             `gorm:"not null;uniqueIndex:idx_pr_stack_position;index"`
	Stack         PullRequestStack `gorm:"foreignKey:StackID"`
	PullRequestID uint             `gorm:"not null;uniqueIndex"`
	PullRequest   PullRequest      `gorm:"foreignKey:PullRequestID"`
	Position      int              `gorm:"not null;uniqueIndex:idx_pr_stack_position"`
	CreatedAt     time.Time
	UpdatedAt     time.Time
}

// AsyncMergeRequest stores the public asynchronous merge operation and its
// retained result. UUID is the identifier returned by the REST API.
type AsyncMergeRequest struct {
	ID                   uint        `gorm:"primaryKey;autoIncrement"`
	UUID                 string      `gorm:"size:64;not null;uniqueIndex"`
	RepositoryID         uint        `gorm:"not null;index"`
	Repository           Repository  `gorm:"foreignKey:RepositoryID"`
	PullRequestID        uint        `gorm:"not null;index"`
	PullRequest          PullRequest `gorm:"foreignKey:PullRequestID"`
	ActorID              uint        `gorm:"not null;index"`
	Actor                User        `gorm:"foreignKey:ActorID"`
	Status               string      `gorm:"size:20;not null;index"`
	MergeMethod          string      `gorm:"size:20;not null"`
	MergeAction          string      `gorm:"size:20;not null"`
	EffectiveMergeAction string      `gorm:"size:20;not null"`
	CommitTitle          string      `gorm:"type:text"`
	CommitMessage        LargeText
	ExpectedHeadSHA      string `gorm:"size:64;not null"`
	// MergeBaseSHA and MergePlanJSON are written before a direct Stack Git
	// update. They let restart recovery prove whether the push happened and
	// reconstruct exact per-member merge SHAs without replaying the merge.
	MergeBaseSHA      string `gorm:"size:64"`
	MergePlanJSON     LargeText
	ResultSHA         string `gorm:"size:64"`
	FailureMessage    string `gorm:"type:text"`
	MergeQueueEntryID *uint  `gorm:"index"`
	CreatedAt         time.Time
	UpdatedAt         time.Time
	ExpiresAt         time.Time `gorm:"index"`
}

// MergeQueue is the public queue for one repository base branch.
type MergeQueue struct {
	ID           uint              `gorm:"primaryKey;autoIncrement"`
	RepositoryID uint              `gorm:"not null;uniqueIndex:idx_merge_queue_repo_base;index"`
	Repository   Repository        `gorm:"foreignKey:RepositoryID"`
	BaseRef      string            `gorm:"size:255;not null;uniqueIndex:idx_merge_queue_repo_base"`
	Entries      []MergeQueueEntry `gorm:"foreignKey:QueueID"`
	CreatedAt    time.Time
	UpdatedAt    time.Time
}

// MergeQueueEntry is a real queued pull request. Descendant entries in a
// Stack share StackBatchID so queue ejection can cascade upward without
// affecting lower positions.
type MergeQueueEntry struct {
	ID             uint        `gorm:"primaryKey;autoIncrement"`
	QueueID        uint        `gorm:"not null;index"`
	Queue          MergeQueue  `gorm:"foreignKey:QueueID"`
	PullRequestID  uint        `gorm:"not null;index"`
	PullRequest    PullRequest `gorm:"foreignKey:PullRequestID"`
	AsyncRequestID *uint       `gorm:"index"`
	Position       int         `gorm:"not null;index"`
	State          string      `gorm:"size:32;not null;index"`
	EnqueuedByID   uint        `gorm:"not null;index"`
	EnqueuedBy     User        `gorm:"foreignKey:EnqueuedByID"`
	HeadSHA        string      `gorm:"size:64;not null"`
	BaseSHA        string      `gorm:"size:64"`
	StackBatchID   string      `gorm:"size:64;index"`
	StackPosition  int
	Jump           bool        `gorm:"default:false"`
	Solo           bool        `gorm:"default:false"`
	MergeGroupID   *uint       `gorm:"index"`
	MergeGroup     *MergeGroup `gorm:"foreignKey:MergeGroupID"`
	CreatedAt      time.Time
	UpdatedAt      time.Time
}

// MergeGroup represents a speculative merge group whose synthetic ref is
// checked by Actions through the merge_group event.
type MergeGroup struct {
	ID             uint       `gorm:"primaryKey;autoIncrement"`
	QueueID        uint       `gorm:"not null;index"`
	Queue          MergeQueue `gorm:"foreignKey:QueueID"`
	HeadEntryID    uint       `gorm:"not null;index"`
	ActorID        uint       `gorm:"index"`
	EntryCount     int        `gorm:"not null"`
	HeadSHA        string     `gorm:"size:64;not null;index"`
	HeadRef        string     `gorm:"size:512;not null"`
	BaseSHA        string     `gorm:"size:64"`
	BaseRef        string     `gorm:"size:255;not null"`
	Status         string     `gorm:"size:32;not null;index"`
	TerminalReason string     `gorm:"size:32;index"`
	RefPublishedAt *time.Time
	RefDeletedAt   *time.Time
	CreatedAt      time.Time
	UpdatedAt      time.Time
}

// MergeGroupLifecycleEvent durably records merge-group lifecycle transitions
// and the Actions work derived from checks_requested. GitHub exposes the
// corresponding webhook only to GitHub Apps; repository hooks must not consume
// these rows.
type MergeGroupLifecycleEvent struct {
	ID                  uint       `gorm:"primaryKey;autoIncrement"`
	MergeGroupID        uint       `gorm:"not null;uniqueIndex:idx_merge_group_lifecycle_kind;index"`
	MergeGroup          MergeGroup `gorm:"foreignKey:MergeGroupID"`
	Kind                string     `gorm:"size:32;not null;uniqueIndex:idx_merge_group_lifecycle_kind"`
	Reason              string     `gorm:"size:32"`
	ActorID             *uint      `gorm:"index"`
	Actor               User       `gorm:"foreignKey:ActorID;constraint:OnDelete:SET NULL"`
	ActionsDispatchedAt *time.Time
	CreatedAt           time.Time
	UpdatedAt           time.Time
}

// PullRequestMergeQueueEvent backs the public AddedToMergeQueueEvent and
// RemovedFromMergeQueueEvent timeline item types.
type PullRequestMergeQueueEvent struct {
	ID            uint        `gorm:"primaryKey;autoIncrement"`
	PullRequestID uint        `gorm:"not null;index"`
	PullRequest   PullRequest `gorm:"foreignKey:PullRequestID"`
	QueueID       uint        `gorm:"not null;index"`
	Queue         MergeQueue  `gorm:"foreignKey:QueueID"`
	QueueEntryID  uint        `gorm:"not null;index"`
	ActorID       uint        `gorm:"not null;index"`
	Actor         User        `gorm:"foreignKey:ActorID"`
	EventType     string      `gorm:"size:32;not null;index"`
	BeforeSHA     string      `gorm:"size:64"`
	Reason        string      `gorm:"type:text"`
	CreatedAt     time.Time
}
