package agentpool

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/mudler/LocalAGI/core/agent"
	"github.com/mudler/LocalAGI/core/sse"
	"github.com/mudler/LocalAGI/core/state"
	agiServices "github.com/mudler/LocalAGI/services"
	"github.com/mudler/LocalAI/core/services/agents"
)

// localAgentConfigBackend wraps the in-memory LocalAGI AgentPool for standalone mode.
type localAgentConfigBackend struct {
	svc *AgentPoolService // back-reference for shared fields (pool, configMeta, outputsDir, etc.)
}

func newLocalAgentConfigBackend(svc *AgentPoolService) *localAgentConfigBackend {
	return &localAgentConfigBackend{svc: svc}
}

func (b *localAgentConfigBackend) ListAgents(userID string) map[string]bool {
	statuses := map[string]bool{}
	agents := b.svc.localAGI.pool.List()
	prefix := ""
	if userID != "" {
		prefix = userID + ":"
	}
	for _, a := range agents {
		if userID != "" && !strings.HasPrefix(a, prefix) {
			continue
		}
		ag := b.svc.localAGI.pool.GetAgent(a)
		if ag == nil {
			continue
		}
		displayName := a
		if prefix != "" {
			displayName = strings.TrimPrefix(a, prefix)
		}
		statuses[displayName] = !ag.Paused()
	}
	return statuses
}

func (b *localAgentConfigBackend) GetConfig(userID, name string) *state.AgentConfig {
	cfg := b.svc.localAGI.pool.GetConfig(agents.AgentKey(userID, name))
	if cfg == nil {
		return nil
	}
	// Return a copy with the original name (strip userID: prefix)
	result := *cfg
	result.Name = name
	return &result
}

func (b *localAgentConfigBackend) SaveConfig(userID string, cfg *state.AgentConfig) error {
	key := agents.AgentKey(userID, cfg.Name)
	cfg.Name = key
	return b.svc.localAGI.pool.CreateAgent(key, cfg)
}

func (b *localAgentConfigBackend) UpdateConfig(userID, name string, cfg *state.AgentConfig) error {
	key := agents.AgentKey(userID, name)
	if old := b.svc.localAGI.pool.GetConfig(key); old == nil {
		return fmt.Errorf("%w: %s", ErrAgentNotFound, name)
	}
	cfg.Name = key
	return b.svc.localAGI.pool.RecreateAgent(key, cfg)
}

func (b *localAgentConfigBackend) DeleteConfig(userID, name string) error {
	return b.svc.localAGI.pool.Remove(agents.AgentKey(userID, name))
}

func (b *localAgentConfigBackend) ImportConfig(userID string, cfg *state.AgentConfig) error {
	key := agents.AgentKey(userID, cfg.Name)
	cfg.Name = key
	return b.svc.localAGI.pool.CreateAgent(key, cfg)
}

func (b *localAgentConfigBackend) ExportConfig(userID, name string) ([]byte, error) {
	cfg := b.svc.localAGI.pool.GetConfig(agents.AgentKey(userID, name))
	if cfg == nil {
		return nil, fmt.Errorf("%w: %s", ErrAgentNotFound, name)
	}
	return json.MarshalIndent(cfg, "", "  ")
}

func (b *localAgentConfigBackend) SetStatus(userID, name, status string) error {
	ag := b.svc.localAGI.pool.GetAgent(agents.AgentKey(userID, name))
	if ag == nil {
		return fmt.Errorf("%w: %s", ErrAgentNotFound, name)
	}
	switch status {
	case "paused":
		ag.Pause()
	case "active":
		ag.Resume()
	default:
		return fmt.Errorf("unknown status: %s", status)
	}
	return nil
}

func (b *localAgentConfigBackend) GetAgent(userID, name string) *agent.Agent {
	return b.svc.localAGI.pool.GetAgent(agents.AgentKey(userID, name))
}

func (b *localAgentConfigBackend) GetSSEManager(userID, name string) sse.Manager {
	return b.svc.localAGI.pool.GetManager(agents.AgentKey(userID, name))
}

func (b *localAgentConfigBackend) GetStatus(userID, name string) *state.Status {
	return b.svc.localAGI.pool.GetStatusHistory(agents.AgentKey(userID, name))
}

func (b *localAgentConfigBackend) GetObservables(userID, name string) ([]json.RawMessage, error) {
	ag := b.svc.localAGI.pool.GetAgent(agents.AgentKey(userID, name))
	if ag == nil {
		return nil, fmt.Errorf("%w: %s", ErrAgentNotFound, name)
	}
	history := ag.Observer().History()
	result := make([]json.RawMessage, 0, len(history))
	for _, obs := range history {
		data, err := json.Marshal(obs)
		if err != nil {
			continue
		}
		result = append(result, data)
	}
	return result, nil
}

func (b *localAgentConfigBackend) ClearObservables(userID, name string) error {
	ag := b.svc.localAGI.pool.GetAgent(agents.AgentKey(userID, name))
	if ag == nil {
		return fmt.Errorf("%w: %s", ErrAgentNotFound, name)
	}
	ag.Observer().ClearHistory()
	return nil
}

func (b *localAgentConfigBackend) ListAllGrouped() map[string][]UserAgentInfo {
	result := map[string][]UserAgentInfo{}
	agents := b.svc.localAGI.pool.List()
	for _, a := range agents {
		ag := b.svc.localAGI.pool.GetAgent(a)
		if ag == nil {
			continue
		}
		userID := ""
		name := a
		if u, n, ok := strings.Cut(a, ":"); ok {
			userID = u
			name = n
		}
		result[userID] = append(result[userID], UserAgentInfo{
			Name:   name,
			Active: !ag.Paused(),
		})
	}
	return result
}

func (b *localAgentConfigBackend) GetConfigMeta() AgentConfigMetaResult {
	meta := b.svc.localAGI.configMeta
	return AgentConfigMetaResult{
		Fields:     meta.Fields,
		Actions:    meta.Actions,
		Connectors: meta.Connectors,
		Filters:    meta.Filters,
		OutputsDir: b.svc.outputsDir,
	}
}

func (b *localAgentConfigBackend) ListAvailableActions() []string {
	return agiServices.AvailableActions
}

func (b *localAgentConfigBackend) Chat(userID, name, message string) (string, error) {
	return b.svc.Chat(agents.AgentKey(userID, name), message)
}

func (b *localAgentConfigBackend) Stop() {
	if b.svc.localAGI.pool != nil {
		b.svc.localAGI.pool.StopAll()
	}
}
