package cmd

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

	"github.com/spf13/cobra"
	appconfig "github.com/yourorg/devour/internal/config"
	"github.com/yourorg/devour/internal/search"
)

var queryCmd = &cobra.Command{
	Use:   "query <text>",
	Short: "Search indexed documentation",
	Long: `Search indexed documentation using semantic similarity.

Returns the most relevant document chunks based on vector similarity
to the query text.

Examples:
  devour query "how to authenticate"
  devour query "API rate limiting" --limit 10
  devour query "deployment" --format json`,
	Args: cobra.MinimumNArgs(1),
	RunE: runQuery,
}

var (
	queryLimit     int
	queryFormat    string
	queryThreshold float64
)

func init() {
	queryCmd.Flags().IntVarP(&queryLimit, "limit", "n", 5, "maximum number of results")
	queryCmd.Flags().StringVarP(&queryFormat, "format", "f", "text", "output format (text, json, markdown)")
	queryCmd.Flags().Float64Var(&queryThreshold, "threshold", 0, "minimum lexical score threshold")
}

func runQuery(cmd *cobra.Command, args []string) error {
	query := strings.TrimSpace(strings.Join(args, " "))
	if query == "" {
		return fmt.Errorf("query cannot be empty")
	}

	cfg, err := loadAppConfig()
	if err != nil {
		return err
	}

	engine := search.NewEngine(cfg)
	results, stats, err := engine.Search(context.Background(), query, search.SearchOptions{
		Limit:     queryLimit,
		Threshold: queryThreshold,
	})
	if err != nil {
		return fmt.Errorf("query failed: %w", err)
	}

	switch strings.ToLower(queryFormat) {
	case "json":
		resp := map[string]any{
			"query":      query,
			"limit":      queryLimit,
			"threshold":  queryThreshold,
			"count":      len(results),
			"results":    results,
			"indexed_at": stats.LastIndexedAt,
			"documents":  stats.Documents,
		}
		enc := json.NewEncoder(cmd.OutOrStdout())
		enc.SetIndent("", "  ")
		return enc.Encode(resp)
	case "markdown":
		return printQueryMarkdown(cmd, query, cfg, results, stats)
	case "text":
		return printQueryText(cmd, query, cfg, results, stats)
	default:
		return fmt.Errorf("unsupported format: %s (supported: text, json, markdown)", queryFormat)
	}
}

func printQueryText(cmd *cobra.Command, query string, cfg *appconfig.Config, results []search.Result, stats *search.IndexStats) error {
	fmt.Fprintf(cmd.OutOrStdout(), "Searching: %q\n", query)
	fmt.Fprintf(cmd.OutOrStdout(), "  Limit: %d\n", queryLimit)
	fmt.Fprintf(cmd.OutOrStdout(), "  Threshold: %.2f\n", queryThreshold)
	fmt.Fprintf(cmd.OutOrStdout(), "  Indexed docs: %d\n", stats.Documents)
	fmt.Fprintf(cmd.OutOrStdout(), "  Docs dir: %s\n\n", cfg.Storage.DocsDir)

	if len(results) == 0 {
		fmt.Fprintln(cmd.OutOrStdout(), "No results found.")
		return nil
	}

	fmt.Fprintln(cmd.OutOrStdout(), "Results:")
	fmt.Fprintln(cmd.OutOrStdout(), "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")
	for i, r := range results {
		fmt.Fprintf(cmd.OutOrStdout(), "%d. %s\n", i+1, r.Title)
		fmt.Fprintf(cmd.OutOrStdout(), "   Score: %.3f | Type: %s | Source: %s\n", r.Score, r.Type, defaultSource(r.Source))
		if r.URL != "" {
			fmt.Fprintf(cmd.OutOrStdout(), "   URL: %s\n", r.URL)
		}
		fmt.Fprintf(cmd.OutOrStdout(), "   Snippet: %s\n\n", r.Snippet)
	}
	return nil
}

func printQueryMarkdown(cmd *cobra.Command, query string, cfg *appconfig.Config, results []search.Result, stats *search.IndexStats) error {
	fmt.Fprintf(cmd.OutOrStdout(), "# Query Results\n\n")
	fmt.Fprintf(cmd.OutOrStdout(), "- Query: `%s`\n", query)
	fmt.Fprintf(cmd.OutOrStdout(), "- Limit: `%d`\n", queryLimit)
	fmt.Fprintf(cmd.OutOrStdout(), "- Threshold: `%.2f`\n", queryThreshold)
	fmt.Fprintf(cmd.OutOrStdout(), "- Indexed docs: `%d`\n", stats.Documents)
	fmt.Fprintf(cmd.OutOrStdout(), "- Docs dir: `%s`\n\n", cfg.Storage.DocsDir)

	if len(results) == 0 {
		fmt.Fprintln(cmd.OutOrStdout(), "_No results found._")
		return nil
	}

	for i, r := range results {
		fmt.Fprintf(cmd.OutOrStdout(), "## %d. %s\n\n", i+1, r.Title)
		fmt.Fprintf(cmd.OutOrStdout(), "- Score: `%.3f`\n", r.Score)
		fmt.Fprintf(cmd.OutOrStdout(), "- Type: `%s`\n", r.Type)
		fmt.Fprintf(cmd.OutOrStdout(), "- Source: `%s`\n", defaultSource(r.Source))
		if r.URL != "" {
			fmt.Fprintf(cmd.OutOrStdout(), "- URL: %s\n", r.URL)
		}
		fmt.Fprintf(cmd.OutOrStdout(), "\n%s\n\n", r.Snippet)
	}
	return nil
}

func defaultSource(source string) string {
	source = strings.TrimSpace(source)
	if source == "" {
		return "unknown"
	}
	return source
}
