import type { RegistryServer } from './types.js';

const WEIGHT_RELEVANCE = 0.4;
const WEIGHT_POPULARITY = 0.3;
const WEIGHT_VERIFIED = 0.2;
const WEIGHT_RECENCY = 0.1;

function textRelevance(server: RegistryServer, query: string): number {
  const q = query.toLowerCase();
  const name = server.name.toLowerCase();
  const desc = server.description.toLowerCase();

  // Exact name match
  if (name === q) return 1.0;
  // Name starts with query
  if (name.startsWith(q)) return 0.9;
  // Name contains query
  if (name.includes(q)) return 0.7;
  // Description contains query
  if (desc.includes(q)) return 0.4;

  // Word-level matching
  const queryWords = q.split(/\s+/);
  const matchCount = queryWords.filter(
    (w) => name.includes(w) || desc.includes(w),
  ).length;
  return queryWords.length > 0 ? (matchCount / queryWords.length) * 0.3 : 0;
}

function popularityScore(server: RegistryServer): number {
  // Normalize to 0-1 range; use log scale since popularity can vary hugely
  if (server.popularityScore <= 0) return 0;
  // Log scale: log10(1) = 0, log10(10000) ≈ 4 → normalize to 0-1 with cap at 100k
  return Math.min(Math.log10(server.popularityScore + 1) / 5, 1.0);
}

function verifiedScore(server: RegistryServer): number {
  return server.verified ? 1.0 : 0;
}

function recencyScore(server: RegistryServer): number {
  if (server.lastUpdated === undefined) return 0.5; // Unknown = middle score
  const ageMs = Date.now() - server.lastUpdated.getTime();
  const ageDays = ageMs / (1000 * 60 * 60 * 24);
  // Less than 30 days = 1.0, decays to 0 at 365 days
  return Math.max(0, 1 - ageDays / 365);
}

function computeScore(server: RegistryServer, query: string): number {
  return (
    WEIGHT_RELEVANCE * textRelevance(server, query) +
    WEIGHT_POPULARITY * popularityScore(server) +
    WEIGHT_VERIFIED * verifiedScore(server) +
    WEIGHT_RECENCY * recencyScore(server)
  );
}

export function rankResults(
  results: RegistryServer[],
  query: string,
): RegistryServer[] {
  return [...results].sort((a, b) => computeScore(b, query) - computeScore(a, query));
}
