package action

import (
	"context"
	"fmt"
	"os"

	"github.com/rockliang/poimen/workflows/internal/memory"
)

// RetrieveMemoryInput input for RetrieveMemoryActivity
type RetrieveMemoryInput struct {
	// Query semantic search query
	Query string `json:"query"`

	// Project memory project (default: "poimen")
	Project string `json:"project,omitempty"`

	// Scope retrieval scope: "skills", "lessons", "all" (default: "all")
	Scope string `json:"scope,omitempty"`

	// Limit max results (default: 10)
	Limit int `json:"limit,omitempty"`

	// LevelFilter filter by level: L1, L2, R (reference)
	LevelFilter []string `json:"levelFilter,omitempty"`

	// Tool tool context for skill matching
	Tool string `json:"tool,omitempty"`

	// Task task description for context retrieval
	Task string `json:"task,omitempty"`
}

// RetrieveMemoryOutput output from RetrieveMemoryActivity
type RetrieveMemoryOutput struct {
	// Skills relevant skills found
	Skills []MemorySkill `json:"skills"`

	// Lessons relevant lessons/knowledge found
	Lessons []MemoryLesson `json:"lessons"`

	// References reference documents found
	References []MemoryReference `json:"references"`

	// TotalResults total results found
	TotalResults int `json:"totalResults"`

	// Budget token budget info
	Budget MemoryBudget `json:"budget"`
}

// MemorySkill skill from memory
type MemorySkill struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Why         string `json:"why,omitempty"`
}

// MemoryLesson lesson from memory
type MemoryLesson struct {
	ID         string  `json:"id"`
	Text       string  `json:"text"`
	Level      string  `json:"level"`
	Score      float32 `json:"score"`
	Breadcrumb string  `json:"breadcrumb,omitempty"`
}

// MemoryReference reference document from memory
type MemoryReference struct {
	ID         string  `json:"id"`
	Text       string  `json:"text"`
	Score      float32 `json:"score"`
	Breadcrumb string  `json:"breadcrumb,omitempty"`
}

// MemoryBudget token budget tracking
type MemoryBudget struct {
	Requested int `json:"requested"`
	Used      int `json:"used"`
}

// RetrieveMemoryActivity retrieves relevant knowledge from poimen-memory
func RetrieveMemoryActivity(ctx context.Context, in RetrieveMemoryInput) (RetrieveMemoryOutput, error) {
	logger := newActivityLogger(ctx)
	logger.Info("RetrieveMemoryActivity started", "query", in.Query, "scope", in.Scope)

	output := RetrieveMemoryOutput{
		Skills:     []MemorySkill{},
		Lessons:    []MemoryLesson{},
		References: []MemoryReference{},
	}

	// Get memory service URL and token
	baseURL := os.Getenv("POIMEN_MEMORY_URL")
	if baseURL == "" {
		baseURL = "http://poimen-memory.poimen.svc.cluster.local:8080"
	}

	token := os.Getenv("POIMEN_MEMORY_TOKEN")
	// Token optional for internal cluster access

	// Set defaults
	project := in.Project
	if project == "" {
		project = "poimen"
	}

	scope := in.Scope
	if scope == "" {
		scope = "all"
	}

	limit := in.Limit
	if limit == 0 {
		limit = 10
	}

	client := memory.NewClient(baseURL, token)

	// If tool/task provided, use Context API for skill matching
	if in.Tool != "" || in.Task != "" {
		contextResp, err := client.Context(ctx, &memory.ContextRequest{
			Project:         project,
			Tool:            in.Tool,
			Task:            in.Task,
			SignatureSource: in.Query,
			Scope:           "tool_context",
			Budget:          8192,
		})
		if err != nil {
			logger.Warn("Context retrieval failed, falling back to query", "error", err)
		} else {
			// Extract skills
			for _, skill := range contextResp.Skills {
				output.Skills = append(output.Skills, MemorySkill{
					Name: skill.Name,
					Why:  skill.Why,
				})
			}

			// Extract lessons
			for i, lesson := range contextResp.Lessons {
				output.Lessons = append(output.Lessons, MemoryLesson{
					ID:         fmt.Sprintf("ctx-%d", i),
					Text:       lesson.Text,
					Level:      lesson.Level,
					Score:      lesson.Score,
					Breadcrumb: "",
				})
			}

			output.Budget = MemoryBudget{
				Requested: contextResp.Budget.Requested,
				Used:      contextResp.Budget.Used,
			}
			output.TotalResults = len(output.Skills) + len(output.Lessons)
		}
	}

	// Also do semantic query for additional context
	if scope == "all" || scope == "lessons" || scope == "references" {
		levelFilter := in.LevelFilter
		if len(levelFilter) == 0 {
			levelFilter = []string{"L1", "L2"}
		}

		queryResp, err := client.Query(ctx, &memory.QueryRequest{
			Project:     project,
			Query:       in.Query,
			LevelFilter: levelFilter,
			Limit:       limit,
			Scope:       "all",
		})
		if err != nil {
			logger.Warn("Query failed", "error", err)
		} else {
			for _, result := range queryResp.Results {
				if result.Level == "R" {
					output.References = append(output.References, MemoryReference{
						ID:         result.ID,
						Text:       result.Text,
						Score:      result.Score,
						Breadcrumb: result.Breadcrumb,
					})
				} else {
					// Avoid duplicates from Context call
					found := false
					for _, existing := range output.Lessons {
						if existing.ID == result.ID {
							found = true
							break
						}
					}
					if !found {
						output.Lessons = append(output.Lessons, MemoryLesson{
							ID:         result.ID,
							Text:       result.Text,
							Level:      result.Level,
							Score:      result.Score,
							Breadcrumb: result.Breadcrumb,
						})
					}
				}
			}
			output.TotalResults = len(output.Skills) + len(output.Lessons) + len(output.References)
		}
	}

	logger.Info("RetrieveMemoryActivity completed",
		"skills", len(output.Skills),
		"lessons", len(output.Lessons),
		"references", len(output.References))

	return output, nil
}

// FormatMemoryForPrompt formats memory output for LLM prompt injection
func FormatMemoryForPrompt(mem RetrieveMemoryOutput) string {
	if mem.TotalResults == 0 {
		return ""
	}

	var result string

	if len(mem.Skills) > 0 {
		result += "\n## Relevant Skills\n"
		for _, skill := range mem.Skills {
			result += fmt.Sprintf("- **%s**: %s\n", skill.Name, skill.Why)
		}
	}

	if len(mem.Lessons) > 0 {
		result += "\n## Relevant Knowledge\n"
		for _, lesson := range mem.Lessons {
			result += fmt.Sprintf("- [%s] %s\n", lesson.Level, truncate(lesson.Text, 200))
		}
	}

	if len(mem.References) > 0 {
		result += "\n## Reference Documents\n"
		for _, ref := range mem.References {
			result += fmt.Sprintf("- %s\n", truncate(ref.Text, 200))
		}
	}

	return result
}

func truncate(s string, maxLen int) string {
	if len(s) <= maxLen {
		return s
	}
	return s[:maxLen] + "..."
}
