import type { SellerLead, Buyer, MatchResult } from "@/types";

const WEIGHTS = {
  assetType: 0.35,
  location: 0.25,
  price: 0.25,
  capRate: 0.15,
};

/**
 * Calculate match score between a seller lead and a buyer
 * Returns a score from 0-100
 */
export function calculateMatchScore(
  lead: SellerLead,
  buyer: Buyer
): { score: number; breakdown: MatchResult["breakdown"] } {
  const assetTypeScore = scoreAssetType(lead.asset_type, buyer.asset_types);
  const locationScore = scoreLocation(lead.market, buyer.target_locations);
  const priceScore = scorePrice(lead.asking_price, buyer.price_min, buyer.price_max);
  const capRateScore = scoreCapRate(lead.cap_rate, buyer.cap_rate_min, buyer.cap_rate_max);

  const totalScore =
    assetTypeScore * WEIGHTS.assetType +
    locationScore * WEIGHTS.location +
    priceScore * WEIGHTS.price +
    capRateScore * WEIGHTS.capRate;

  return {
    score: Math.round(totalScore * 100) / 100,
    breakdown: {
      assetTypeScore,
      locationScore,
      priceScore,
      capRateScore,
    },
  };
}

/**
 * Score asset type match (0-100)
 * Exact match = 100, related type = 50, no match = 0
 */
function scoreAssetType(leadType: string, buyerTypes: string[]): number {
  if (!buyerTypes || buyerTypes.length === 0) return 50; // No preference = neutral

  if (buyerTypes.includes(leadType)) return 100;

  // Related type scoring
  const relatedTypes: Record<string, string[]> = {
    Office: ["Mixed-Use"],
    Industrial: ["Land"],
    Retail: ["Mixed-Use"],
    Multifamily: ["Mixed-Use"],
    "Mixed-Use": ["Office", "Retail", "Multifamily"],
    Land: ["Industrial"],
    Hospitality: ["Mixed-Use"],
    Other: [],
  };

  const related = relatedTypes[leadType] || [];
  if (buyerTypes.some((t) => related.includes(t))) return 50;

  return 0;
}

/**
 * Score location match (0-100)
 * Exact market match = 100, same state = 60, no match = 0
 */
function scoreLocation(leadMarket: string, buyerLocations: string[]): number {
  if (!buyerLocations || buyerLocations.length === 0) return 50;

  // Exact market match
  if (buyerLocations.some((loc) => loc.toLowerCase() === leadMarket.toLowerCase())) return 100;

  // Partial match (same state)
  const leadState = extractState(leadMarket);
  if (
    leadState &&
    buyerLocations.some((loc) => {
      const state = extractState(loc);
      return state && state.toLowerCase() === leadState.toLowerCase();
    })
  )
    return 60;

  // Check if buyer targets broad regions
  if (buyerLocations.some((loc) => loc.toLowerCase() === "nationwide" || loc.toLowerCase() === "national"))
    return 70;

  return 0;
}

function extractState(location: string): string | null {
  const parts = location.split(",").map((p) => p.trim());
  return parts.length > 1 ? parts[parts.length - 1] : null;
}

/**
 * Score price match (0-100)
 * Within range = 100, within 10% = 75, within 25% = 50, outside = 0
 */
function scorePrice(
  askingPrice: number,
  buyerMin?: number | null,
  buyerMax?: number | null
): number {
  if (!buyerMin && !buyerMax) return 50;

  const min = buyerMin || 0;
  const max = buyerMax || Infinity;

  if (askingPrice >= min && askingPrice <= max) return 100;

  // Calculate how far outside range
  if (askingPrice < min) {
    const diff = (min - askingPrice) / min;
    if (diff <= 0.1) return 75;
    if (diff <= 0.25) return 50;
    return 0;
  }

  if (max !== Infinity && askingPrice > max) {
    const diff = (askingPrice - max) / max;
    if (diff <= 0.1) return 75;
    if (diff <= 0.25) return 50;
    return 0;
  }

  return 50;
}

/**
 * Score cap rate match (0-100)
 */
function scoreCapRate(
  capRate: number,
  buyerMin?: number | null,
  buyerMax?: number | null
): number {
  if (!buyerMin && !buyerMax) return 50;
  if (!capRate) return 50;

  const min = buyerMin || 0;
  const max = buyerMax || 100;

  if (capRate >= min && capRate <= max) return 100;

  const diff = capRate < min ? min - capRate : capRate - max;
  if (diff <= 0.5) return 75;
  if (diff <= 1.0) return 50;
  if (diff <= 2.0) return 25;
  return 0;
}

/**
 * Match a seller lead against all buyers and return ranked results
 */
export function matchLeadToBuyers(lead: SellerLead, buyers: Buyer[]): MatchResult[] {
  const results: MatchResult[] = buyers
    .filter((buyer) => buyer.status === "active" || buyer.status === "high-intent")
    .map((buyer) => {
      const { score, breakdown } = calculateMatchScore(lead, buyer);
      return { buyer, score, breakdown };
    })
    .filter((result) => result.score >= 30) // Minimum threshold
    .sort((a, b) => b.score - a.score);

  return results;
}

/**
 * Get match quality label based on score
 */
export function getMatchQuality(score: number): {
  label: string;
  color: string;
} {
  if (score >= 85) return { label: "Excellent", color: "text-emerald-600" };
  if (score >= 70) return { label: "Strong", color: "text-blue-600" };
  if (score >= 55) return { label: "Good", color: "text-amber-600" };
  if (score >= 40) return { label: "Fair", color: "text-orange-600" };
  return { label: "Weak", color: "text-red-600" };
}
