// Package operator provides an abstraction layer for CLI operations.
// It auto-detects whether the daemon is running and uses the appropriate backend:
//   - FileOperator: reads YAML files directly (daemon not running)
//   - APIOperator: calls daemon HTTP API (daemon running)
//
// CLI commands use the Operator interface without knowing which backend is active.
package operator

import (
	"fmt"

	"github.com/tidbcloud/AgentTeam/desktop/internal/agentview"
	"github.com/tidbcloud/AgentTeam/desktop/internal/daemon"
	"github.com/tidbcloud/AgentTeam/desktop/internal/profile"
	"github.com/tidbcloud/AgentTeam/desktop/internal/token"
)

var (
	daemonStatus          = daemon.NewStatus
	generateCLIControlKey = func() (string, error) {
		return token.Default().GenerateTempKey()
	}
)

// Operator provides access to per-resource-type sub-operators.
// This mirrors the existing profile.Manager accessor pattern.
type Operator interface {
	// Agents returns the agent configuration operator.
	Agents() AgentOperator
	// Servers returns the AgentTeam server auth configuration operator.
	Servers() ServerOperator
	// Skills returns the skill configuration/import operator.
	Skills() SkillOperator
}

// ---------------------------------------------------------------------------
// AgentOperator
// ---------------------------------------------------------------------------

// AgentReader is the read-only CLI surface for canonical Agent snapshots.
// Keeping the runtime projection intact lets commands expose live status without
// mixing ephemeral session state into persisted Agent configuration.
type AgentReader interface {
	Get(id string) (agentview.Snapshot, bool, error)
	All() ([]agentview.Snapshot, error)
}

// AgentOperator is the CLI-facing agent operation surface.
type AgentOperator interface {
	AgentReader
}

// ---------------------------------------------------------------------------
// ServerOperator
// ---------------------------------------------------------------------------

// ServerReader is the read-only CLI surface for AgentTeam server auth configurations.
type ServerReader interface {
	Get(id string) (profile.AgentTeamServer, bool, error)
	All() ([]profile.AgentTeamServer, error)
}

// ServerWriter mutates AgentTeam server auth configurations through either the
// daemon API or direct profile files.
type ServerWriter interface {
	Add(server *profile.AgentTeamServer) (profile.AgentTeamServer, error)
	Update(server profile.AgentTeamServer) (profile.AgentTeamServer, error)
	Delete(id string) error
}

// ServerEnabler toggles whether a saved AgentTeam server auth entry is active
// without editing the rest of the record.
type ServerEnabler interface {
	SetEnabled(id string, enabled bool) error
}

// ServerOperator is the CLI-facing AgentTeam server auth operation surface.
type ServerOperator interface {
	ServerReader
	ServerWriter
	ServerEnabler
}

// ---------------------------------------------------------------------------
// SkillOperator
// ---------------------------------------------------------------------------

// SkillReader is the read-only CLI surface for skill configurations.
type SkillReader interface {
	Get(id string) (profile.Skill, bool, error)
	All() ([]profile.Skill, error)
}

// SkillWriter mutates stored skill metadata and content references.
type SkillWriter interface {
	Add(s profile.Skill) (profile.Skill, error)
	Update(s profile.Skill) (profile.Skill, error)
	Delete(id string) error
}

// SkillImporter imports skills from local files, remote files, or archives.
type SkillImporter interface {
	ImportFromFile(filePath string, meta *profile.SkillMeta, force bool) (profile.Skill, bool, error)
	ImportFromURL(rawURL string, meta *profile.SkillMeta, force bool) (profile.Skill, bool, error)
	ImportAutoFromFile(filePath string, meta *profile.SkillMeta, force bool) (*profile.AutoImportResult, error)
	ImportAutoFromURL(rawURL string, meta *profile.SkillMeta, force bool) (*profile.AutoImportResult, error)
}

// SkillOperator is the CLI-facing skill operation surface.
type SkillOperator interface {
	SkillReader
	SkillWriter
	SkillImporter
}

// ---------------------------------------------------------------------------
// Factory
// ---------------------------------------------------------------------------

// New creates the appropriate Operator based on daemon status.
// If the daemon is running, it returns an APIOperator that communicates
// with the daemon's REST API. Otherwise, it returns a FileOperator
// that directly manipulates YAML files.
func New() (Operator, error) {
	status := daemonStatus()
	if !status.Running {
		return newFileOperator(), nil
	}
	if !status.Healthy {
		return nil, fmt.Errorf(
			"agentteam daemon is running but unavailable (PID: %d); refusing direct profile mutation",
			status.PID,
		)
	}

	apiKey, err := generateCLIControlKey()
	if err != nil {
		return nil, fmt.Errorf("generate local CLI control credential: %w", err)
	}

	return newAPIOperator(status.BaseURL, apiKey), nil
}

// NewAPIOperator creates an APIOperator with the given base URL and API key.
// This is intended for testing purposes.
func NewAPIOperator(baseURL, apiKey string) Operator {
	return newAPIOperator(baseURL, apiKey)
}
