import { GeoSeekItem, GeoSeekItemType, geoSeekItems } from './geoseek';

export type GeoSeekDistancePriority = {
  rank: number;
  label: string;
  range: string;
  description: string;
};

export type GeoSeekScoredItem = GeoSeekItem & {
  geoScore: number;
  relevanceScore: number;
  distanceScore: number;
  distancePriority: GeoSeekDistancePriority;
  ratingScore: number;
  activityContribution: number;
  automationNotes: string[];
};

export type GeoSeekSmartDraft = {
  businessName: string;
  itemName: string;
  category: string;
  price?: number;
  stock?: number;
  location: string;
  promo: string;
  status: string;
  tags: string[];
  nextActions: string[];
};

export type GeoSeekCartItem = {
  id: string;
  name: string;
  businessName: string;
  price: number;
  quantity: number;
};

const normalize = (value: string) => value.toLowerCase().trim();

const distancePriorityTiers: Array<GeoSeekDistancePriority & { maxKm: number }> = [
  {
    rank: 0,
    maxKm: 1,
    label: 'Sangat dekat (jalan kaki)',
    range: '0–1 km',
    description: 'Prioritas tertinggi untuk kebutuhan yang bisa ditempuh dengan jalan kaki.',
  },
  {
    rank: 1,
    maxKm: 5,
    label: 'Dekat',
    range: '1–5 km',
    description: 'Masih dekat dari lokasi aktif dan cocok untuk kebutuhan harian sekitar.',
  },
  {
    rank: 2,
    maxKm: 10,
    label: 'Agak dekat',
    range: '5–10 km',
    description: 'Masih mudah dijangkau, biasanya perlu kendaraan singkat.',
  },
  {
    rank: 3,
    maxKm: 20,
    label: 'Sedang',
    range: '10–20 km',
    description: 'Jarak menengah; ditampilkan setelah hasil yang lebih dekat.',
  },
  {
    rank: 4,
    maxKm: Number.POSITIVE_INFINITY,
    label: 'Jauh',
    range: '20+ km',
    description: 'Di luar prioritas jarak utama dan hanya muncul jika radius diperluas.',
  },
];

export const getDistancePriority = (distanceKm?: number | null): GeoSeekDistancePriority => {
  const normalizedDistance =
    typeof distanceKm === 'number' && Number.isFinite(distanceKm)
      ? Math.max(distanceKm, 0)
      : Number.POSITIVE_INFINITY;

  return distancePriorityTiers.find((tier) => normalizedDistance <= tier.maxKm) || distancePriorityTiers[distancePriorityTiers.length - 1];
};

export const currency = (value?: number) => {
  if (typeof value !== 'number') return 'Hubungi penjual';

  return new Intl.NumberFormat('id-ID', {
    style: 'currency',
    currency: 'IDR',
    maximumFractionDigits: 0,
  }).format(value);
};

export const getGeoSeekModule = (module?: string | string[]) => {
  const key = Array.isArray(module) ? module[0] : module;

  return key || 'home';
};

export const calculateRelevanceScore = (item: GeoSeekItem, query: string) => {
  const normalizedQuery = normalize(query);
  if (!normalizedQuery) return 72;

  const searchable = normalize([
    item.name,
    item.businessName,
    item.category,
    item.description,
    item.area,
    item.tags.join(' '),
    item.promo || '',
  ].join(' '));

  const words = normalizedQuery.split(/\s+/).filter(Boolean);
  if (!words.length) return 72;

  const matched = words.filter((word) => searchable.includes(word)).length;
  const exactBonus = searchable.includes(normalizedQuery) ? 18 : 0;

  return Math.min(100, Math.round((matched / words.length) * 82 + exactBonus));
};

export const calculateGeoScore = (item: GeoSeekItem, query: string) => {
  const maxRadius = 20;
  const distanceScore = Math.max(0, Math.round((1 - Math.min(item.distanceKm, maxRadius) / maxRadius) * 100));
  const relevanceScore = calculateRelevanceScore(item, query);
  const ratingScore = Math.round((item.rating / 5) * 100);
  const activityContribution = item.activityScore;
  const geoScore = Math.round(
    distanceScore * 0.6 + relevanceScore * 0.2 + ratingScore * 0.1 + activityContribution * 0.1,
  );

  return {
    geoScore,
    relevanceScore,
    distanceScore,
    ratingScore,
    activityContribution,
  };
};

export const getAutomationNotes = (item: GeoSeekItem, moduleKey: string) => {
  const notes: string[] = [];

  if (item.open) notes.push('Buka sekarang');
  if (typeof item.stock === 'number' && item.stock <= 20) notes.push('Stok perlu dipantau/restock');
  if (typeof item.stock === 'number' && item.stock > 20) notes.push('Stok aman untuk order cepat');
  if (item.promo) notes.push('Promo aktif terdeteksi');
  if (item.bookingAvailable) notes.push('Bisa dibuat booking otomatis');
  if (item.deliveryAvailable) notes.push('Mendukung kurir/pengiriman lokal');
  if (item.etaMinutes) notes.push(`Estimasi respons ${item.etaMinutes} menit`);

  if (moduleKey === 'marketplace') notes.push('Siap masuk keranjang dan checkout simulasi');
  if (moduleKey === 'map') notes.push('Pin prioritas peta berdasarkan radius');
  if (moduleKey === 'business-dashboard') notes.push('Masuk insight dashboard bisnis');

  return notes.slice(0, 4);
};

export const filterGeoSeekItems = ({
  query,
  radiusKm,
  includeTypes,
  moduleKey,
  extraItems = [],
  baseItems = geoSeekItems,
}: {
  query: string;
  radiusKm: number;
  includeTypes: GeoSeekItemType[];
  moduleKey: string;
  extraItems?: GeoSeekItem[];
  baseItems?: GeoSeekItem[];
}): GeoSeekScoredItem[] => {
  const normalizedQuery = normalize(query);
  const sourceItems = [...extraItems, ...baseItems];

  return sourceItems
    .filter((item) => includeTypes.includes(item.type))
    .filter((item) => item.distanceKm <= radiusKm)
    .map((item) => ({
      ...item,
      ...calculateGeoScore(item, normalizedQuery),
      distancePriority: getDistancePriority(item.distanceKm),
      automationNotes: getAutomationNotes(item, moduleKey),
    }))
    .filter((item) => {
      if (!normalizedQuery) return true;

      const searchable = normalize([
        item.name,
        item.businessName,
        item.category,
        item.description,
        item.area,
        item.tags.join(' '),
        item.promo || '',
      ].join(' '));

      return normalizedQuery.split(/\s+/).some((word) => searchable.includes(word));
    })
    .sort((a, b) => {
      const priorityDiff = a.distancePriority.rank - b.distancePriority.rank;
      if (priorityDiff !== 0) return priorityDiff;

      const distanceDiff = a.distanceKm - b.distanceKm;
      if (Math.abs(distanceDiff) > 0.05) return distanceDiff;

      const geoScoreDiff = b.geoScore - a.geoScore;
      if (geoScoreDiff !== 0) return geoScoreDiff;

      return b.relevanceScore - a.relevanceScore;
    });
};

const getFirstCurrencyValue = (text: string) => {
  const match = text.match(/(?:rp\s*)?([0-9][0-9.]{2,})(?:\s*(?:rb|ribu))?/i);
  if (!match) return undefined;

  const raw = match[1].replace(/\./g, '');
  const number = Number(raw);
  if (Number.isNaN(number)) return undefined;

  if (/rb|ribu/i.test(match[0]) && number < 1000) return number * 1000;

  return number;
};

const getStockValue = (text: string) => {
  const match = text.match(/(?:stok|stock|tersedia|ready)\s*(\d+)/i);
  if (!match) return undefined;

  const number = Number(match[1]);
  return Number.isNaN(number) ? undefined : number;
};

const guessCategory = (text: string) => {
  const normalized = normalize(text);

  if (/nasi|kopi|bakso|mie|ayam|sarapan|kuliner|warung/.test(normalized)) return 'Kuliner';
  if (/pupuk|bibit|tani|sayur|organik/.test(normalized)) return 'Produk Pertanian';
  if (/ac|laundry|servis|jasa|teknisi|booking/.test(normalized)) return 'Jasa';
  if (/apotek|klinik|obat|vitamin|dokter/.test(normalized)) return 'Kesehatan';
  if (/ban|bengkel|oli|motor|mobil|aki/.test(normalized)) return 'Otomotif';
  if (/kios|rumah|kontrakan|tanah|ruko/.test(normalized)) return 'Properti';
  if (/wisata|tiket|tour|event|bazar/.test(normalized)) return 'Wisata & Event';
  if (/kurir|ongkir|antar|kirim|pickup/.test(normalized)) return 'Kurir';

  return 'UMKM Lokal';
};

const guessBusinessName = (text: string) => {
  const patterns = [
    /(?:umkm|toko|warung|kedai|apotek|bengkel|klinik|laundry|roastery)\s+([a-z0-9\s]{2,28})/i,
    /([a-z0-9\s]{2,28})\s+(?:buka|promo|menjual|ready|stok)/i,
  ];

  for (const pattern of patterns) {
    const match = text.match(pattern);
    if (match?.[0]) {
      return match[0]
        .replace(/\b(buka|promo|menjual|ready|stok)\b/gi, '')
        .trim()
        .replace(/\s+/g, ' ');
    }
  }

  return 'Bisnis Lokal Baru';
};

const guessItemName = (text: string) => {
  const normalized = text.replace(/\s+/g, ' ').trim();
  const productMatch = normalized.match(/(?:jual|menjual|promo|ready|stok)\s+([^,.]{3,42})/i);

  if (productMatch?.[1]) {
    return productMatch[1]
      .replace(/\b(rp\s*[0-9.]+|stok\s*\d+|dekat\s+.+)$/i, '')
      .trim();
  }

  return normalized.split(/[,.]/)[0].slice(0, 48) || 'Produk/Jasa Baru';
};

const guessLocation = (text: string) => {
  const match = text.match(/(?:dekat|di|area|lokasi)\s+([^,.]{3,36})/i);

  return match?.[1]?.trim() || 'Lokasi pengguna saat ini';
};

export const createSmartDraft = (input: string): GeoSeekSmartDraft => {
  const cleaned = input.trim();
  const category = guessCategory(cleaned);
  const stock = getStockValue(cleaned);
  const price = getFirstCurrencyValue(cleaned);
  const tags = Array.from(
    new Set(
      cleaned
        .toLowerCase()
        .replace(/[^a-z0-9\s]/gi, ' ')
        .split(/\s+/)
        .filter((word) => word.length > 3)
        .slice(0, 8),
    ),
  );

  return {
    businessName: guessBusinessName(cleaned),
    itemName: guessItemName(cleaned),
    category,
    price,
    stock,
    location: guessLocation(cleaned),
    promo: /promo|diskon|gratis|voucher|hemat/i.test(cleaned) ? 'Promo aktif dari input pengguna' : 'Belum ada promo khusus',
    status: /tutup|habis/i.test(cleaned) ? 'Perlu review manual' : 'Draft siap dipublikasikan',
    tags: tags.length ? tags : ['lokal', 'geoseek', 'umkm'],
    nextActions: [
      'Validasi lokasi dan radius bisnis',
      'Publikasikan ke menu terkait',
      'Buat notifikasi promo untuk warga sekitar',
      'Siapkan opsi booking/order/kurir jika relevan',
    ],
  };
};

export const getBusinessInsights = (items: GeoSeekScoredItem[]) => {
  const products = items.filter((item) => item.type === 'product' || item.type === 'culinary');
  const services = items.filter((item) => item.type === 'service');
  const promos = items.filter((item) => Boolean(item.promo) || item.type === 'promo');
  const lowStock = products.filter((item) => typeof item.stock === 'number' && item.stock <= 20);
  const bookingReady = items.filter((item) => item.bookingAvailable);
  const deliveryReady = items.filter((item) => item.deliveryAvailable);

  return {
    products: products.length,
    services: services.length,
    promos: promos.length,
    lowStock: lowStock.length,
    bookingReady: bookingReady.length,
    deliveryReady: deliveryReady.length,
    averageGeoScore: items.length ? Math.round(items.reduce((sum, item) => sum + item.geoScore, 0) / items.length) : 0,
    recommendations: [
      lowStock.length ? `${lowStock.length} item perlu restock hari ini.` : 'Stok utama masih aman.',
      promos.length ? `${promos.length} promo aktif siap didorong ke warga sekitar.` : 'Buat promo baru untuk menaikkan visibilitas.',
      deliveryReady.length ? 'Pengiriman lokal siap dipakai untuk checkout.' : 'Aktifkan kurir lokal untuk mempercepat transaksi.',
      bookingReady.length ? 'Booking otomatis tersedia untuk beberapa layanan.' : 'Tambahkan slot booking untuk jasa/layanan.',
    ],
  };
};

export const createCartFromResults = (items: GeoSeekScoredItem[]): GeoSeekCartItem[] => items
  .filter((item) => typeof item.price === 'number')
  .slice(0, 3)
  .map((item) => ({
    id: item.id,
    name: item.name,
    businessName: item.businessName,
    price: item.price || 0,
    quantity: item.type === 'culinary' ? 2 : 1,
  }));

export const getCheckoutSummary = (cartItems: GeoSeekCartItem[]) => {
  const subtotal = cartItems.reduce((sum, item) => sum + item.price * item.quantity, 0);
  const deliveryFee = cartItems.length ? 9000 : 0;
  const platformFee = cartItems.length ? 1500 : 0;
  const discount = subtotal >= 50000 ? 9000 : 0;
  const total = Math.max(0, subtotal + deliveryFee + platformFee - discount);

  return {
    subtotal,
    deliveryFee,
    platformFee,
    discount,
    total,
    paymentMethods: ['QRIS', 'Transfer Bank', 'E-Wallet'],
    status: cartItems.length ? 'Checkout simulasi siap diproses' : 'Tambahkan item untuk checkout',
  };
};
