package memory

import (
	"context"
	"fmt"
)

// Service memory service manager
type Service struct {
	client  *Client
	project string
}

// NewService creates memory service manager
func NewService(baseURL, token, project string) *Service {
	return &Service{
		client:  NewClient(baseURL, token),
		project: project,
	}
}

// KnowledgeRecord high-level knowledge record
type KnowledgeRecord struct {
	ID       string
	Level    string // L1|L2|reference
	Title    string
	Content  string
	Source   string
	Metadata map[string]interface{}
	SHA256   string
}

// CreateKnowledge creates knowledge record
func (s *Service) CreateKnowledge(ctx context.Context, record *KnowledgeRecord) (string, error) {
	if record.Level == "" {
		record.Level = "L1"
	}
	if record.Source == "" {
		record.Source = "workflow"
	}

	req := &IngestRequest{
		Project:  s.project,
		Source:   record.Source,
		Kind:     record.Level,
		Text:     record.Content,
		Metadata: record.Metadata,
	}

	resp, err := s.client.Ingest(ctx, req)
	if err != nil {
		return "", fmt.Errorf("create knowledge: %w", err)
	}

	return resp.ID, nil
}

// UpdateKnowledge updates existing knowledge (re-ingest)
func (s *Service) UpdateKnowledge(ctx context.Context, record *KnowledgeRecord) (string, error) {
	// Update done by re-ingesting with same signature/source
	// Memory service deduplicates based on idempotency key
	if record.Metadata == nil {
		record.Metadata = make(map[string]interface{})
	}

	// Use ID as session_id for idempotency
	record.Metadata["session_id"] = record.ID

	return s.CreateKnowledge(ctx, record)
}

// RetrievalOptions search options
type RetrievalOptions struct {
	LevelFilter []string // L1, L2, R
	Floor       float32  // minimum relevance
	Limit       int      // default 10
	Scope       string   // learned|reference|all
}

// RetrieveKnowledge searches knowledge
func (s *Service) RetrieveKnowledge(ctx context.Context, query string, opts *RetrievalOptions) ([]KnowledgeRecord, error) {
	if opts == nil {
		opts = &RetrievalOptions{}
	}

	if opts.Limit == 0 {
		opts.Limit = 10
	}

	req := &QueryRequest{
		Project:     s.project,
		Query:       query,
		LevelFilter: opts.LevelFilter,
		Floor:       opts.Floor,
		Limit:       opts.Limit,
		Scope:       opts.Scope,
	}

	resp, err := s.client.Query(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("retrieve knowledge: %w", err)
	}

	records := make([]KnowledgeRecord, len(resp.Results))
	for i, r := range resp.Results {
		records[i] = KnowledgeRecord{
			ID:       r.ID,
			Level:    r.Level,
			Content:  r.Text,
			Source:   r.Source,
			SHA256:   "", // Not in response
			Metadata: map[string]interface{}{
				"score":           r.Score,
				"semantic_score":  r.SemanticScore,
				"lexical_score":   r.LexicalScore,
				"breadcrumb":      r.Breadcrumb,
			},
		}
	}

	return records, nil
}

// ServiceContext tool/task context
type ServiceContext struct {
	Tier      int
	Lessons   []Lesson
	Skills    []Skill
	BudgetUsed int
	BudgetMax int
}

// Lesson learned fact or reference
type Lesson struct {
	Tier        int
	Level       string
	Score       float32
	Text        string
	MatchedKind string
	SeenCount   int
	LastSeen    string
}

// Skill recommended action
type Skill struct {
	Name string
	Why  string
}

// RetrieveContext retrieves context for tool/task (three-tier)
func (s *Service) RetrieveContext(ctx context.Context, tool, task string, budget int) (*ServiceContext, error) {
	if budget == 0 {
		budget = 8192
	}

	req := &ContextRequest{
		Project:         s.project,
		Tool:            tool,
		Task:            task,
		SignatureSource: fmt.Sprintf("%s:%s", tool, task),
		Scope:           "tool_context",
		Budget:          budget,
	}

	resp, err := s.client.Context(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("retrieve context: %w", err)
	}

	lessons := make([]Lesson, len(resp.Lessons))
	for i, l := range resp.Lessons {
		lessons[i] = Lesson{
			Tier:        l.Tier,
			Level:       l.Level,
			Score:       l.Score,
			Text:        l.Text,
			MatchedKind: l.MatchedKind,
			SeenCount:   l.SeenCount,
			LastSeen:    l.LastSeen,
		}
	}

	skills := make([]Skill, len(resp.Skills))
	for i, sk := range resp.Skills {
		skills[i] = Skill{
			Name: sk.Name,
			Why:  sk.Why,
		}
	}

	return &ServiceContext{
		Tier:       resp.Tier,
		Lessons:    lessons,
		Skills:     skills,
		BudgetUsed: resp.Budget.Used,
		BudgetMax:  resp.Budget.Requested,
	}, nil
}

// VaultInfo vault browsing
type VaultInfo struct {
	Path        string
	Title       string
	Level       string
	UpdatedAt   string
	RecordCount int
}

// GetVault lists vault files
func (s *Service) GetVault(ctx context.Context) ([]VaultInfo, error) {
	resp, err := s.client.Vault(ctx, s.project)
	if err != nil {
		return nil, fmt.Errorf("get vault: %w", err)
	}

	files := make([]VaultInfo, len(resp.Files))
	for i, f := range resp.Files {
		files[i] = VaultInfo{
			Path:        f.Path,
			Title:       f.Title,
			Level:       f.Level,
			UpdatedAt:   f.UpdatedAt,
			RecordCount: f.RecordCount,
		}
	}

	return files, nil
}

// IsHealthy checks service health
func (s *Service) IsHealthy(ctx context.Context) bool {
	ok, err := s.client.Health(ctx)
	return ok && err == nil
}
