// Package meshxruntime exposes MeshX as an embeddable HTTP runtime.
//
// The composition root stays in internal/resource/server; consumers only receive
// the narrow lifecycle surface required to mount it in another process.
package meshxruntime

import (
	"context"
	"fmt"
	"net/http"
	"strings"
	"sync"

	"github.com/tidbcloud/AgentTeam/internal/config"
	"github.com/tidbcloud/AgentTeam/internal/kbgovernance"
	"github.com/tidbcloud/AgentTeam/internal/resource/server"
	"github.com/tidbcloud/AgentTeam/internal/store/workspace"
)

// Runtime owns the embedded MeshX HTTP handler, workers, and storage handles.
type Runtime struct {
	server       *server.Server
	workersMu    sync.Mutex
	workersReady bool
}

// WorkerOwnership describes the enclosing AgentTeam process's workspace and global
// route ownership.
type WorkerOwnership struct {
	WorkspaceGroupID   string
	RequireGroup       bool
	StartGlobalWorkers bool
	WorkspaceScope     func(context.Context) ([]string, error)
}

// NewFromEnv validates MeshX configuration and constructs its handler without
// opening a listener or starting background workers.
func NewFromEnv() (*Runtime, error) {
	cfg, err := config.LoadResourceRuntimeFromEnv()
	if err != nil {
		return nil, err
	}
	return newRuntime(cfg)
}

// ConfigureWorkspaceAGSSeam binds the embedded outer seam to the enclosing
// Workspace Server's local placement authority. The target server admits only
// registered operations selected by AgentTeam's split activation overlay.
func (runtime *Runtime) ConfigureWorkspaceAGSSeam(groupID string, checker workspaceAGSWorkspaceChecker) error {
	if runtime == nil || runtime.server == nil {
		return fmt.Errorf("configure workspace AGS seam: runtime is not configured")
	}
	return runtime.server.ConfigureWorkspaceAGSSeam(groupID, checker)
}

// ConfigureStandaloneWorkspaceAGSSeam binds the canonical outer seam for an
// all-in-one deployment while retaining authoritative placement and repository
// binding checks.
func (runtime *Runtime) ConfigureStandaloneWorkspaceAGSSeam(resolver workspaceAGSWorkspaceResolver) error {
	if runtime == nil || runtime.server == nil {
		return fmt.Errorf("configure standalone workspace AGS seam: runtime is not configured")
	}
	return runtime.server.ConfigureStandaloneWorkspaceAGSSeam(resolver)
}

type workspaceAGSWorkspaceChecker interface {
	IsWorkspaceRoutableToGroup(context.Context, string, string) (bool, error)
}

type workspaceAGSWorkspaceResolver interface {
	ResolveWorkspaceRouteTarget(context.Context, string) (workspace.WorkspaceRouteTarget, error)
}

func newRuntime(cfg config.ResourceRuntimeConfig) (*Runtime, error) {
	cfg.Database.DisableAutoMigrate = true
	srv, err := server.New(cfg, server.Options{DeferBackgroundWorkers: true})
	if err != nil {
		return nil, err
	}
	return &Runtime{server: srv}, nil
}

// Handler returns the complete public MeshX and AGS HTTP surface.
func (runtime *Runtime) Handler() http.Handler {
	if runtime == nil || runtime.server == nil {
		return nil
	}
	return runtime.server.Handler()
}

// WikiGenerationAuthority returns the transport-neutral KB governance seam
// consumed by AgentTeam's generic Approval subject adapter.
func (runtime *Runtime) WikiGenerationAuthority() kbgovernance.WikiGenerationAuthority {
	if runtime == nil || runtime.server == nil {
		return nil
	}
	return runtime.server.WikiGenerationAuthority()
}

func (runtime *Runtime) KBGovernanceAuthority() kbgovernance.Authority {
	if runtime == nil || runtime.server == nil {
		return nil
	}
	return runtime.server.KBGovernanceAuthority()
}

// ConfigureWikiGenerationApprovalGateway injects AgentTeam's generic Approval
// bridge into the embedded KB service before Handler receives traffic.
func (runtime *Runtime) ConfigureWikiGenerationApprovalGateway(gateway kbgovernance.WikiGenerationApprovalGateway) error {
	if runtime == nil || runtime.server == nil {
		return fmt.Errorf("configure Wiki generation Approval gateway: runtime is not configured")
	}
	return runtime.server.ConfigureWikiGenerationApprovalGateway(gateway)
}

// ConfigureWikiGenerationTerminalGateway injects AgentTeam's requester
// notification bridge before embedded workers start.
func (runtime *Runtime) ConfigureWikiGenerationTerminalGateway(gateway kbgovernance.WikiGenerationTerminalGateway) error {
	if runtime == nil || runtime.server == nil {
		return fmt.Errorf("configure Wiki generation terminal gateway: runtime is not configured")
	}
	return runtime.server.ConfigureWikiGenerationTerminalGateway(gateway)
}

func (runtime *Runtime) ConfigurePublicationApprovalGateway(gateway kbgovernance.PublicationApprovalGateway) error {
	if runtime == nil || runtime.server == nil {
		return fmt.Errorf("configure publication Approval gateway: runtime is not configured")
	}
	return runtime.server.ConfigurePublicationApprovalGateway(gateway)
}

// StartWorkers starts embedded background workers exactly once.
//
// workspaceGroupID is required for workspace profile deployments so a future
// group-fenced worker implementation cannot silently fall back to global work.
func (runtime *Runtime) StartWorkers(ownership WorkerOwnership) error {
	if runtime == nil || runtime.server == nil {
		return fmt.Errorf("start embedded MeshX workers: runtime is not configured")
	}
	if ownership.RequireGroup && strings.TrimSpace(ownership.WorkspaceGroupID) == "" {
		return fmt.Errorf("start embedded MeshX workers: workspace group id is required")
	}
	if ownership.RequireGroup {
		if ownership.WorkspaceScope == nil {
			return fmt.Errorf("start embedded MeshX workers: workspace scope is required")
		}
	}
	runtime.workersMu.Lock()
	defer runtime.workersMu.Unlock()
	if runtime.workersReady {
		return nil
	}
	if err := runtime.server.StartBackgroundWorkers(server.WorkerOwnership{
		WorkspaceScope:    server.WorkspaceScope(ownership.WorkspaceScope),
		GlobalMaintenance: ownership.StartGlobalWorkers,
	}); err != nil {
		return err
	}
	runtime.workersReady = true
	return nil
}

// Ready reports whether all runtime dependencies and explicitly owned workers
// are ready to receive business traffic.
func (runtime *Runtime) Ready(ctx context.Context) error {
	if runtime == nil || runtime.Handler() == nil {
		return fmt.Errorf("embedded MeshX handler is not configured")
	}
	runtime.workersMu.Lock()
	defer runtime.workersMu.Unlock()
	if !runtime.workersReady {
		return fmt.Errorf("embedded MeshX workers are not started")
	}
	return runtime.server.Ready(ctx)
}

// QuiesceWorkers stops new background claims and drains active worker loops.
func (runtime *Runtime) QuiesceWorkers(ctx context.Context) error {
	if runtime == nil || runtime.server == nil {
		return nil
	}
	return runtime.server.QuiesceBackgroundWorkers(ctx)
}

// Shutdown drains workers and closes all MeshX, AGS, and AgentTeam-core verifier
// database handles. It does not own the enclosing AgentTeam HTTP server.
func (runtime *Runtime) Shutdown(ctx context.Context) error {
	if runtime == nil || runtime.server == nil {
		return nil
	}
	return runtime.server.Shutdown(ctx)
}
