// Package knowledgeqa owns durable server-hosted Knowledge Q&A sessions,
// turns, attempts, evidence metadata, owner-visible events, runtime root
// handles, and accounting checkpoints. It deliberately has no Agent or Machine
// routing state.
package knowledgeqa

import (
	"errors"
	"time"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/knowledgeqa/protocol"
	"gorm.io/gorm"
)

const (
	MaxUserRunningTurns         = 1
	MaxUserQueuedTurns          = 2
	MaxOrganizationRunningTurns = 8
	MaxUserSubmissionsPerMinute = 6
	MaxOrgSubmissionsPerMinute  = 60

	CitationKindKnowledge = "knowledge"
	CitationKindWeb       = "web"

	// AccountingRecoveryWindow bounds retries while remaining shorter than the
	// MeshX checkpoint TTL.
	AccountingRecoveryWindow = 24 * time.Hour
)

var (
	ErrNotFound      = errors.New("knowledge Q&A session not found")
	ErrForbidden     = errors.New("knowledge Q&A session forbidden")
	ErrTurnBusy      = errors.New("knowledge Q&A session already has an active turn")
	ErrQueueFull     = errors.New("knowledge Q&A queue is full")
	ErrRateLimited   = errors.New("knowledge Q&A submission rate exceeded")
	ErrInvalidState  = errors.New("knowledge Q&A state transition is invalid")
	ErrEventSequence = errors.New("knowledge Q&A event sequence is invalid")
)

type Session struct {
	ID                        string
	WorkspaceID               string
	OrganizationID            string
	OwnerUserID               string
	OwnerMemberID             string
	RootMessageID             string
	ThreadChannelID           string
	RequestedKnowledgeBaseIDs []string
	RequestedSourceIDs        []string
	RequestedModel            string
	RequestedReasonLevel      string
	WebSearchEnabled          bool
	ActiveTurnID              string
	Status                    string
	LastActivityAt            time.Time
	CreatedAt                 time.Time
	UpdatedAt                 time.Time
}

type CreateSessionParams struct {
	ID                        string
	WorkspaceID               string
	OrganizationID            string
	OwnerUserID               string
	OwnerMemberID             string
	RootMessageID             string
	ThreadChannelID           string
	RequestedKnowledgeBaseIDs []string
	RequestedSourceIDs        []string
	RequestedModel            string
	RequestedReasonLevel      string
	WebSearchEnabled          bool
	Now                       time.Time
}

type Turn struct {
	ID                        string
	WorkspaceID               string
	OrganizationID            string
	SessionID                 string
	RequesterUserID           string
	UserMessageID             string
	AssistantMessageID        string
	Question                  string
	IdempotencyKey            string
	RequestedKnowledgeBaseIDs []string
	RequestedSourceIDs        []string
	AuthorizedRoots           []AuthorizedRoot
	RequestedModel            string
	RequestedReasonLevel      string
	WebSearchEnabled          bool
	EffectiveModel            string
	EffectiveReasonLevel      string
	OrganizationPolicyVersion int64
	RuntimeVersion            string
	PromptVersion             string
	CurrentAttemptID          string
	Status                    string
	ErrorCode                 string
	ErrorDetail               string
	DebugModelOutput          string
	QueuedAt                  time.Time
	StartedAt                 *time.Time
	CompletedAt               *time.Time
	UpdatedAt                 time.Time
	Activities                []protocol.RuntimeActivity
}

type Attempt struct {
	ID             string
	WorkspaceID    string
	OrganizationID string
	TurnID         string
	AttemptNumber  int64
	IdempotencyKey string
	Status         string
	ErrorCode      string
	ErrorDetail    string
	Usage          map[string]any
	SettlementRef  string
	SettlementRefs []string
	QueuedAt       time.Time
	StartedAt      *time.Time
	CompletedAt    *time.Time
	UpdatedAt      time.Time
}

type AuthorizedRoot struct {
	ID              string
	KnowledgeBaseID string
	SourceID        string
	RootHandleRef   string
	RootKind        string
	RepoRole        string
	Revision        string
	FreshnessStatus string
}

type Citation struct {
	ID              string
	WorkspaceID     string
	TurnID          string
	AttemptID       string
	CitationKind    string
	KnowledgeBaseID string
	SourceID        string
	RootKind        string
	RepoRole        string
	Revision        string
	ResolvedRef     string
	ResolvedRefKind string
	Path            string
	LineStart       int64
	LineEnd         int64
	URL             string
	Title           string
	Snippet         string
	FetchedAt       *time.Time
	CreatedAt       time.Time
}

type RuntimeHistoryTurn struct {
	TurnID   string
	Status   string
	Question string
	Answer   string
}

type RuntimeContext struct {
	Generation             int64
	Summary                string
	CompactedThroughTurnID string
	SummaryVersion         string
	Turns                  []RuntimeHistoryTurn
	Bytes                  int
}

type RuntimeContextUpdate struct {
	ExpectedGeneration     int64
	Summary                string
	CompactedThroughTurnID string
	SummaryVersion         string
}

type CreateTurnParams struct {
	ID                        string
	AttemptID                 string
	WorkspaceID               string
	OrganizationID            string
	SessionID                 string
	RequesterUserID           string
	UserMessageID             string
	Question                  string
	IdempotencyKey            string
	RequestedKnowledgeBaseIDs []string
	RequestedSourceIDs        []string
	Now                       time.Time
}

type RetryTurnParams struct {
	WorkspaceID     string
	SessionID       string
	TurnID          string
	RequesterUserID string
	IdempotencyKey  string
	AttemptID       string
	Now             time.Time
}

type TurnSnapshot struct {
	AuthorizedRoots           []AuthorizedRoot
	EffectiveModel            string
	EffectiveReasonLevel      string
	OrganizationPolicyVersion int64
	RuntimeVersion            string
	PromptVersion             string
}

type Completion struct {
	Status             string
	AssistantMessageID string
	ErrorCode          string
	ErrorDetail        string
	DebugModelOutput   string
	Usage              map[string]any
	SettlementRef      string
	SettlementRefs     []string
	RecoverAccounting  bool
	RuntimeContext     *RuntimeContextUpdate
	Now                time.Time
}

// AccountingRecovery is one terminal attempt whose MeshX accounting
// checkpoint still needs an owner-bound recovery read.
type AccountingRecovery struct {
	WorkspaceID    string
	OrganizationID string
	RequesterID    string
	TurnID         string
	AttemptID      string
	Attempts       int64
	StartedAt      *time.Time
	DeadlineAt     time.Time
}

// AccountingRecoveryResolution is the full monotonic aggregate recovered for
// one exact attempt.
type AccountingRecoveryResolution struct {
	WorkspaceID    string
	TurnID         string
	AttemptID      string
	Usage          map[string]any
	SettlementRef  string
	SettlementRefs []string
	Now            time.Time
}

type QueuedAttempt struct {
	WorkspaceID string
	TurnID      string
	AttemptID   string
	Status      string
}

type Store struct {
	db        coredb.DB
	runtimeDB *gorm.DB
}

func New(db coredb.DB) *Store { return &Store{db: db} }

// NewRuntime creates the same domain Store for the MeshX runtime database.
// GORM remains the runtime persistence implementation while coredb exposes the
// shared connection for the rest of the domain; there is still one Store owner.
func NewRuntime(db *gorm.DB) *Store {
	if db == nil {
		return &Store{}
	}
	sqlDB, err := db.DB()
	if err != nil {
		return &Store{runtimeDB: db}
	}
	return &Store{db: coredb.WrapSQLDB(sqlDB), runtimeDB: db}
}
