// Package changerequest models the change_requests entity and the server-side
// merge gate. A change request links a project/workspace/(requirement|issue)
// and a source->target branch to an external (Gitea) pull request, carrying a
// review verdict + CI state. The crux is Service.Merge, which hard-blocks the
// host-side merge unless review_verdict=='approved' (and optionally
// ci_state=='success'): an agent can open and merge PRs via MCP, but cannot
// self-approve — approval is HTTP/web-only by policy.
//
// Layout mirrors internal/workspace (single package, service + repository +
// handler + sqlc) to keep the aggregate cohesive.
package changerequest

import (
	"context"
	"time"

	"github.com/google/uuid"
)

// State mirrors the change_requests.state CHECK constraint.
type State string

// State enum values.
const (
	StateOpen   State = "open"
	StateMerged State = "merged"
	StateClosed State = "closed"
)

// Verdict mirrors the change_requests.review_verdict CHECK constraint.
type Verdict string

// Verdict enum values.
const (
	VerdictPending          Verdict = "pending"
	VerdictApproved         Verdict = "approved"
	VerdictChangesRequested Verdict = "changes_requested"
	VerdictRejected         Verdict = "rejected"
)

// IsValid reports whether v is in the enum set.
func (v Verdict) IsValid() bool {
	switch v {
	case VerdictPending, VerdictApproved, VerdictChangesRequested, VerdictRejected:
		return true
	}
	return false
}

// CIState mirrors the change_requests.ci_state CHECK constraint.
type CIState string

// CIState enum values.
const (
	CIUnknown CIState = "unknown"
	CIPending CIState = "pending"
	CISuccess CIState = "success"
	CIFailure CIState = "failure"
)

// ChangeRequest is the change_requests row projection.
type ChangeRequest struct {
	ID             uuid.UUID
	ProjectID      uuid.UUID
	WorkspaceID    uuid.UUID
	RequirementID  *uuid.UUID
	IssueID        *uuid.UUID
	Number         int
	Title          string
	Description    string
	SourceBranch   string
	TargetBranch   string
	State          State
	ReviewVerdict  Verdict
	CIState        CIState
	Provider       string
	ExternalID     *int64
	ExternalURL    string
	MergeCommitSHA string
	ReviewedBy     *uuid.UUID
	ReviewedAt     *time.Time
	CreatedBy      uuid.UUID
	MergedAt       *time.Time
	CreatedAt      time.Time
	UpdatedAt      time.Time
}

// Caller mirrors workspace.Caller: the user context driving auth + audit.
type Caller struct {
	UserID    uuid.UUID
	IsAdmin   bool
	SessionID *uuid.UUID
}

// CreateInput carries the fields to open a change request (and host PR).
type CreateInput struct {
	SourceBranch  string
	TargetBranch  string // empty => workspace default branch
	Title         string
	Description   string
	RequirementID *uuid.UUID
	IssueID       *uuid.UUID
}

// Service is the change-request application service.
type Service interface {
	Create(ctx context.Context, c Caller, wsID uuid.UUID, in CreateInput) (*ChangeRequest, error)
	Get(ctx context.Context, c Caller, id uuid.UUID) (*ChangeRequest, error)
	GetByNumber(ctx context.Context, c Caller, projectSlug string, number int) (*ChangeRequest, error)
	ListByWorkspace(ctx context.Context, c Caller, wsID uuid.UUID) ([]*ChangeRequest, error)
	// Review records a human verdict (owner/admin only). It is intentionally NOT
	// exposed as an MCP tool so agents cannot self-approve their own PRs.
	Review(ctx context.Context, c Caller, id uuid.UUID, verdict Verdict, note string) (*ChangeRequest, error)
	// Merge is the gate: requires review_verdict=='approved' (+ ci success when
	// RequireCIPass), then merges the host PR and persists merged state.
	Merge(ctx context.Context, c Caller, id uuid.UUID, method string) (*ChangeRequest, error)
	// SyncStatus refreshes ci_state/state from the host (provider.GetPR).
	SyncStatus(ctx context.Context, c Caller, id uuid.UUID) (*ChangeRequest, error)
}
