// Package clustercontext contains the public Data Proxy metadata contract and
// an adapter to Clinic's canonical internal resource API.
package clustercontext

import (
	"context"
	"errors"
)

var (
	// ErrNotFound is returned when a cluster does not exist in the requested org.
	ErrNotFound = errors.New("cluster metadata not found")
	// ErrUnavailable is returned when the metadata repository is not configured.
	ErrUnavailable = errors.New("cluster metadata repository unavailable")
	// ErrTimeout is returned when the metadata store misses its request deadline.
	ErrTimeout = errors.New("cluster metadata repository timeout")
	// ErrUnauthenticated means the caller did not supply valid user credentials.
	ErrUnauthenticated = errors.New("cluster metadata request unauthenticated")
	// ErrPermissionDenied means the authenticated caller cannot access the resource.
	ErrPermissionDenied = errors.New("cluster metadata request permission denied")
	// ErrResourceExhausted means the upstream service rate limited the request.
	ErrResourceExhausted = errors.New("cluster metadata request rate limited")
	// ErrBadGateway means an upstream returned an invalid or unsupported response.
	ErrBadGateway = errors.New("cluster metadata upstream failure")
)

// DiagnosticContext contains transitional diagnostic metadata. New Data Proxy
// handlers must not accept these values back from callers as routing input.
type DiagnosticContext struct {
	ProjectID  string `json:"projectId,omitempty"`
	ParentID   string `json:"parentId,omitempty"`
	ShootName  string `json:"shootName,omitempty"`
	KeyspaceID string `json:"keyspaceId,omitempty"`
}

// Cluster is the Investibook-minimal canonical metadata response.
type Cluster struct {
	ClusterID         string            `json:"clusterId"`
	OrgID             string            `json:"orgId"`
	Name              string            `json:"name"`
	Status            string            `json:"status"`
	Deleted           bool              `json:"deleted"`
	Version           string            `json:"version"`
	Provider          string            `json:"provider"`
	Region            string            `json:"region"`
	DeployType        string            `json:"deployType"`
	DeployTypeV2      string            `json:"deployTypeV2"`
	CreatedAt         string            `json:"createdAt,omitempty"`
	DiagnosticContext DiagnosticContext `json:"diagnosticContext"`
}

// ListOptions controls an org-scoped metadata query.
type ListOptions struct {
	Page        int
	PageSize    int
	Query       string
	ShowDeleted bool
}

// Page is the canonical collection response for cluster metadata.
type Page struct {
	Items    []Cluster `json:"items"`
	Page     int       `json:"page"`
	PageSize int       `json:"pageSize"`
	Total    int64     `json:"total"`
}

// Repository provides canonical metadata owned by Clinic. Org IDs are TiDB
// Cloud/DBAAS IDs, not Clinic internal primary keys.
type Repository interface {
	GetByClusterID(ctx context.Context, clusterID string) (*Cluster, error)
	GetByOrgAndClusterID(ctx context.Context, orgID uint64, clusterID string) (*Cluster, error)
	ListByOrg(ctx context.Context, orgID uint64, opts ListOptions) (*Page, error)
}

// UserRepository resolves only the clusters visible to the authenticated user.
type UserRepository interface {
	ListByOrgForUser(ctx context.Context, orgID uint64, opts ListOptions, authorization string, traceHeaders map[string][]string) (*Page, error)
}

type unavailableRepository struct{}

// NewUnavailableRepository keeps public routes registered in isolated tests
// that do not construct the Clinic internal client.
func NewUnavailableRepository() Repository {
	return unavailableRepository{}
}

func (unavailableRepository) GetByClusterID(context.Context, string) (*Cluster, error) {
	return nil, ErrUnavailable
}

func (unavailableRepository) GetByOrgAndClusterID(context.Context, uint64, string) (*Cluster, error) {
	return nil, ErrUnavailable
}

func (unavailableRepository) ListByOrg(context.Context, uint64, ListOptions) (*Page, error) {
	return nil, ErrUnavailable
}
