import { search } from "@/lib/search";
import { parseSearchBody, parseSearchParams } from "@/lib/search-utils";
import type { ParsedSearchInput, SearchError, ScoredProduct } from "@/types/search";

/**
 * GET  /api/search?q=wireless+headphones&category=Electronics&sort=price-asc
 * POST /api/search  { "query": "...", "filters": {...}, "sort": "...", "limit": 24 }
 *
 * Returns ranked products. The raw embedding vectors are never serialised —
 * only the derived similarity score, which is what the client actually needs.
 */

/** Expose only the fields the client renders, plus the ranking signals. */
function toResult(entry: ScoredProduct) {
  return {
    id: entry.product.id,
    name: entry.product.name,
    description: entry.product.description,
    category: entry.product.category,
    subcategory: entry.product.subcategory,
    price: entry.product.price,
    brand: entry.product.brand,
    rating: entry.product.rating,
    stock: entry.product.stock,
    image: entry.product.image,
    tags: entry.product.tags,
    score: Number(entry.score.toFixed(4)),
    similarity: Number(entry.similarity.toFixed(4)),
    keywordScore: Number(entry.keywordScore.toFixed(4)),
    priceScore: Number(entry.priceScore.toFixed(4)),
    matchedTerms: entry.matchedTerms,
  };
}

function badRequest(errors: Record<string, string[]>): Response {
  const body: SearchError = {
    error: {
      code: "INVALID_INPUT",
      message: "One or more search parameters are invalid.",
      details: errors,
    },
  };
  return Response.json(body, { status: 400 });
}

function serverError(error: unknown): Response {
  console.error("[api/search] search failed:", error);
  const body: SearchError = {
    error: {
      code: "SEARCH_FAILED",
      message: "The search index could not be loaded.",
    },
  };
  return Response.json(body, { status: 500 });
}

async function respond(input: ParsedSearchInput): Promise<Response> {
  try {
    const { response } = await search(input);
    return Response.json(
      {
        query: response.meta.query,
        count: response.results.length,
        results: response.results.map(toResult),
        suggestions: response.suggestions,
        meta: {
          total: response.meta.total,
          returned: response.meta.returned,
          took: response.meta.took,
          provider: response.meta.provider,
          providerFallback: response.meta.providerFallback,
          sort: response.meta.sort,
          weights: response.meta.weights,
          priceIntent: response.meta.priceIntent,
        },
      },
      {
        // Search results are per-query; the client revalidates on every keystroke.
        headers: { "cache-control": "no-store" },
      },
    );
  } catch (error) {
    return serverError(error);
  }
}

export async function GET(request: Request): Promise<Response> {
  const { searchParams } = new URL(request.url);
  const parsed = parseSearchParams(searchParams);
  if (!parsed.ok) return badRequest(parsed.errors);
  return respond(parsed.value);
}

export async function POST(request: Request): Promise<Response> {
  let body: unknown;
  try {
    body = await request.json();
  } catch {
    const failure: SearchError = {
      error: { code: "INVALID_JSON", message: "Request body must be valid JSON." },
    };
    return Response.json(failure, { status: 400 });
  }

  const parsed = parseSearchBody(body);
  if (!parsed.ok) return badRequest(parsed.errors);
  return respond(parsed.value);
}
