package runstatus

import (
	"context"
	"strings"

	"github.com/codex-k8s/kodex/libs/go/crypto/tokencrypt"
	mcpdomain "github.com/codex-k8s/kodex/services/internal/control-plane/internal/domain/mcp"
	nextstepdomain "github.com/codex-k8s/kodex/services/internal/control-plane/internal/domain/nextstep"
	agentrunrepo "github.com/codex-k8s/kodex/services/internal/control-plane/internal/domain/repository/agentrun"
	agentsessionrepo "github.com/codex-k8s/kodex/services/internal/control-plane/internal/domain/repository/agentsession"
	floweventrepo "github.com/codex-k8s/kodex/services/internal/control-plane/internal/domain/repository/flowevent"
	githubratelimitwaitrepo "github.com/codex-k8s/kodex/services/internal/control-plane/internal/domain/repository/githubratelimitwait"
	platformtokenrepo "github.com/codex-k8s/kodex/services/internal/control-plane/internal/domain/repository/platformtoken"
	staffrunrepo "github.com/codex-k8s/kodex/services/internal/control-plane/internal/domain/repository/staffrun"
	runtimedeploydomain "github.com/codex-k8s/kodex/services/internal/control-plane/internal/domain/runtimedeploy"
	querytypes "github.com/codex-k8s/kodex/services/internal/control-plane/internal/domain/types/query"
)

// Phase identifies a run status event reflected in one GitHub issue comment.
type Phase string

const (
	PhaseCreated          Phase = "created"
	PhasePreparingRuntime Phase = "preparing_runtime"
	PhaseStarted          Phase = "started"
	PhaseAuthRequired     Phase = "auth_required"
	PhaseAuthResolved     Phase = "auth_resolved"
	PhaseReady            Phase = "ready"
	PhaseFinished         Phase = "finished"
	PhaseNamespaceDeleted Phase = "namespace_deleted"
)

// UpsertCommentParams describes one run status comment update request.
type UpsertCommentParams struct {
	RunID                    string
	Phase                    Phase
	JobName                  string
	JobNamespace             string
	RuntimeMode              string
	Namespace                string
	TriggerKind              string
	PromptLocale             string
	Model                    string
	ReasoningEffort          string
	RunStatus                string
	CodexAuthVerificationURL string
	CodexAuthUserCode        string
	Deleted                  bool
	AlreadyDeleted           bool
}

// UpsertCommentResult returns tracked issue comment metadata.
type UpsertCommentResult struct {
	CommentID  int64
	CommentURL string
}

// TriggerLabelConflictCommentParams describes one localized conflict comment request.
type TriggerLabelConflictCommentParams struct {
	CorrelationID      string
	RepositoryFullName string
	IssueNumber        int
	Locale             string
	TriggerLabel       string
	ConflictingLabels  []string
}

// TriggerLabelConflictCommentResult returns posted GitHub comment metadata.
type TriggerLabelConflictCommentResult struct {
	CommentID  int64
	CommentURL string
}

// TriggerWarningCommentParams describes one localized warning comment request
// when a webhook event was processed but run was not created.
type TriggerWarningCommentParams struct {
	CorrelationID      string
	RepositoryFullName string
	ThreadKind         string
	ThreadNumber       int
	Locale             string
	ReasonCode         TriggerWarningReasonCode
	ConflictingLabels  []string
	SuggestedLabels    []string
}

// TriggerWarningCommentResult returns posted GitHub comment metadata.
type TriggerWarningCommentResult struct {
	CommentID  int64
	CommentURL string
}

// EnsureNeedInputLabelParams describes one remediation request that guarantees `need:input` label.
type EnsureNeedInputLabelParams struct {
	CorrelationID      string
	RepositoryFullName string
	ThreadKind         string
	ThreadNumber       int
}

// EnsureNeedInputLabelResult describes label remediation outcome.
type EnsureNeedInputLabelResult struct {
	ThreadKind    string
	ThreadNumber  int
	Label         string
	AlreadyExists bool
}

// RequestedByType identifies who requested run namespace deletion.
type RequestedByType string

const (
	RequestedByTypeSystem    RequestedByType = "system"
	RequestedByTypeStaffUser RequestedByType = "staff_user"
)

// DeleteNamespaceParams describes one namespace delete request for a run.
type DeleteNamespaceParams struct {
	RunID           string
	RequestedByType RequestedByType
	RequestedByID   string
}

// DeleteNamespaceResult describes namespace delete operation outcome.
type DeleteNamespaceResult struct {
	RunID          string
	Namespace      string
	Deleted        bool
	AlreadyDeleted bool
	CommentURL     string
}

// CancelRunParams describes one run cancellation request.
type CancelRunParams struct {
	RunID             string
	Reason            string
	RequestedByType   RequestedByType
	RequestedByID     string
	RequestedByEmail  string
	RequestedByGitHub string
}

// CancelRunResult describes run cancellation outcome.
type CancelRunResult struct {
	RunID                        string
	PreviousStatus               string
	CurrentStatus                string
	AlreadyTerminal              bool
	RuntimeDeployCancelRequested bool
	JobStopped                   bool
	CanceledGitHubWaits          int
	CommentURL                   string
}

// RuntimeState describes current run runtime artifacts from status comment and Kubernetes.
type RuntimeState struct {
	HasStatusComment bool
	JobName          string
	JobNamespace     string
	Namespace        string
	JobExists        bool
	NamespaceExists  bool
}

// CleanupByIssueParams describes auto-cleanup scope for issue/pr close events.
type CleanupByIssueParams struct {
	RepositoryFullName string
	IssueNumber        int64
	RequestedByID      string
}

// CleanupByPullRequestParams describes auto-cleanup scope for pull request close/merge events.
type CleanupByPullRequestParams struct {
	RepositoryFullName string
	PRNumber           int64
	RequestedByID      string
}

// CleanupByIssueResult summarizes auto-cleanup outcomes.
type CleanupByIssueResult struct {
	MatchedRuns         int
	CleanedNamespaces   int
	AlreadyDeletedCount int
	SkippedRuns         int
	FailedRuns          int
}

// Config controls run status operations.
type Config struct {
	PublicBaseURL    string
	DefaultLocale    string
	AIDomain         string
	ProductionDomain string
	NextStepLabels   nextstepdomain.Labels
}

// KubernetesClient provides namespace cleanup operation for runstatus service.
type KubernetesClient interface {
	DeleteManagedRunNamespace(ctx context.Context, namespace string) (bool, error)
	NamespaceExists(ctx context.Context, namespace string) (bool, error)
	JobExists(ctx context.Context, namespace string, jobName string) (bool, error)
	DeleteJobIfExists(ctx context.Context, namespace string, jobName string) error
	FindManagedRunNamespaceByRunID(ctx context.Context, runID string) (string, bool, error)
}

type runtimeDeployController interface {
	RequestTaskAction(ctx context.Context, params runtimedeploydomain.TaskActionParams) (runtimedeploydomain.TaskActionResult, error)
}

// GitHubClient provides issue comment operations for runstatus service.
type GitHubClient interface {
	ListIssueComments(ctx context.Context, params mcpdomain.GitHubListIssueCommentsParams) ([]mcpdomain.GitHubIssueComment, error)
	GetIssueComment(ctx context.Context, params mcpdomain.GitHubGetIssueCommentParams) (mcpdomain.GitHubIssueComment, error)
	CreateIssueComment(ctx context.Context, params mcpdomain.GitHubCreateIssueCommentParams) (mcpdomain.GitHubIssueComment, error)
	EditIssueComment(ctx context.Context, params mcpdomain.GitHubEditIssueCommentParams) (mcpdomain.GitHubIssueComment, error)
	DeleteIssueComment(ctx context.Context, params mcpdomain.GitHubDeleteIssueCommentParams) error
	ListIssueReactions(ctx context.Context, params mcpdomain.GitHubListIssueReactionsParams) ([]mcpdomain.GitHubIssueReaction, error)
	CreateIssueReaction(ctx context.Context, params mcpdomain.GitHubCreateIssueReactionParams) (mcpdomain.GitHubIssueReaction, error)
	ListIssueLabels(ctx context.Context, params mcpdomain.GitHubListIssueLabelsParams) ([]mcpdomain.GitHubLabel, error)
	AddLabels(ctx context.Context, params mcpdomain.GitHubMutateLabelsParams) ([]mcpdomain.GitHubLabel, error)
}

// Dependencies wires required adapters for runstatus service.
type Dependencies struct {
	Runs                 agentrunrepo.Repository
	Sessions             agentsessionrepo.Repository
	Platform             platformtokenrepo.Repository
	TokenCrypt           *tokencrypt.Service
	GitHub               GitHubClient
	Kubernetes           KubernetesClient
	FlowEvents           floweventrepo.Repository
	StaffRuns            staffrunrepo.Repository
	GitHubRateLimitWaits githubratelimitwaitrepo.Repository
	RuntimeDeploy        runtimeDeployController
}

// Service maintains one run status message in issue comments and handles forced namespace cleanup.
type Service struct {
	cfg Config

	runs                 agentrunrepo.Repository
	sessions             agentsessionrepo.Repository
	platform             platformtokenrepo.Repository
	tokenCrypt           *tokencrypt.Service
	github               GitHubClient
	kubernetes           KubernetesClient
	flowEvents           floweventrepo.Repository
	staffRuns            staffrunrepo.Repository
	githubRateLimitWaits githubratelimitwaitrepo.Repository
	runtimeDeploy        runtimeDeployController
}

type runContext struct {
	run                 agentrunrepo.Run
	payload             querytypes.RunPayload
	commentTargetNumber int
	commentTargetKind   commentTargetKind
	repoOwner           string
	repoName            string
	githubToken         string
	triggerKind         string
}

func (c runContext) hasCommentTarget() bool {
	return c.commentTargetNumber > 0 && strings.TrimSpace(string(c.commentTargetKind)) != ""
}

type commentState struct {
	RunID                    string `json:"run_id"`
	Phase                    Phase  `json:"phase"`
	AuthRequested            bool   `json:"auth_requested,omitempty"`
	RepositoryFullName       string `json:"repository_full_name,omitempty"`
	IssueNumber              int    `json:"issue_number,omitempty"`
	JobName                  string `json:"job_name,omitempty"`
	JobNamespace             string `json:"job_namespace,omitempty"`
	RuntimeMode              string `json:"runtime_mode,omitempty"`
	RuntimeTargetEnv         string `json:"runtime_target_env,omitempty"`
	RuntimeBuildRef          string `json:"runtime_build_ref,omitempty"`
	RuntimeAccessProfile     string `json:"runtime_access_profile,omitempty"`
	Namespace                string `json:"namespace,omitempty"`
	SlotURL                  string `json:"slot_url,omitempty"`
	IssueURL                 string `json:"issue_url,omitempty"`
	PullRequestURL           string `json:"pull_request_url,omitempty"`
	TriggerKind              string `json:"trigger_kind,omitempty"`
	TriggerLabel             string `json:"trigger_label,omitempty"`
	DiscussionMode           bool   `json:"discussion_mode,omitempty"`
	PromptLocale             string `json:"prompt_locale,omitempty"`
	Model                    string `json:"model,omitempty"`
	ReasoningEffort          string `json:"reasoning_effort,omitempty"`
	RunStatus                string `json:"run_status,omitempty"`
	CodexAuthVerificationURL string `json:"codex_auth_verification_url,omitempty"`
	CodexAuthUserCode        string `json:"codex_auth_user_code,omitempty"`
	Deleted                  bool   `json:"deleted,omitempty"`
	AlreadyDeleted           bool   `json:"already_deleted,omitempty"`
}
