package exec

import (
	"bytes"
	"encoding/json"
	"time"

	invopopjsonschema "github.com/invopop/jsonschema"
)

type workflowPlanActorResponse struct {
	Type     string `json:"type"`
	ID       string `json:"id"`
	MemberID string `json:"memberId"`
}

type workflowPlanVersionRefResponse struct {
	ID string `json:"id"`
}

type workflowPlanResponse struct {
	ID             string                          `json:"id"`
	ScopeID        string                          `json:"scopeId"`
	Key            string                          `json:"key"`
	DisplayName    string                          `json:"displayName"`
	DescriptionMD  string                          `json:"descriptionMd"`
	State          string                          `json:"state"`
	Revision       int64                           `json:"revision"`
	CurrentVersion *workflowPlanVersionRefResponse `json:"currentVersion,omitempty"`
	DefaultVersion *workflowPlanVersionRefResponse `json:"defaultVersion,omitempty"`
	CreatedBy      workflowPlanActorResponse       `json:"createdBy"`
	CreatedAt      time.Time                       `json:"createdAt"`
	UpdatedBy      workflowPlanActorResponse       `json:"updatedBy"`
	UpdatedAt      time.Time                       `json:"updatedAt"`
	ArchivedBy     *workflowPlanActorResponse      `json:"archivedBy,omitempty"`
	ArchivedAt     *time.Time                      `json:"archivedAt,omitempty"`
}

type workflowPlanDraftResponse struct {
	PlanID    string                    `json:"planId"`
	Source    string                    `json:"source"`
	Layout    workflowValue             `json:"layout"`
	Revision  int64                     `json:"revision"`
	UpdatedBy workflowPlanActorResponse `json:"updatedBy"`
	CreatedAt time.Time                 `json:"createdAt"`
	UpdatedAt time.Time                 `json:"updatedAt"`
}

type workflowPlanAgentViewResponse struct {
	PlanID          string                          `json:"planId"`
	ScopeID         string                          `json:"scopeId"`
	PlanRevision    int64                           `json:"planRevision"`
	State           string                          `json:"state"`
	Source          string                          `json:"source,omitempty"`
	SourceCursor    string                          `json:"sourceCursor,omitempty"`
	WorkingRevision int64                           `json:"workingRevision"`
	PlanVersion     *workflowPlanVersionRefResponse `json:"planVersion,omitempty"`
	TeamID          string                          `json:"teamId,omitempty"`
	TeamWorkflowID  string                          `json:"teamWorkflowId,omitempty"`
	Payload         *workflowPayloadPageResponse    `json:"payload,omitempty"`
}

type workflowPayloadRefResponse struct {
	Cursor string `json:"cursor"`
}

type workflowPayloadPageResponse struct {
	Section    string `json:"section"`
	Encoding   string `json:"encoding"`
	Value      string `json:"value"`
	NextCursor string `json:"nextCursor,omitempty"`
}

type workflowPlanVersionResponse struct {
	ID              string                      `json:"id"`
	PlanID          string                      `json:"planId"`
	DraftRevision   *int64                      `json:"draftRevision,omitempty"`
	SourceVersionID *string                     `json:"sourceVersionId,omitempty"`
	Source          string                      `json:"source,omitempty"`
	SourceCursor    string                      `json:"sourceCursor,omitempty"`
	Layout          workflowValue               `json:"layout,omitempty"`
	LayoutRef       *workflowPayloadRefResponse `json:"layoutRef,omitempty"`
	CompilerVersion string                      `json:"compilerVersion"`
	Digest          string                      `json:"digest"`
	PublishedBy     workflowPlanActorResponse   `json:"publishedBy"`
	PublishedAt     time.Time                   `json:"publishedAt"`
}

type workflowPlanDiagnosticResponse struct {
	Severity string `json:"severity"`
	Code     string `json:"code"`
	Path     string `json:"path"`
	Message  string `json:"message"`
	Line     int    `json:"line,omitempty"`
	Column   int    `json:"column,omitempty"`
	NodeID   string `json:"nodeId,omitempty"`
	EdgeID   string `json:"edgeId,omitempty"`
}

type workflowPlanValidationResponse struct {
	Diagnostics []workflowPlanDiagnosticResponse `json:"diagnostics"`
	Digest      string                           `json:"digest,omitempty"`
}

type workflowPlanCreateResponse struct {
	Plan  workflowPlanResponse      `json:"plan"`
	Draft workflowPlanDraftResponse `json:"draft"`
}

type workflowPlanPublishResponse struct {
	Plan    workflowPlanResponse        `json:"plan"`
	Version workflowPlanVersionResponse `json:"version"`
}

type workflowPlanListResponse struct {
	Items      []workflowPlanResponse `json:"items"`
	NextCursor string                 `json:"nextCursor,omitempty"`
}

type workflowTriggerActorResponse struct {
	Type     string `json:"type"`
	ID       string `json:"id"`
	MemberID string `json:"memberId,omitempty"`
}

type workflowTriggerOwnerResponse struct {
	UserID   string `json:"userId"`
	MemberID string `json:"memberId"`
}

type workflowTriggerRevisionRefResponse struct {
	ID       string `json:"id"`
	Revision int64  `json:"revision"`
}

type workflowTriggerResponse struct {
	ID             string                              `json:"id"`
	PlanID         string                              `json:"planId"`
	Key            string                              `json:"key"`
	DisplayName    string                              `json:"displayName"`
	DescriptionMD  string                              `json:"descriptionMd"`
	State          string                              `json:"state"`
	Revision       int64                               `json:"revision"`
	LatestRevision *workflowTriggerRevisionRefResponse `json:"latestRevision,omitempty"`
	ActiveRevision *workflowTriggerRevisionRefResponse `json:"activeRevision,omitempty"`
	Owner          workflowTriggerOwnerResponse        `json:"owner"`
	CreatedBy      workflowTriggerActorResponse        `json:"createdBy"`
	CreatedAt      time.Time                           `json:"createdAt"`
	UpdatedBy      workflowTriggerActorResponse        `json:"updatedBy"`
	UpdatedAt      time.Time                           `json:"updatedAt"`
	ArchivedBy     *workflowTriggerActorResponse       `json:"archivedBy,omitempty"`
	ArchivedAt     *time.Time                          `json:"archivedAt,omitempty"`
}

type workflowTriggerScheduleResponse struct {
	Mode            string         `json:"mode"`
	CronExpression  string         `json:"cronExpression,omitempty"`
	Timezone        string         `json:"timezone,omitempty"`
	IntervalSeconds *int64         `json:"intervalSeconds,omitempty"`
	AnchorAt        *time.Time     `json:"anchorAt,omitempty"`
	ScheduledAt     *time.Time     `json:"scheduledAt,omitempty"`
	RelativeSeconds *int64         `json:"relativeSeconds,omitempty"`
	Inputs          workflowObject `json:"inputs"`
}

type workflowTriggerSourceType string

func (workflowTriggerSourceType) JSONSchema() *invopopjsonschema.Schema {
	return &invopopjsonschema.Schema{Type: "string", Const: "schedule"}
}

type workflowTriggerSourceResponse struct {
	Type     workflowTriggerSourceType       `json:"type"`
	Schedule workflowTriggerScheduleResponse `json:"schedule"`
}

type workflowTriggerInputPolicyResponse struct {
	Defaults  workflowNullableObject `json:"defaults,omitempty"`
	Constants workflowNullableObject `json:"constants,omitempty"`
}

type workflowTriggerRevisionResponse struct {
	ID            string                             `json:"id"`
	TriggerID     string                             `json:"triggerId"`
	PlanID        string                             `json:"planId"`
	Revision      int64                              `json:"revision"`
	PlanVersionID string                             `json:"planVersionId"`
	Source        workflowTriggerSourceResponse      `json:"source"`
	InputPolicy   workflowTriggerInputPolicyResponse `json:"inputPolicy"`
	Digest        string                             `json:"digest"`
	CreatedBy     workflowTriggerActorResponse       `json:"createdBy"`
	CreatedAt     time.Time                          `json:"createdAt"`
}

type workflowTriggerDiagnosticResponse struct {
	Severity string `json:"severity"`
	Code     string `json:"code"`
	Path     string `json:"path"`
	Message  string `json:"message"`
}

type workflowTriggerValidationResponse struct {
	Diagnostics []workflowTriggerDiagnosticResponse `json:"diagnostics"`
	Digest      string                              `json:"digest,omitempty"`
}

type workflowTriggerMutationResponse struct {
	Trigger  workflowTriggerResponse         `json:"trigger"`
	Revision workflowTriggerRevisionResponse `json:"revision"`
}

type workflowTriggerShowResponse struct {
	Trigger  workflowTriggerResponse         `json:"trigger"`
	Revision workflowTriggerRevisionResponse `json:"revision"`
}

type workflowTriggerListResponse struct {
	Items      []workflowTriggerResponse `json:"items"`
	NextCursor string                    `json:"nextCursor,omitempty"`
}

type workflowTriggerRevisionListResponse struct {
	Items      []workflowTriggerRevisionResponse `json:"items"`
	NextCursor string                            `json:"nextCursor,omitempty"`
}

type workflowMessageScopeResponse struct {
	Kind    workflowMessageScopeKind `json:"kind"`
	ScopeID workflowMessageScopeID   `json:"scopeId"`
}

func (value *workflowMessageScopeResponse) UnmarshalJSON(raw []byte) error {
	scope, err := decodeWorkflowMessageScope(raw)
	if err != nil {
		return err
	}
	value.Kind = workflowMessageScopeKind(scope.Kind)
	value.ScopeID = workflowMessageScopeID(scope.ScopeID)
	return nil
}

type workflowMessageScopeKind string

func (workflowMessageScopeKind) JSONSchema() *invopopjsonschema.Schema {
	return &invopopjsonschema.Schema{
		Type: "string",
		Enum: []any{"channel", "thread", "dm", "task"},
	}
}

type workflowMessageScopeID string

func (workflowMessageScopeID) JSONSchema() *invopopjsonschema.Schema {
	return &invopopjsonschema.Schema{
		Type:    "string",
		Pattern: workflowScopeIDPattern,
	}
}

// workflowNullableMessageScopeResponse retains the protocol distinction
// between an omitted legacy field and an explicit collaboration null while still
// validating the non-null object as one canonical scope.
type workflowNullableMessageScopeResponse []byte

func (value *workflowNullableMessageScopeResponse) UnmarshalJSON(raw []byte) error {
	raw = bytes.TrimSpace(raw)
	if bytes.Equal(raw, []byte("null")) {
		*value = append((*value)[:0], raw...)
		return nil
	}
	scope, err := decodeWorkflowMessageScope(raw)
	if err != nil {
		return err
	}
	encoded, err := json.Marshal(workflowMessageScopeResponse{
		Kind:    workflowMessageScopeKind(scope.Kind),
		ScopeID: workflowMessageScopeID(scope.ScopeID),
	})
	if err != nil {
		return err
	}
	*value = append((*value)[:0], encoded...)
	return nil
}

func (value workflowNullableMessageScopeResponse) MarshalJSON() ([]byte, error) {
	if len(value) == 0 {
		return []byte("null"), nil
	}
	return append([]byte(nil), value...), nil
}

func (workflowNullableMessageScopeResponse) JSONSchema() *invopopjsonschema.Schema {
	reflector := invopopjsonschema.Reflector{
		Anonymous: true, DoNotReference: true, ExpandedStruct: true,
	}
	scope := reflector.Reflect(workflowMessageScopeResponse{})
	scope.Version = ""
	return &invopopjsonschema.Schema{
		OneOf: []*invopopjsonschema.Schema{
			{Type: "null"},
			scope,
		},
	}
}

type workflowStepView struct {
	RunID             string                             `json:"runId"`
	StepID            string                             `json:"stepId"`
	Status            string                             `json:"status"`
	RunStatus         string                             `json:"runStatus"`
	Input             workflowValue                      `json:"input,omitempty"`
	OutputContract    workflowValue                      `json:"outputContract,omitempty"`
	WorkItemsContract *workflowWorkItemsContractResponse `json:"workItemsContract,omitempty"`
	Payload           *workflowPayloadPageResponse       `json:"payload,omitempty"`
	InputRef          *workflowPayloadRefResponse        `json:"inputRef,omitempty"`
	OutputContractRef *workflowPayloadRefResponse        `json:"outputContractRef,omitempty"`
	WorkItemsRef      *workflowPayloadRefResponse        `json:"workItemsRef,omitempty"`
	DeliveryScope     *workflowMessageScopeResponse      `json:"deliveryScope,omitempty"`
	// WorkScope preserves omitted, Agent-selected null, and a canonical scope.
	WorkScope     workflowNullableMessageScopeResponse `json:"workScope,omitempty"`
	RelatedScopes *[]workflowMessageScopeResponse      `json:"relatedScopes,omitempty"`
	Deadline      *time.Time                           `json:"deadline,omitempty"`
	Replayed      bool                                 `json:"replayed"`
	// TeamMemberContext is the frozen minimal Workflow-specific member context
	// for a responder of any Run with a frozen Team ID (Team-linked authoritative
	// binding or dynamic-explicit teamId; team identity/purpose, teamMemberId,
	// role label, role overlay). It never includes the team roster, other
	// members' duties, wake configuration, or Team division hints.
	TeamMemberContext *workflowTeamMemberContextResponse `json:"teamMemberContext,omitempty"`
}

// workflowTeamMemberContextResponse is the Desktop wire shape of the frozen
// minimal Workflow-specific member context.
type workflowTeamMemberContextResponse struct {
	TeamID          string `json:"teamId"`
	TeamHandle      string `json:"teamHandle,omitempty"`
	TeamDisplayName string `json:"teamDisplayName,omitempty"`
	TeamPurpose     string `json:"teamPurpose,omitempty"`
	TeamMemberID    string `json:"teamMemberId"`
	Role            string `json:"role,omitempty"`
	RoleLabel       string `json:"roleLabel,omitempty"`
	RoleOverlay     string `json:"roleOverlay,omitempty"`
}

type workflowStepListResponse struct {
	Steps      []workflowStepSummary `json:"steps"`
	NextCursor string                `json:"nextCursor,omitempty"`
}

type workflowStepSummary struct {
	RunID     string     `json:"runId"`
	StepID    string     `json:"stepId"`
	Status    string     `json:"status"`
	RunStatus string     `json:"runStatus"`
	Deadline  *time.Time `json:"deadline,omitempty"`
}

type workflowWorkItemsContractResponse struct {
	Required                  bool     `json:"required"`
	MaxItems                  int      `json:"maxItems"`
	MaxKeyBytes               int      `json:"maxKeyBytes"`
	MaxRelatedScopesPerItem   int      `json:"maxRelatedScopesPerItem"`
	MaxDependencyEdges        int      `json:"maxDependencyEdges"`
	MaxRelatedScopeReferences int      `json:"maxRelatedScopeReferences"`
	MaxJSONValues             int      `json:"maxJsonValues"`
	MaxJSONBytes              int      `json:"maxJsonBytes"`
	AllowedResponders         []string `json:"allowedResponders"`
	// DependencyValueContract is the server-frozen ArtifactContract for each
	// dependencies.<key>.value object.
	DependencyValueContract workflowValue `json:"dependencyValueContract"`
}
