package rest

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"time"
)

func (s *Server) queryAIRoutes(ctx context.Context, query string) ([]map[string]any, string) {
	baseURL := strings.TrimSpace(firstNonEmptyEnv(
		"TOKEN_AGGREGATION_API_BASE",
		"TOKEN_AGGREGATION_URL",
		"TOKEN_AGGREGATION_BASE_URL",
	))
	if baseURL == "" {
		return nil, "token aggregation api base url is not configured for ai route retrieval"
	}

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, strings.TrimRight(baseURL, "/")+"/api/v1/routes/ingestion?fromChainId=138", nil)
	if err != nil {
		return nil, "unable to build token aggregation ai request"
	}

	client := &http.Client{Timeout: 6 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return nil, "token aggregation live routes unavailable: " + err.Error()
	}
	defer resp.Body.Close()

	if resp.StatusCode >= 400 {
		return nil, fmt.Sprintf("token aggregation live routes returned %d", resp.StatusCode)
	}

	var payload struct {
		Routes []map[string]any `json:"routes"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
		return nil, "unable to decode token aggregation live routes"
	}
	if len(payload.Routes) == 0 {
		return nil, "token aggregation returned no live routes"
	}

	matches := filterAIRouteMatches(payload.Routes, query)
	return matches, ""
}

func filterAIRouteMatches(routes []map[string]any, query string) []map[string]any {
	query = strings.ToLower(strings.TrimSpace(query))
	matches := make([]map[string]any, 0, 6)
	for _, route := range routes {
		if query != "" && !routeMatchesQuery(route, query) {
			continue
		}
		trimmed := map[string]any{
			"routeId":            route["routeId"],
			"status":             route["status"],
			"routeType":          route["routeType"],
			"fromChainId":        route["fromChainId"],
			"toChainId":          route["toChainId"],
			"tokenInSymbol":      route["tokenInSymbol"],
			"tokenOutSymbol":     route["tokenOutSymbol"],
			"assetSymbol":        route["assetSymbol"],
			"label":              route["label"],
			"aggregatorFamilies": route["aggregatorFamilies"],
			"hopCount":           route["hopCount"],
			"bridgeType":         route["bridgeType"],
			"tags":               route["tags"],
		}
		matches = append(matches, compactAnyMap(trimmed))
		if len(matches) >= 6 {
			break
		}
	}
	if len(matches) == 0 {
		for _, route := range routes {
			trimmed := map[string]any{
				"routeId":            route["routeId"],
				"status":             route["status"],
				"routeType":          route["routeType"],
				"fromChainId":        route["fromChainId"],
				"toChainId":          route["toChainId"],
				"tokenInSymbol":      route["tokenInSymbol"],
				"tokenOutSymbol":     route["tokenOutSymbol"],
				"assetSymbol":        route["assetSymbol"],
				"label":              route["label"],
				"aggregatorFamilies": route["aggregatorFamilies"],
			}
			matches = append(matches, compactAnyMap(trimmed))
			if len(matches) >= 4 {
				break
			}
		}
	}
	return matches
}

func normalizeHexString(value string) string {
	trimmed := strings.TrimSpace(strings.ToLower(value))
	return strings.TrimPrefix(trimmed, "0x")
}

func routeMatchesQuery(route map[string]any, query string) bool {
	fields := []string{
		stringValue(route["routeId"]),
		stringValue(route["routeType"]),
		stringValue(route["tokenInSymbol"]),
		stringValue(route["tokenOutSymbol"]),
		stringValue(route["assetSymbol"]),
		stringValue(route["label"]),
	}
	for _, field := range fields {
		if strings.Contains(strings.ToLower(field), query) {
			return true
		}
	}
	for _, value := range stringSliceValue(route["aggregatorFamilies"]) {
		if strings.Contains(strings.ToLower(value), query) {
			return true
		}
	}
	for _, value := range stringSliceValue(route["tags"]) {
		if strings.Contains(strings.ToLower(value), query) {
			return true
		}
	}
	for _, symbol := range []string{"cusdt", "cusdc", "cxauc", "ceurt", "usdt", "usdc", "weth"} {
		if strings.Contains(query, symbol) {
			if strings.Contains(strings.ToLower(strings.Join(fields, " ")), symbol) {
				return true
			}
		}
	}
	return false
}
