package manage

import (
	"time"

	"github.com/tidbcloud/AgentTeam/internal/store/message"
	"github.com/tidbcloud/AgentTeam/internal/store/storeerr"
)

type requestError struct {
	kind    error
	message string
}

func (err requestError) Error() string {
	return err.message
}

func (err requestError) Unwrap() error {
	return err.kind
}

func badRequest(message string) error {
	return requestError{kind: storeerr.ErrBadRequest, message: message}
}

func forbidden(message string) error {
	return requestError{kind: storeerr.ErrForbidden, message: message}
}

func notFound(message string) error {
	return requestError{kind: storeerr.ErrNotFound, message: message}
}

func conflict(message string) error {
	return requestError{kind: storeerr.ErrConflict, message: message}
}

type SourceInput struct {
	SourceKind        SourceKind              `json:"sourceKind"`
	TimeMode          TimeMode                `json:"timeMode,omitempty"`
	ScheduledAt       *time.Time              `json:"scheduledAt,omitempty"`
	RelativeSeconds   *int64                  `json:"relativeSeconds,omitempty"`
	AnchorAt          *time.Time              `json:"anchorAt,omitempty"`
	IntervalSeconds   *int64                  `json:"intervalSeconds,omitempty"`
	CronExpression    string                  `json:"cronExpression,omitempty"`
	Timezone          string                  `json:"timezone,omitempty"`
	EventSubscription *EventSubscriptionInput `json:"eventSubscription,omitempty"`
}

type TargetInput struct {
	Kind TargetKind `json:"kind,omitempty"`
	Ref  string     `json:"ref"`
}

type UpsertInput struct {
	Name                  string                       `json:"name"`
	Source                SourceInput                  `json:"source"`
	Target                TargetInput                  `json:"target"`
	MessageTemplate       string                       `json:"messageTemplate"`
	MentionHints          []message.MessageMentionHint `json:"mentions,omitempty"`
	MentionHintsSet       bool                         `json:"-"`
	AlsoStartThread       bool                         `json:"alsoStartThread,omitempty"`
	HumanNotificationMode HumanNotificationMode        `json:"humanNotificationMode,omitempty"`
	IdempotencyKey        string                       `json:"idempotencyKey,omitempty"`
	ExpectedUpdatedAt     *time.Time                   `json:"expectedUpdatedAt,omitempty"`
}

type TargetView struct {
	Kind            TargetKind `json:"kind"`
	Ref             string     `json:"ref"`
	Label           string     `json:"label,omitempty"`
	ParentChannelID string     `json:"parentChannelId,omitempty"`
	ParentMessageID string     `json:"parentMessageId,omitempty"`
}

type ValidationView struct {
	Valid   bool   `json:"valid"`
	Code    string `json:"code,omitempty"`
	Message string `json:"message,omitempty"`
}

// ScheduleView is the canonical browser-facing schedule representation.
type ScheduleView struct {
	ID                    string                       `json:"id,omitempty"`
	Name                  string                       `json:"name"`
	Status                DefinitionStatus             `json:"status"`
	SourceKind            SourceKind                   `json:"sourceKind"`
	TimeMode              TimeMode                     `json:"timeMode,omitempty"`
	EventSubscription     *EventSubscriptionView       `json:"eventSubscription,omitempty"`
	ScheduledAt           *time.Time                   `json:"scheduledAt,omitempty"`
	RelativeSeconds       *int64                       `json:"relativeSeconds,omitempty"`
	AnchorAt              *time.Time                   `json:"anchorAt,omitempty"`
	IntervalSeconds       *int64                       `json:"intervalSeconds,omitempty"`
	CronExpression        string                       `json:"cronExpression,omitempty"`
	Timezone              string                       `json:"timezone,omitempty"`
	Target                TargetView                   `json:"target"`
	MessageTemplate       string                       `json:"messageTemplate"`
	MentionHints          []message.MessageMentionHint `json:"mentions,omitempty"`
	AlsoStartThread       bool                         `json:"alsoStartThread,omitempty"`
	HumanNotificationMode HumanNotificationMode        `json:"humanNotificationMode"`
	NextOccurrenceAt      *time.Time                   `json:"nextOccurrenceAt,omitempty"`
	LastRunAt             *time.Time                   `json:"lastRunAt,omitempty"`
	LastSuccessAt         *time.Time                   `json:"lastSuccessAt,omitempty"`
	LastFailureCode       string                       `json:"lastFailureCode,omitempty"`
	CreatedAt             time.Time                    `json:"createdAt"`
	UpdatedAt             time.Time                    `json:"updatedAt"`
	Validation            ValidationView               `json:"validation"`
}

// TriggerView is the legacy compatibility name used by /triggers handlers.
type TriggerView = ScheduleView

// ScheduleSummaryView is the bounded list representation returned by agent
// list APIs. Full configuration, including messageTemplate, stays available
// only through schedule_get/trigger_get and mutation responses.
type ScheduleSummaryView struct {
	ID               string           `json:"id,omitempty"`
	Name             string           `json:"name"`
	Status           DefinitionStatus `json:"status"`
	SourceKind       SourceKind       `json:"sourceKind"`
	TimeMode         TimeMode         `json:"timeMode,omitempty"`
	Target           TargetView       `json:"target"`
	NextOccurrenceAt *time.Time       `json:"nextOccurrenceAt,omitempty"`
	LastFailureCode  string           `json:"lastFailureCode,omitempty"`
}

// TriggerSummaryView is the legacy compatibility name used by /triggers
// handlers.
type TriggerSummaryView = ScheduleSummaryView

type ScheduleValidateResult struct {
	Current              *ScheduleView `json:"current,omitempty"`
	Proposed             ScheduleView  `json:"proposed"`
	EstimatedScheduledAt *time.Time    `json:"estimatedScheduledAt,omitempty"`
}

type ValidateResult = ScheduleValidateResult

// AutomationRunView exposes AttemptedAt as the effective run-history ordering
// timestamp: attempted_at when a run has been attempted, otherwise created_at.
// This preserves the public field while keeping it aligned with pagination
// cursors across unattempted rows.
type AutomationRunView struct {
	ID                     string     `json:"id"`
	ScheduleID             string     `json:"scheduleId,omitempty"`
	TriggerID              string     `json:"triggerId,omitempty"`
	WorkspaceID            string     `json:"workspaceId"`
	IdempotencyKey         string     `json:"idempotencyKey"`
	SourceOccurrenceRef    string     `json:"sourceOccurrenceRef"`
	SourceKind             SourceKind `json:"sourceKind"`
	TimeMode               TimeMode   `json:"timeMode,omitempty"`
	Status                 RunStatus  `json:"status"`
	ScheduledFor           *time.Time `json:"scheduledFor,omitempty"`
	OccurredAt             *time.Time `json:"occurredAt,omitempty"`
	AttemptedAt            time.Time  `json:"attemptedAt"`
	CompletedAt            *time.Time `json:"completedAt,omitempty"`
	MessageID              string     `json:"messageId,omitempty"`
	EffectKind             string     `json:"effectKind,omitempty"`
	EffectRef              string     `json:"effectRef,omitempty"`
	ErrorCode              string     `json:"errorCode,omitempty"`
	ErrorDetail            string     `json:"errorDetail,omitempty"`
	RenderedContentPreview string     `json:"renderedContentPreview"`
	AttemptCount           int        `json:"attemptCount"`
	Target                 TargetView `json:"target"`
	ScheduleName           string     `json:"scheduleName,omitempty"`
	TriggerName            string     `json:"triggerName,omitempty"`
}

type RunView = AutomationRunView

// RunListOptions bounds schedule run history reads with the stable effective
// COALESCE(attempted_at, created_at) DESC, id DESC keyset ordering.
type RunListOptions struct {
	Limit           int
	CursorAttempted *time.Time
	CursorID        string
}

type RunPage struct {
	Runs    []AutomationRunView
	HasMore bool
}

type normalizedMutation struct {
	record               definitionRecord
	target               TargetView
	validation           ValidationView
	validationErr        error
	estimatedScheduledAt *time.Time
	proposedNextAt       *time.Time
}
