package domain

import (
	"strings"
	"time"
)

// DataPipelineSourceInput contains source credentials accepted by Create and
// source validation. It is input-only and must not be embedded in read models.
type DataPipelineSourceInput struct {
	Username      string
	Password      string
	TableFilter   []string
	CaseSensitive bool
}

// DataPipelineS3StagingInput contains the customer-managed S3 credentials
// accepted by Create and staging validation. SecretAccessKey is input-only.
type DataPipelineS3StagingInput struct {
	URI      string
	Region   string
	Endpoint string
	// Provider is empty for AWS S3. Alibaba OSS is addressed by an oss:// URI
	// and needs a custom endpoint, so the two travel together.
	Provider DataPipelineS3Provider
	AuthType DataPipelineS3AuthType
	// Populated for the access-key mode.
	AccessKeyID     string
	SecretAccessKey string
	// Populated for the role-ARN mode.
	RoleARN string
	// Optional. When set, the destination is told to consume this queue
	// instead of listing the staging prefix on a timer. The queue is the
	// customer's, attached to their bucket by their own notification
	// configuration, so an empty value is a normal configuration and not a
	// missing one.
	SQSQueueURL string
	SQSRegion   string
}

// UsesSQS reports whether the destination is notified of new staged objects
// rather than discovering them by polling.
func (i DataPipelineS3StagingInput) UsesSQS() bool {
	return strings.TrimSpace(i.SQSQueueURL) != ""
}

// UsesRoleARN reports whether this input assumes a role rather than carrying a
// static key pair.
func (i DataPipelineS3StagingInput) UsesRoleARN() bool {
	return i.AuthType == DataPipelineS3AuthTypeRoleARN
}

type DataPipelineStagingInput struct {
	Type DataPipelineStagingType
	S3   *DataPipelineS3StagingInput
}

type DataPipelineDestinationInput struct {
	Type DataPipelineDestinationType
	// Which Lake holds the warehouse. A TiDB organization may own several, so
	// the warehouse name alone does not identify where data lands.
	LakeOrgID            string
	Warehouse            string
	TargetNaming         DataPipelineTargetNaming
	FlushIntervalSeconds uint32
}

type DataPipelineEditableSourceInput struct {
	TableFilter   []string
	CaseSensitive bool
}

type DataPipelineEditableDestinationInput struct {
	Warehouse            string
	TargetNaming         DataPipelineTargetNaming
	FlushIntervalSeconds uint32
}

// DataPipelineEditableStagingInput is the part of the staging area an Edit may
// change. Where data lands is fixed at creation; only how the destination
// learns that it landed can move.
type DataPipelineEditableStagingInput struct {
	SQSQueueURL string
	SQSRegion   string
}

// UsesSQS reports whether this Edit leaves the Pipeline notified rather than
// polling.
func (i DataPipelineEditableStagingInput) UsesSQS() bool {
	return strings.TrimSpace(i.SQSQueueURL) != ""
}

type CreateDataPipelineReq struct {
	ClusterID uint64
	UserID    uint64
	// UserEmail is recorded on the row so a Console can name the creator
	// without a lookup the account service does not offer: it can resolve a
	// user by token, not by id, so the address has to be captured here while
	// the caller is still in hand.
	UserEmail               string
	Name                    string
	Source                  DataPipelineSourceInput
	Destination             DataPipelineDestinationInput
	Staging                 DataPipelineStagingInput
	SyncMode                DataPipelineSyncMode
	ChangefeedSpecification string
}

type CreateDataPipelineResp struct {
	PipelineID uint64
}

type GetDataPipelineReq struct {
	ClusterID  uint64
	PipelineID uint64
	UserID     uint64
}

type GetDataPipelineResp struct {
	DataPipeline *DataPipelineDetails
}

type ListDataPipelinesReq struct {
	ClusterID uint64
	UserID    uint64
	Page      uint32
	PerPage   uint32
	Status    *DataPipelineStatus
}

type ListDataPipelinesResp struct {
	DataPipelines []*DataPipelineDetails
	Total         uint32
}

type PauseDataPipelineReq struct {
	ClusterID  uint64
	PipelineID uint64
	UserID     uint64
}

// EditDataPipelineReq fully replaces the editable desired configuration of a
// paused Pipeline. It cannot change the changefeed specification: resizing is
// ScaleDataPipelineReq, which reuses the Changefeed scale workflow.
type EditDataPipelineReq struct {
	ClusterID   uint64
	PipelineID  uint64
	UserID      uint64
	Name        string
	Source      DataPipelineEditableSourceInput
	Destination DataPipelineEditableDestinationInput
	Staging     DataPipelineEditableStagingInput
}

// ValidateDataPipelineDestinationReq checks a destination before it is used.
type ValidateDataPipelineDestinationReq struct {
	ClusterID   uint64
	UserID      uint64
	SyncMode    DataPipelineSyncMode
	Destination DataPipelineDestinationInput
}

// ScaleDataPipelineReq changes the TiCDC capacity of a running Pipeline.
type ScaleDataPipelineReq struct {
	ClusterID               uint64
	PipelineID              uint64
	UserID                  uint64
	ChangefeedSpecification string
}

type ResumeDataPipelineReq struct {
	ClusterID  uint64
	PipelineID uint64
	UserID     uint64
}

type DeleteDataPipelineReq struct {
	ClusterID  uint64
	PipelineID uint64
	UserID     uint64
}

type ValidateDataPipelineSourceConnectionReq struct {
	ClusterID uint64
	UserID    uint64
	Username  string
	Password  string
}

type ValidateDataPipelineStagingReq struct {
	ClusterID uint64
	UserID    uint64
	LakeOrgID string
	Staging   DataPipelineStagingInput
}

// DataPipelineDetails augments the persisted business view with current child
// resource states and derived observation flags. Pipeline may contain encrypted
// credentials for internal orchestration, but never plaintext credentials.
// Console conversion must only project the explicitly safe fields.
type DataPipelineDetails struct {
	Pipeline       *DataPipeline
	ChildResources DataPipelineChildResourceDetails
	Observation    DataPipelineObservationDetails
}

type DataPipelineResourceDetails struct {
	Status       string
	ErrorMessage string
}

type DataPipelineLakeResourceDetails struct {
	DataSourceStatus  string
	IntegrationStatus string
	ErrorMessage      string
}

type DataPipelineChildResourceDetails struct {
	Export     DataPipelineResourceDetails
	Changefeed DataPipelineResourceDetails
	Lake       DataPipelineLakeResourceDetails
}

type DataPipelineObservationDetails struct {
	ChangefeedCheckpointTSO  uint64
	ChangefeedCheckpointTime *time.Time
	LakeResolvedTSO          uint64
	LakeResolvedTime         *time.Time
	LatencySeconds           uint64
	ObservedAt               *time.Time
	Stale                    bool
	Error                    *DataPipelineError

	// Reported by the destination for its latest incremental run only, and so
	// zero for the whole life of a snapshot-only Pipeline. Per-run, not
	// cumulative.
	RowsSynced      uint64
	InsertCount     uint64
	UpdateCount     uint64
	DeleteCount     uint64
	TablesActive    int32
	TablesError     int32
	DatabasesActive int32
}

// GetDataPipelineStagingTrustReq asks which identities a customer must trust
// on the IAM role they intend to use for role-ARN staging access.
type GetDataPipelineStagingTrustReq struct {
	ClusterID uint64
	UserID    uint64
	LakeOrgID string
}

// DataPipelineStagingTrustPrincipal is one identity that assumes that role.
type DataPipelineStagingTrustPrincipal struct {
	Name       string
	RoleARN    string
	ExternalID string
}

type GetDataPipelineStagingTrustResp struct {
	Principals []DataPipelineStagingTrustPrincipal
	// The actions those principals need. Knowing which roles to trust is only
	// half of a working policy, and the other half fails later and less
	// legibly - partway through a delivery rather than at validation.
	BucketActions []string
	QueueActions  []string
}
