const { useState, useRef, useEffect, useCallback, useMemo } = React;

// ─── System Prompt ──────────────────────────────────────────────────────────

const SOURCING_SYSTEM_PROMPT = `You are a Global Supplier Search Agent for manufacturing procurement. You help users find suppliers worldwide, build RFQ shortlists, compare quotes, and manage the sourcing process.

INTERACTION FLOW:
1. When the user first describes a need, ask what they need to source (part type, specs, quantity) and if they have a current supplier.
2. After understanding the need, search and populate suppliers on the map with rankings.
3. Proactively include supplier rankings (rankingScore 0-100) based on: certifications, price competitiveness, lead time, location risk, capabilities match.
4. When asked to "suggest top 20 suppliers" or similar, return a supplier-map block with 20 ranked suppliers across domestic, nearshore, and offshore regions.
5. When eliminating suppliers, ALWAYS explain why in your response AND include an elimination-log viz-data block.
6. When the user asks to update supplier information, include a supplier-update viz-data block.

IMPORTANT: When you provide structured data, include a JSON block so the UI can visualize it. Use this format:

\`\`\`viz-data
{ "type": "...", ... }
\`\`\`

Supported visualization types:

1. **supplier-map** — when discussing suppliers and their locations:
\`\`\`viz-data
{"type":"supplier-map","suppliers":[{"name":"Supplier Name","lat":40.7,"lng":-74.0,"country":"USA","capabilities":"CNC, milling","rating":"preferred","notes":"ISO 9001","contact":{"email":"sales@example.com","phone":"+1-555-0100","website":"https://example.com","contactPerson":"John Smith"},"certifications":["ISO 9001","AS9100"],"unitPrice":12.50,"leadTime":"4 weeks","moq":1000,"region":"domestic","rankingScore":87}]}
\`\`\`
rating can be: "preferred", "alternative", "current", "risky", "eliminated"
region must be: "domestic", "nearshore", or "offshore"
rankingScore: 0-100 (higher is better)
Include contact info, certifications, unitPrice, leadTime, moq, and rankingScore whenever possible.

2. **cost-chart** — when providing cost estimates or comparisons (ALWAYS include all 3 regions):
\`\`\`viz-data
{"type":"cost-chart","title":"Cost Comparison (per unit)","categories":["Material","Labor","Overhead","Logistics","Duties/Tariffs"],"series":[{"label":"Domestic (US)","values":[50,80,40,10,0]},{"label":"Nearshore (MX)","values":[45,30,20,15,0]},{"label":"Offshore (CN)","values":[35,15,10,25,20]}]}
\`\`\`
IMPORTANT: Do NOT include "Total" in categories. Always include exactly 3 series: Domestic (US), Nearshore, and Offshore/Global.

3. **quote-compare** — when comparing supplier quotes:
\`\`\`viz-data
{"type":"quote-compare","items":[{"supplier":"Acme Corp","unitPrice":12.50,"moq":1000,"leadTime":"4 weeks","quality":"ISO 9001","location":"Ohio, USA","tier":"A","region":"domestic"}]}
\`\`\`

4. **recommended-quotes** — curated top recommendations:
\`\`\`viz-data
{"type":"recommended-quotes","items":[{"supplier":"Acme Corp","unitPrice":12.50,"moq":1000,"leadTime":"4 weeks","quality":"ISO 9001","location":"Ohio, USA","tier":"S","region":"domestic","reason":"Best domestic option"}]}
\`\`\`

5. **elimination-log** — when suppliers are eliminated:
\`\`\`viz-data
{"type":"elimination-log","eliminations":[{"supplier":"Pacific Mfg","reason":"Missing ITAR certification","requirement":"ITAR"}]}
\`\`\`

6. **supplier-update** — when updating existing supplier information:
\`\`\`viz-data
{"type":"supplier-update","updates":[{"name":"Acme Corp","field":"unitPrice","value":11.50}]}
\`\`\`

7. **decision-flow** — when recommending a sourcing decision process:
\`\`\`viz-data
{"type":"decision-flow","title":"Sourcing Decision","nodes":[{"id":"1","label":"Requirement","type":"start"}],"edges":[{"from":"1","to":"2"}]}
\`\`\`

Always include the viz-data block alongside your text explanation.

Cost Estimation Framework:
When providing cost estimates, ALWAYS compare three sourcing regions side-by-side:
1. "Domestic (US)" - US-based manufacturing
2. "Nearshore (MX/CA)" - Mexico, Canada, or other USMCA/Latin America options
3. "Offshore (CN/VN/IN)" - China, Vietnam, India, or other global options

Break down costs into: Material, Labor, Overhead, Logistics, Duties/Tariffs.
Do NOT include a "Total" category.

Supplier Ranking Criteria (for rankingScore 0-100):
- Certifications match: 25 points
- Price competitiveness: 25 points
- Lead time: 15 points
- Location/logistics: 15 points
- Capabilities match: 10 points
- Reputation/size: 10 points

Interaction style:
- Ask clarifying questions
- Present comparisons clearly
- Flag risks
- Consider total cost of ownership
- Be specific with recommendations`;

const QUOTE_EXTRACTION_PROMPT = `You are a procurement document parser. Extract structured quote data from the uploaded document.

Return a JSON block in this exact format:
\`\`\`quote-data
{
  "supplierName": "...",
  "unitPrice": 0,
  "totalPrice": 0,
  "leadTime": "...",
  "moq": 0,
  "paymentTerms": "...",
  "shippingTerms": "...",
  "certifications": [],
  "countryOfOrigin": "...",
  "validUntil": "...",
  "notes": "..."
}
\`\`\`

Extract as much as possible. Use null for fields you cannot find. Be precise with numbers.`;

const DEMO_QUOTE_PROMPT = `You are a procurement data generator. Generate a realistic supplier quote for demo purposes.

Supplier context:
- Name: {supplierName}
- Country: {country}
- Region: {region} (domestic / nearshore / offshore)
- Capabilities: {capabilities}
- Certifications: {certifications}
- Indicative unit price: {unitPrice}

RFQ context:
- Description: {rfqDescription}
- Quantity: {quantity}
- Requirements: {requirements}

Today's date: {todayISO}

Return ONLY this JSON block, no other text:
\`\`\`quote-data
{
  "supplierName": "...",
  "unitPrice": 0,
  "totalPrice": 0,
  "leadTime": "...",
  "moq": 0,
  "paymentTerms": "...",
  "shippingTerms": "...",
  "certifications": [],
  "countryOfOrigin": "...",
  "validUntil": "YYYY-MM-DD",
  "notes": "..."
}
\`\`\`

Make values realistic for the supplier region:
- domestic: higher unit price ($15–30), 2–4 week lead time, Net-30 payment, FOB Origin
- nearshore: mid price ($8–18), 4–6 week lead time, Net-45 payment, DAP
- offshore: lower price ($3–12), 6–12 week lead time, Net-60 payment, CIF
Use certifications the supplier already holds. Set validUntil to 90 days from today's date.`;

const RFQ_EXTRACTION_PROMPT = `You are a procurement assistant. Extract RFQ details from a conversation.
Return ONLY this JSON block, no other text:
\`\`\`rfq-data
{
  "name": "short descriptive RFQ title (max 60 chars)",
  "description": "what is being sourced and key context",
  "quantity": 0,
  "targetDate": "YYYY-MM-DD or empty string if unknown",
  "requirements": "technical or compliance requirements mentioned (certifications, materials, specs) or empty string"
}
\`\`\``;

const SUPPLIER_SCORING_PROMPT = `You are a procurement analyst. Score this supplier quote 0-100 across 5 dimensions.
Return ONLY this JSON block:
\`\`\`score-data
{
  "overall": 0,
  "breakdown": { "price": 0, "leadTime": 0, "certifications": 0, "riskProfile": 0, "paymentTerms": 0 },
  "summary": "2-3 sentence assessment."
}
\`\`\`
Weights: Price 30%, Lead Time 20%, Certifications 20%, Risk Profile 15%, Payment Terms 15%.
Price: lower vs market = higher score. Lead Time: <4wk=90+, 4-8wk=60-80, >12wk=<40.
Certifications: ISO 9001=+20, AS9100=+25, ITAR=+20, each other=+10, cap 100.
Risk: US domestic=85+, nearshore=70-80, established offshore=50-70, high-risk country=<40.
Payment Terms: Net 30=80, Net 60=60, Prepayment=20, LC=50.`;

const WELCOME_MESSAGE = `Hello! I'm your **Global Supplier Search Agent**. I help you find, evaluate, and manage suppliers worldwide.

## How to Get Started

1. **Tell me what you need to source** -- part type, specifications, quantity
2. **Share your current supplier** (optional) -- I'll benchmark against alternatives

I'll search globally, rank suppliers, and help you build an RFQ shortlist right from the map.

Use the quick actions below or just describe what you need!`;

// ─── Utilities ──────────────────────────────────────────────────────────────

function generateId() {
  return Date.now().toString(36) + Math.random().toString(36).substr(2, 6);
}

function classifyCountry(country) {
  const c = (country || "").toLowerCase();
  const domestic = ["usa", "united states", "us", "america"];
  const nearshore = ["mexico", "canada", "costa rica", "colombia", "brazil", "dominican", "guatemala", "honduras", "el salvador", "panama", "chile", "argentina", "peru"];
  if (domestic.some(d => c.includes(d))) return "domestic";
  if (nearshore.some(n => c.includes(n))) return "nearshore";
  return "offshore";
}

function formatDate(dateStr) {
  if (!dateStr) return "";
  try {
    return new Date(dateStr).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
  } catch { return dateStr; }
}

// ─── Markdown Renderer ──────────────────────────────────────────────────────

function renderMarkdown(text) {
  const cleaned = text.replace(/```viz-data[\s\S]*?```/g, "").replace(/```quote-data[\s\S]*?```/g, "").trim();
  const lines = cleaned.split("\n");
  const result = [];
  let inTable = false;
  let tableRows = [];

  function processInline(str) {
    str = str.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
    str = str.replace(/`(.+?)`/g, '<code style="background:#374151;padding:1px 4px;border-radius:3px;font-size:12px;color:#E5E7EB">$1</code>');
    str = str.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank" rel="noopener" style="color:#60A5FA;text-decoration:underline">$1</a>');
    return str;
  }

  function flushTable() {
    if (tableRows.length < 2) { tableRows = []; return null; }
    const header = tableRows[0];
    const body = tableRows.slice(2);
    const html = `<table style="width:100%;border-collapse:collapse;font-size:12px;margin:8px 0">
      <thead><tr>${header.map(h => `<th style="border:1px solid #4B5563;padding:6px 10px;background:#374151;text-align:left;font-weight:600;color:#E5E7EB">${processInline(h.trim())}</th>`).join("")}</tr></thead>
      <tbody>${body.map(row => `<tr>${row.map(cell => `<td style="border:1px solid #4B5563;padding:6px 10px;color:#D1D5DB">${processInline(cell.trim())}</td>`).join("")}</tr>`).join("")}</tbody>
    </table>`;
    tableRows = [];
    return html;
  }

  for (let i = 0; i < lines.length; i++) {
    const line = lines[i];
    if (line.trim().startsWith("|") && line.trim().endsWith("|")) {
      const cells = line.split("|").filter((_, idx, arr) => idx > 0 && idx < arr.length - 1);
      if (!inTable) inTable = true;
      tableRows.push(cells);
      continue;
    }
    if (inTable) {
      const tableHtml = flushTable();
      if (tableHtml) result.push(tableHtml);
      inTable = false;
    }
    if (line.trim().match(/^#{1,4}\s+/)) {
      const match = line.trim().match(/^(#{1,4})\s+(.*)/);
      const level = match[1].length;
      const sizes = { 1: "18px", 2: "15px", 3: "13px", 4: "12px" };
      result.push(`<div style="font-size:${sizes[level]};font-weight:700;margin:10px 0 4px;color:#F1F5F9">${processInline(match[2])}</div>`);
    } else if (line.trim().startsWith("- ") || line.trim().startsWith("* ") || line.trim().startsWith("• ")) {
      const content = line.trim().replace(/^[-*\u2022]\s*/, "");
      result.push(`<div style="padding:2px 0 2px 16px;color:#D1D5DB">${processInline(content)}</div>`);
    } else if (line.trim().match(/^\d+\.\s/)) {
      result.push(`<div style="padding:2px 0 2px 16px;color:#D1D5DB">${processInline(line.trim())}</div>`);
    } else if (line.trim() === "") {
      result.push('<div style="height:4px"></div>');
    } else {
      result.push(`<div style="margin:2px 0;color:#D1D5DB">${processInline(line)}</div>`);
    }
  }
  if (inTable) { const t = flushTable(); if (t) result.push(t); }
  return result.join("");
}

// ─── Stable supplier ID (name-based, survives session replays) ───────────────
function stableSupplierIdFromName(name) {
  let h = 0;
  for (let i = 0; i < (name || '').length; i++) { h = Math.imul(31, h) + name.charCodeAt(i) | 0; }
  return 'sup_' + Math.abs(h).toString(36);
}

// ─── Extract viz-data from LLM response ─────────────────────────────────────

function extractVizData(text) {
  const blocks = [];
  const regex = /```viz-data\s*([\s\S]*?)```/g;
  let match;
  while ((match = regex.exec(text)) !== null) {
    try { blocks.push(JSON.parse(match[1].trim())); } catch (e) { /* skip */ }
  }
  return blocks;
}

function extractQuoteData(text) {
  const regex = /```quote-data\s*([\s\S]*?)```/g;
  let match;
  while ((match = regex.exec(text)) !== null) {
    try { return JSON.parse(match[1].trim()); } catch (e) { /* skip */ }
  }
  return null;
}

// ─── Client-side File Parsing ────────────────────────────────────────────────

async function parseUploadedFile(file) {
  const ext = file.name.split(".").pop().toLowerCase();
  if (ext === "pdf") {
    if (!window.pdfjsLib) throw new Error("PDF library still loading, please try again.");
    const arrayBuffer = await file.arrayBuffer();
    const pdf = await window.pdfjsLib.getDocument({ data: arrayBuffer }).promise;
    const pages = [];
    for (let i = 1; i <= pdf.numPages; i++) {
      const page = await pdf.getPage(i);
      const content = await page.getTextContent();
      pages.push(content.items.map(item => item.str).join(" "));
    }
    return { filename: file.name, text: pages.join("\n\n"), pageCount: pdf.numPages };
  }
  if (ext === "docx") {
    if (!window.mammoth) throw new Error("DOCX library not loaded.");
    const arrayBuffer = await file.arrayBuffer();
    const result = await mammoth.extractRawText({ arrayBuffer });
    return { filename: file.name, text: result.value, pageCount: null };
  }
  const text = await file.text();
  return { filename: file.name, text, pageCount: null };
}

// ─── Quick Actions ──────────────────────────────────────────────────────────

const QUICK_ACTIONS = [
  { id: "find-suppliers", label: "Find Suppliers", icon: "\uD83D\uDD0D", prompt: "I need to find suppliers for: ", searchEnabled: true },
  { id: "top-20", label: "Suggest Top 20", icon: "\uD83C\uDFC6", prompt: "Suggest the top 20 suppliers globally for: ", searchEnabled: true },
  { id: "cost-estimate", label: "Cost Estimate", icon: "\uD83D\uDCB0", prompt: "Give me a detailed cost estimate with breakdown for: " },
  { id: "compare-quotes", label: "Compare Quotes", icon: "\uD83D\uDCCA", prompt: "Compare these supplier quotes:\n\nSupplier 1: [name, price, lead time, MOQ]\nSupplier 2: [name, price, lead time, MOQ]\n\nPart: " },
  { id: "update-supplier", label: "Update Info", icon: "\u270F\uFE0F", prompt: "Update supplier information: " }
];

// ─── Score Algorithm ────────────────────────────────────────────────────────

function computeQuoteScore(quote, allQuotes) {
  let score = 0;
  // Price competitiveness: 30%
  const prices = allQuotes.map(q => q.unitPrice).filter(p => p > 0);
  if (prices.length > 0 && quote.unitPrice > 0) {
    const minPrice = Math.min(...prices);
    const maxPrice = Math.max(...prices);
    const range = maxPrice - minPrice || 1;
    score += (1 - (quote.unitPrice - minPrice) / range) * 30;
  }
  // Lead time: 20%
  const leadDays = parseLeadTimeDays(quote.leadTime);
  if (leadDays > 0) {
    const allDays = allQuotes.map(q => parseLeadTimeDays(q.leadTime)).filter(d => d > 0);
    if (allDays.length > 0) {
      const minDays = Math.min(...allDays);
      const maxDays = Math.max(...allDays);
      const range = maxDays - minDays || 1;
      score += (1 - (leadDays - minDays) / range) * 20;
    }
  }
  // Certifications: 20%
  const certCount = (quote.certifications || []).length;
  score += Math.min(certCount / 3, 1) * 20;
  // Supply chain risk: 15%
  const riskMap = { domestic: 15, nearshore: 10, offshore: 5 };
  score += riskMap[quote.category] || 5;
  // Payment terms: 15%
  const terms = (quote.paymentTerms || "").toLowerCase();
  if (terms.includes("net 60") || terms.includes("net 90")) score += 15;
  else if (terms.includes("net 30") || terms.includes("net 45")) score += 10;
  else if (terms.includes("advance") || terms.includes("prepay")) score += 3;
  else score += 7;
  return Math.round(Math.min(score, 100));
}

function parseLeadTimeDays(lt) {
  if (!lt) return 0;
  const s = lt.toLowerCase();
  const numMatch = s.match(/(\d+)/);
  if (!numMatch) return 0;
  const num = parseInt(numMatch[1]);
  if (s.includes("week")) return num * 7;
  if (s.includes("month")) return num * 30;
  return num;
}

// ─── Sidebar Navigation ─────────────────────────────────────────────────────

const NAV_ITEMS = [
  { id: "discovery", label: "Chat & Discovery", icon: "\uD83D\uDCAC" },
  { id: "rfq", label: "RFQ Management", icon: "\uD83D\uDCCB" },
  { id: "analysis", label: "Quote Analysis", icon: "\uD83D\uDCCA" }
];

// ─── DB API helpers ───────────────────────────────────────────────────────────
function dbGet(collection) {
  return fetch(`/api/data/${collection}`, {
    headers: { "Authorization": `Bearer ${localStorage.getItem("auth_token")}` }
  }).then(r => r.ok ? r.json() : Promise.reject(r.status));
}
function dbUpsert(collection, item) {
  return fetch(`/api/data/${collection}`, {
    method: "POST",
    headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("auth_token")}` },
    body: JSON.stringify(item)
  }).then(r => r.ok ? r.json() : Promise.reject(r.status));
}
function dbDelete(collection, id) {
  return fetch(`/api/data/${collection}/${id}`, {
    method: "DELETE",
    headers: { "Authorization": `Bearer ${localStorage.getItem("auth_token")}` }
  }).then(r => r.ok ? r.json() : Promise.reject(r.status));
}
// ─────────────────────────────────────────────────────────────────────────────

function Sidebar({ activeView, onNavigate, counts, collapsed, onToggleCollapse, onBack, onSettings }) {
  return (
    <div style={{
      width: collapsed ? 56 : 220, background: "#0F172A", display: "flex", flexDirection: "column",
      borderRight: "1px solid #1E293B", transition: "width 0.2s ease", flexShrink: 0, zIndex: 50
    }}>
      {/* Logo */}
      <div style={{ padding: collapsed ? "16px 8px" : "16px 16px", borderBottom: "1px solid #1E293B", display: "flex", alignItems: "center", gap: 10 }}>
        <div style={{ width: 32, height: 32, borderRadius: 8, background: "linear-gradient(135deg, #3B82F6, #8B5CF6)", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 16, flexShrink: 0 }}>
          N
        </div>
        {!collapsed && <span style={{ fontSize: 15, fontWeight: 800, color: "white", letterSpacing: -0.5 }}>NeuraChain</span>}
      </div>

      {/* Nav items */}
      <div style={{ flex: 1, padding: "8px 0", display: "flex", flexDirection: "column", gap: 2 }}>
        {NAV_ITEMS.map(item => {
          const isActive = activeView === item.id;
          const count = counts[item.id] || 0;
          return (
            <button
              key={item.id}
              onClick={() => onNavigate(item.id)}
              title={collapsed ? item.label : undefined}
              style={{
                display: "flex", alignItems: "center", gap: 10, padding: collapsed ? "10px 0" : "10px 16px",
                justifyContent: collapsed ? "center" : "flex-start",
                background: isActive ? "#1E293B" : "transparent", border: "none", cursor: "pointer",
                borderLeft: isActive ? "3px solid #3B82F6" : "3px solid transparent",
                color: isActive ? "#F1F5F9" : "#94A3B8", fontSize: 13, fontWeight: isActive ? 600 : 400,
                transition: "all 0.15s", width: "100%", position: "relative"
              }}
            >
              <span style={{ fontSize: 18, flexShrink: 0 }}>{item.icon}</span>
              {!collapsed && <span>{item.label}</span>}
              {count > 0 && (
                <span style={{
                  position: collapsed ? "absolute" : "relative", top: collapsed ? 4 : "auto", right: collapsed ? 6 : "auto",
                  marginLeft: collapsed ? 0 : "auto", background: "#3B82F6", color: "white",
                  fontSize: 10, fontWeight: 700, padding: "1px 6px", borderRadius: 10, minWidth: 16, textAlign: "center"
                }}>{count}</span>
              )}
            </button>
          );
        })}
      </div>

      {/* Bottom actions */}
      <div style={{ borderTop: "1px solid #1E293B", padding: "8px 0", display: "flex", flexDirection: "column", gap: 2 }}>
        <button onClick={onToggleCollapse} style={{
          display: "flex", alignItems: "center", justifyContent: collapsed ? "center" : "flex-start",
          gap: 10, padding: collapsed ? "10px 0" : "10px 16px", background: "transparent",
          border: "none", cursor: "pointer", color: "#64748B", fontSize: 13, width: "100%"
        }}>
          <span style={{ fontSize: 16 }}>{collapsed ? "\u00BB" : "\u00AB"}</span>
          {!collapsed && <span>Collapse</span>}
        </button>
        <button onClick={onSettings} style={{
          display: "flex", alignItems: "center", justifyContent: collapsed ? "center" : "flex-start",
          gap: 10, padding: collapsed ? "10px 0" : "10px 16px", background: "transparent",
          border: "none", cursor: "pointer", color: "#64748B", fontSize: 13, width: "100%"
        }}>
          <span style={{ fontSize: 16 }}>{"\u2699"}</span>
          {!collapsed && <span>Settings</span>}
        </button>
        {onBack && (
          <button onClick={onBack} style={{
            display: "flex", alignItems: "center", justifyContent: collapsed ? "center" : "flex-start",
            gap: 10, padding: collapsed ? "10px 0" : "10px 16px", background: "transparent",
            border: "none", cursor: "pointer", color: "#64748B", fontSize: 13, width: "100%"
          }}>
            <span style={{ fontSize: 16 }}>{"\u2190"}</span>
            {!collapsed && <span>Home</span>}
          </button>
        )}
      </div>
    </div>
  );
}

// ─── Sources Card ───────────────────────────────────────────────────────────

function SourcesCard({ sources }) {
  const [expanded, setExpanded] = useState(false);
  if (!sources || sources.length === 0) return null;
  return (
    <div style={{ maxWidth: "85%" }}>
      <button onClick={() => setExpanded(!expanded)} style={{
        display: "flex", alignItems: "center", gap: 8, padding: "4px 10px",
        background: "#1E293B", border: "1px solid #374151", borderRadius: 6,
        fontSize: 11, color: "#94A3B8", cursor: "pointer"
      }}>
        <span>{sources.length} sources</span>
        <span style={{ fontSize: 10 }}>{expanded ? "\u25B2" : "\u25BC"}</span>
      </button>
      {expanded && (
        <div style={{ marginTop: 4, padding: "6px 10px", background: "#1E293B", border: "1px solid #374151", borderRadius: 6, display: "flex", flexDirection: "column", gap: 6 }}>
          {sources.map((s, i) => (
            <div key={i}>
              <a href={s.link} target="_blank" rel="noopener" style={{ color: "#60A5FA", fontSize: 11, fontWeight: 500 }}>{s.title}</a>
              <div style={{ fontSize: 11, color: "#6B7280" }}>{s.snippet}</div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ─── Elimination Card ───────────────────────────────────────────────────────

function EliminationCard({ eliminations }) {
  if (!eliminations || eliminations.length === 0) return null;
  return (
    <div style={{ marginTop: 6, padding: "8px 12px", background: "#7F1D1D20", border: "1px solid #7F1D1D40", borderRadius: 8, maxWidth: "90%" }}>
      <div style={{ fontSize: 11, fontWeight: 700, color: "#EF4444", marginBottom: 4 }}>Suppliers Eliminated</div>
      {eliminations.map((e, i) => (
        <div key={i} style={{ fontSize: 12, color: "#FCA5A5", padding: "2px 0", display: "flex", gap: 6 }}>
          <span style={{ color: "#EF4444" }}>{"\u2715"}</span>
          <div><strong>{e.supplier}</strong> -- {e.reason}</div>
        </div>
      ))}
    </div>
  );
}

// ─── Supplier Map Panel ─────────────────────────────────────────────────────

function SupplierMapPanel({ suppliers, onAddToRfq, rfqSupplierIds, quotes }) {
  const mapRef = useRef(null);
  const mapInstanceRef = useRef(null);
  const markersRef = useRef([]);

  useEffect(() => {
    if (!mapRef.current || !window.L) return;
    // Add pulse animation style if not already present
    if (!document.getElementById('map-pulse-style')) {
      const style = document.createElement('style');
      style.id = 'map-pulse-style';
      style.textContent = '@keyframes pulse { 0%,100% { opacity:1; } 50% { opacity:0.5; } }';
      document.head.appendChild(style);
    }
    if (!mapInstanceRef.current) {
      mapInstanceRef.current = L.map(mapRef.current, { attributionControl: false }).setView([30, 0], 2);
      L.tileLayer("https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png", {
        maxZoom: 18
      }).addTo(mapInstanceRef.current);
    }
    return () => {
      if (mapInstanceRef.current) { mapInstanceRef.current.remove(); mapInstanceRef.current = null; }
    };
  }, []);

  useEffect(() => {
    window.__addToRfqFromMap__ = (supplierId) => { if (onAddToRfq) onAddToRfq(supplierId); };
    return () => { delete window.__addToRfqFromMap__; };
  }, [onAddToRfq]);

  useEffect(() => {
    if (!mapInstanceRef.current) return;
    // Always clear old markers first so stale pins don't linger
    markersRef.current.forEach(m => m.remove());
    markersRef.current = [];
    if (!suppliers || suppliers.length === 0) return;
    const ratingColors = { preferred: "#22C55E", alternative: "#3B82F6", current: "#F59E0B", risky: "#EF4444", eliminated: "#6B7280" };
    const bounds = [];

    suppliers.forEach(s => {
      if (!s.lat || !s.lng || s.eliminated) return;
      const color = ratingColors[s.rating] || "#6B7280";
      const inRfq = rfqSupplierIds && rfqSupplierIds.has(s.id);
      // Determine quote status for this supplier
      const supplierQuotes = (quotes || []).filter(q => q.supplierId === s.id || q.supplierName.toLowerCase() === s.name.toLowerCase());
      const hasQuote = supplierQuotes.length > 0;
      const bestQuote = hasQuote ? supplierQuotes.reduce((a, b) => a.score > b.score ? a : b) : null;
      const quotePrice = hasQuote ? bestQuote.unitPrice : s.unitPrice;

      const markerSize = hasQuote ? 18 : 14;
      const borderWidth = hasQuote ? 3 : 2;
      const glowStyle = hasQuote && bestQuote.score >= 70 ? 'box-shadow:0 0 8px 2px #22C55E;' : '';
      const pulseStyle = inRfq && !hasQuote ? 'animation:pulse 2s infinite;' : '';
      const shapeStyle = hasQuote ? 'border-radius:3px;transform:rotate(45deg);' : 'border-radius:50%;';

      const icon = L.divIcon({
        className: "",
        html: `<div style="position:relative">
          <div style="width:${markerSize}px;height:${markerSize}px;${shapeStyle}background:${color};border:${borderWidth}px solid white;box-shadow:0 1px 4px rgba(0,0,0,0.4);${inRfq ? 'outline:2px solid #8B5CF6;outline-offset:2px;' : ''}${glowStyle}${pulseStyle}"></div>
          ${quotePrice ? `<div style="position:absolute;top:-22px;left:50%;transform:translateX(-50%);background:#0F172AE8;color:#F1F5F9;padding:2px 8px;border-radius:4px;font-size:11px;font-weight:800;white-space:nowrap;box-shadow:0 2px 6px rgba(0,0,0,0.5);border:1px solid ${hasQuote ? '#22C55E' : '#374151'};">$${typeof quotePrice === 'number' ? quotePrice.toFixed(2) : quotePrice}${hasQuote ? ' \u2713' : ''}</div>` : `<div style="position:absolute;top:-18px;left:50%;transform:translateX(-50%);background:#0F172AE8;color:#94A3B8;padding:2px 8px;border-radius:4px;font-size:10px;font-weight:600;white-space:nowrap;box-shadow:0 2px 6px rgba(0,0,0,0.5);border:1px solid #374151;">${s.name.length > 15 ? s.name.slice(0,15) + '\u2026' : s.name}</div>`}
        </div>`,
        iconSize: [markerSize, markerSize], iconAnchor: [markerSize/2, markerSize/2]
      });
      const certBadges = (s.certifications || []).map(c => `<span style="display:inline-block;padding:1px 4px;background:#1E293B;border:1px solid #374151;border-radius:3px;font-size:9px;color:#60A5FA;margin:1px 2px 1px 0">${c}</span>`).join("");
      const popup = `<div style="font-size:12px;min-width:220px;max-width:280px;color:#F1F5F9;background:#1E293B;margin:-14px -20px;padding:12px 14px;border-radius:8px;">
        <div style="font-weight:700;font-size:13px;margin-bottom:4px;">${s.name}</div>
        <div style="color:#94A3B8;font-size:11px;margin-bottom:6px;">${s.country || ""} <span style="padding:1px 5px;background:#374151;border-radius:3px;font-size:9px;font-weight:600;">${s.category || s.region || ""}</span></div>
        ${s.capabilities ? `<div style="font-size:10px;color:#94A3B8;margin-bottom:4px;">${s.capabilities}</div>` : ""}
        ${certBadges ? `<div style="margin-bottom:4px;">${certBadges}</div>` : ""}
        <div style="display:flex;gap:10px;margin-top:6px;">
          ${s.unitPrice ? `<div><div style="font-size:14px;font-weight:800;">$${s.unitPrice}</div><div style="font-size:9px;color:#94A3B8;">unit</div></div>` : ""}
          ${s.leadTime ? `<div><div style="font-size:12px;font-weight:600;">${s.leadTime}</div><div style="font-size:9px;color:#94A3B8;">lead time</div></div>` : ""}
          ${s.moq ? `<div><div style="font-size:12px;font-weight:600;">${typeof s.moq === 'number' ? s.moq.toLocaleString() : s.moq}</div><div style="font-size:9px;color:#94A3B8;">MOQ</div></div>` : ""}
        </div>
        <button onclick="window.__addToRfqFromMap__('${s.id}')" style="margin-top:8px;padding:5px 0;background:${inRfq ? '#22C55E' : '#3B82F6'};color:white;border:none;border-radius:5px;font-size:11px;cursor:pointer;font-weight:600;width:100%;">
          ${inRfq ? '\u2713 In RFQ' : '+ Add to RFQ'}
        </button>
      </div>`;
      const marker = L.marker([s.lat, s.lng], { icon }).addTo(mapInstanceRef.current);
      marker.bindPopup(popup, { maxWidth: 300, className: "dark-popup" });
      markersRef.current.push(marker);
      bounds.push([s.lat, s.lng]);
    });
    if (bounds.length > 0) mapInstanceRef.current.fitBounds(bounds, { padding: [40, 40], maxZoom: 6 });
  }, [suppliers, rfqSupplierIds, quotes]);

  return (
    <div style={{ height: "100%", position: "relative" }}>
      <div ref={mapRef} style={{ height: "100%" }} />
      {/* Legend */}
      <div style={{
        position: "absolute", bottom: 12, left: 12, background: "#0F172AE0", padding: "8px 12px",
        borderRadius: 8, display: "flex", gap: 10, fontSize: 10, color: "#94A3B8", zIndex: 1000
      }}>
        <span style={{ display: "flex", alignItems: "center", gap: 3 }}><span style={{ width: 8, height: 8, borderRadius: "50%", background: "#22C55E", display: "inline-block" }} /> Preferred</span>
        <span style={{ display: "flex", alignItems: "center", gap: 3 }}><span style={{ width: 8, height: 8, borderRadius: "50%", background: "#3B82F6", display: "inline-block" }} /> Alt</span>
        <span style={{ display: "flex", alignItems: "center", gap: 3 }}><span style={{ width: 8, height: 8, borderRadius: "50%", background: "#EF4444", display: "inline-block" }} /> Risky</span>
        <span style={{ display: "flex", alignItems: "center", gap: 3 }}><span style={{ width: 8, height: 8, borderRadius: 2, background: "#F59E0B", display: "inline-block", transform: "rotate(45deg)" }} /> Quoted</span>
        <span style={{ display: "flex", alignItems: "center", gap: 3 }}><span style={{ width: 8, height: 8, borderRadius: "50%", background: "#6B7280", display: "inline-block", outline: "2px solid #8B5CF6", outlineOffset: 1 }} /> In RFQ</span>
        {suppliers && suppliers.length > 0 && (
          <span style={{ fontWeight: 600, color: "#E2E8F0" }}>{suppliers.filter(s => !s.eliminated).length} suppliers</span>
        )}
      </div>
      {(!suppliers || suppliers.length === 0) && (
        <div style={{ position: "absolute", top: "50%", left: "50%", transform: "translate(-50%,-50%)", textAlign: "center", color: "#64748B", fontSize: 14 }}>
          <div style={{ fontSize: 32, marginBottom: 8 }}>{"\uD83D\uDDFA\uFE0F"}</div>
          Ask me to find suppliers and they'll appear on the map
        </div>
      )}
    </div>
  );
}

// ─── View 1: Chat & Discovery ───────────────────────────────────────────────

function ChatSessionPanel({ sessions, activeSesId, onSelect, onNew, onDelete }) {
  const [confirmId, setConfirmId] = React.useState(null);
  function relTime(iso) {
    if (!iso) return "";
    const d = Math.floor((Date.now() - new Date(iso)) / 86400000);
    if (d === 0) return "today";
    if (d === 1) return "yesterday";
    return `${d}d ago`;
  }
  return (
    <div style={{ width: 210, minWidth: 210, background: "#0A1120", borderRight: "1px solid #1E293B", display: "flex", flexDirection: "column", overflow: "hidden" }}>
      <div style={{ padding: "10px 10px 8px", borderBottom: "1px solid #1E293B", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
        <span style={{ fontSize: 10, fontWeight: 700, color: "#64748B", textTransform: "uppercase", letterSpacing: 0.5 }}>Conversations</span>
        <button onClick={onNew} style={{ background: "#3B82F6", border: "none", borderRadius: 5, color: "white", fontSize: 10, padding: "2px 7px", cursor: "pointer", fontWeight: 700 }}>+ New</button>
      </div>
      <div style={{ flex: 1, overflowY: "auto" }}>
        {sessions.length === 0 && (
          <div style={{ padding: "14px 10px", color: "#374151", fontSize: 12 }}>No saved conversations</div>
        )}
        {[...sessions].reverse().map(s => {
          const isActive = s.id === activeSesId;
          const isConfirm = confirmId === s.id;
          return (
            <div key={s.id}
              onClick={() => !isConfirm && onSelect(s)}
              style={{ padding: "9px 10px", cursor: "pointer", borderLeft: isActive ? "3px solid #3B82F6" : "3px solid transparent", background: isActive ? "#1E293B" : "transparent", borderBottom: "1px solid #1E293B20", display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 4 }}
              onMouseEnter={e => { if (!isActive) e.currentTarget.style.background = "#1E293B50"; }}
              onMouseLeave={e => { if (!isActive) e.currentTarget.style.background = "transparent"; }}
            >
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 12, color: "#E2E8F0", fontWeight: isActive ? 600 : 400, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                  {s.title || "Untitled"}
                </div>
                <div style={{ fontSize: 10, color: "#4B5563", marginTop: 2 }}>{relTime(s.updatedAt)}</div>
              </div>
              {isConfirm ? (
                <div style={{ display: "flex", gap: 3, flexShrink: 0 }} onClick={e => e.stopPropagation()}>
                  <button onClick={() => { onDelete(s.id); setConfirmId(null); }} style={{ fontSize: 10, padding: "1px 5px", background: "#EF4444", color: "white", border: "none", borderRadius: 3, cursor: "pointer" }}>Yes</button>
                  <button onClick={() => setConfirmId(null)} style={{ fontSize: 10, padding: "1px 5px", background: "#374151", color: "white", border: "none", borderRadius: 3, cursor: "pointer" }}>No</button>
                </div>
              ) : (
                <button onClick={e => { e.stopPropagation(); setConfirmId(s.id); }} style={{ background: "none", border: "none", color: "#374151", cursor: "pointer", fontSize: 12, padding: "0 2px", flexShrink: 0 }} title="Delete">{"\uD83D\uDDD1"}</button>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}

function ChatDiscoveryView({ messages, input, setInput, loading, loadingStatus, onSend, onFileSelect, uploadedFile, setUploadedFile, uploadError, setUploadError, suppliers, onAddToRfq, rfqSupplierIds, activeAction, setActiveAction, quotes, chatSessions, activeSesId, onLoadChat, onDeleteChat, onNewChat, onCreateRfq }) {
  const chatEndRef = useRef(null);
  const inputRef = useRef(null);
  const fileInputRef = useRef(null);

  useEffect(() => {
    chatEndRef.current?.scrollIntoView({ behavior: "smooth" });
  }, [messages, loading]);

  const userMessageCount = messages.filter(m => m.role === "user").length;
  const showQuickActions = userMessageCount < 5;

  function handleQuickAction(action) {
    setActiveAction(action);
    setInput(action.prompt);
    setTimeout(() => inputRef.current?.focus(), 50);
  }

  function handleKeyDown(e) {
    if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); onSend(); }
  }

  return (
    <div style={{ flex: 1, display: "flex", overflow: "hidden" }}>
      {/* Session panel */}
      <ChatSessionPanel
        sessions={chatSessions || []}
        activeSesId={activeSesId}
        onSelect={onLoadChat}
        onNew={onNewChat}
        onDelete={onDeleteChat}
      />
      {/* Left: Chat — width reduced from 42% to 38% to accommodate session panel */}
      <div style={{ width: "38%", minWidth: 300, display: "flex", flexDirection: "column", borderRight: "1px solid #1E293B", background: "#111827" }}>
        {/* Messages */}
        <div style={{ flex: 1, overflowY: "auto", padding: "16px 12px", display: "flex", flexDirection: "column", gap: 10 }}>
          {messages.filter(m => m.role === "user").length === 0 && (
            <div style={{ maxWidth: "90%", padding: "10px 14px", fontSize: 13, lineHeight: 1.55, borderRadius: 12, background: "#1E293B", color: "#D1D5DB", border: "1px solid #374151" }}>
              <div dangerouslySetInnerHTML={{ __html: renderMarkdown(WELCOME_MESSAGE) }} />
            </div>
          )}
          {messages.filter(m => !m.content?.startsWith("Hello! I'm your **Global Supplier Search Agent**")).map((msg, i) => {
            const isUser = msg.role === "user";
            return (
              <div key={i}>
                <div style={{ display: "flex", justifyContent: isUser ? "flex-end" : "flex-start" }}>
                  <div style={{
                    maxWidth: "90%", padding: "10px 14px", fontSize: 13, lineHeight: 1.55, borderRadius: 12,
                    background: isUser ? "#3B82F6" : "#1E293B", color: isUser ? "white" : "#D1D5DB",
                    borderBottomRightRadius: isUser ? 4 : 12, borderBottomLeftRadius: isUser ? 12 : 4,
                    border: isUser ? "none" : "1px solid #374151"
                  }}>
                    {isUser ? msg.content : <div dangerouslySetInnerHTML={{ __html: renderMarkdown(msg.content) }} />}
                  </div>
                </div>
                {!isUser && msg.sources && <div style={{ marginTop: 4 }}><SourcesCard sources={msg.sources} /></div>}
                {!isUser && msg.eliminations && <EliminationCard eliminations={msg.eliminations} />}
              </div>
            );
          })}
          {loading && (
            <div style={{ display: "flex", justifyContent: "flex-start" }}>
              <div style={{ padding: "10px 14px", fontSize: 13, background: "#1E293B", borderRadius: 12, border: "1px solid #374151", color: "#94A3B8" }}>
                <span className="spinning" style={{ display: "inline-block" }}>{"\u23F3"}</span>
                <span style={{ marginLeft: 6 }}>{loadingStatus}</span>
              </div>
            </div>
          )}
          <div ref={chatEndRef} />
        </div>

        {/* Quick actions */}
        {showQuickActions && !loading && (
          <div style={{ display: "flex", flexWrap: "wrap", gap: 4, padding: "6px 12px", background: "#0F172A", borderTop: "1px solid #1E293B" }}>
            {QUICK_ACTIONS.map(action => (
              <button key={action.id} onClick={() => handleQuickAction(action)} style={{
                padding: "4px 10px", background: activeAction?.id === action.id ? "#1E293B" : "transparent",
                border: "1px solid #374151", borderRadius: 6, color: "#94A3B8", fontSize: 11, cursor: "pointer",
                display: "flex", alignItems: "center", gap: 4
              }}>
                <span>{action.icon}</span> {action.label}
              </button>
            ))}
            {onCreateRfq && (
              <button onClick={onCreateRfq} style={{
                padding: "4px 10px", background: "#4C1D95", border: "1px solid #7C3AED", borderRadius: 6,
                color: "#C4B5FD", fontSize: 11, cursor: "pointer", display: "flex", alignItems: "center", gap: 4
              }}>
                {"\uD83D\uDCCB"} Create RFQ
              </button>
            )}
          </div>
        )}

        {/* Active action hint */}
        {activeAction && (
          <div style={{ display: "flex", alignItems: "center", gap: 6, padding: "4px 12px", background: "#1E293B", borderTop: "1px solid #374151", fontSize: 11, color: "#94A3B8" }}>
            <span>{activeAction.icon} <strong style={{ color: "#E2E8F0" }}>{activeAction.label}</strong></span>
            {activeAction.searchEnabled && <span style={{ color: "#64748B" }}>· will search the web</span>}
            <button onClick={() => { setActiveAction(null); setInput(""); }} style={{ marginLeft: "auto", background: "none", border: "none", cursor: "pointer", color: "#6B7280", fontSize: 13 }}>{"\u2715"}</button>
          </div>
        )}

        {/* File preview */}
        {uploadedFile && (
          <div style={{ display: "flex", alignItems: "center", gap: 8, padding: "6px 12px", background: "#064E3B40", borderTop: "1px solid #064E3B", fontSize: 12, color: "#6EE7B7" }}>
            <span>{"\uD83D\uDCC4"} {uploadedFile.filename}</span>
            {uploadedFile.pageCount && <span style={{ color: "#94A3B8" }}>({uploadedFile.pageCount} pages)</span>}
            <button onClick={() => setUploadedFile(null)} style={{ marginLeft: "auto", background: "none", border: "none", cursor: "pointer", color: "#6B7280", fontSize: 14 }}>{"\u2715"}</button>
          </div>
        )}
        {uploadError && (
          <div style={{ padding: "6px 12px", background: "#7F1D1D40", borderTop: "1px solid #7F1D1D", fontSize: 12, color: "#FCA5A5" }}>
            {uploadError}
            <button onClick={() => setUploadError("")} style={{ marginLeft: 8, background: "none", border: "none", cursor: "pointer", color: "#6B7280" }}>{"\u2715"}</button>
          </div>
        )}

        {/* Input */}
        <div style={{ padding: "10px 12px", borderTop: "1px solid #1E293B", background: "#0F172A", display: "flex", gap: 8 }}>
          <input type="file" ref={fileInputRef} accept=".pdf,.docx,.csv,.txt,.xlsx" style={{ display: "none" }} onChange={onFileSelect} />
          <button onClick={() => fileInputRef.current?.click()} disabled={loading} style={{
            padding: "10px 12px", background: uploadedFile ? "#064E3B" : "#1E293B", border: "1px solid #374151",
            borderRadius: 8, fontSize: 16, cursor: loading ? "default" : "pointer", flexShrink: 0, color: "#94A3B8"
          }}><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48"/></svg></button>
          <input
            ref={inputRef}
            value={input}
            onChange={e => setInput(e.target.value)}
            onKeyDown={handleKeyDown}
            placeholder={uploadedFile ? "Add a message about this file..." : "What do you need to source?"}
            disabled={loading}
            style={{ flex: 1, padding: "10px 14px", border: "1px solid #374151", borderRadius: 8, fontSize: 13, outline: "none", background: "#1E293B", color: "#F1F5F9" }}
          />
          <button onClick={onSend} disabled={loading || (!input.trim() && !uploadedFile)} style={{
            padding: "10px 16px", background: loading || (!input.trim() && !uploadedFile) ? "#374151" : "#3B82F6",
            color: "white", border: "none", borderRadius: 8, fontSize: 13, fontWeight: 600,
            cursor: loading || (!input.trim() && !uploadedFile) ? "default" : "pointer"
          }}>
            {activeAction?.searchEnabled ? "Search" : "Send"}
          </button>
        </div>
      </div>

      {/* Right: Map */}
      <div style={{ flex: 1, background: "#0F172A" }}>
        <SupplierMapPanel suppliers={suppliers} onAddToRfq={onAddToRfq} rfqSupplierIds={rfqSupplierIds} quotes={quotes} />
      </div>
    </div>
  );
}

// ─── View 2: RFQ Management ─────────────────────────────────────────────────

function RfqManagementView({ rfqs, setRfqs, suppliers, quotes, setQuotes, modelId, saveRfq, saveQuote, onGoToChat }) {
  const [selectedRfq, setSelectedRfq] = useState(null);
  const [showForm, setShowForm] = useState(false);
  const [formData, setFormData] = useState({ title: "", description: "", quantity: "", targetDate: "", supplierIds: [] });
  const [expandedSupplier, setExpandedSupplier] = useState(null);
  const [uploading, setUploading] = useState(null); // supplierId being uploaded for
  const [demoGenerating, setDemoGenerating] = useState({}); // { [supplierId]: boolean }
  const [demoQuoteError, setDemoQuoteError] = useState({});  // { [supplierId]: string | null }
  const [sortBy, setSortBy] = useState("status"); // "status" | "score" | "price"
  const fileInputRefs = useRef({});

  const statusColors = {
    draft: { bg: "#374151", text: "#9CA3AF", label: "Draft" },
    sent: { bg: "#1E3A5F", text: "#60A5FA", label: "Sent" },
    quotes_received: { bg: "#3B2F08", text: "#FBBF24", label: "Quotes In" },
    closed: { bg: "#064E3B", text: "#6EE7B7", label: "Closed" }
  };

  const supplierStatusOrder = { shortlisted: 0, invited: 1, responded: 2 };

  function getSupplierStatus(supplier, rfq, quotes) {
    const hasQuote = (quotes || []).some(q => q.supplierId === supplier.id || q.supplierName.toLowerCase() === supplier.name.toLowerCase());
    if (hasQuote) return "responded";
    if (rfq.status === "sent" || rfq.status === "quotes_received" || rfq.status === "closed") return "invited";
    return "shortlisted";
  }

  function handleCreate() {
    const newRfq = {
      id: generateId(), title: formData.title || "Untitled RFQ", description: formData.description,
      quantity: parseInt(formData.quantity) || 0, targetDate: formData.targetDate,
      suppliers: formData.supplierIds, status: "draft", createdAt: new Date().toISOString()
    };
    setRfqs(prev => [...prev, newRfq]);
    saveRfq(newRfq);
    setFormData({ title: "", description: "", quantity: "", targetDate: "", supplierIds: [] });
    setShowForm(false);
  }

  function handleStatusChange(rfqId, newStatus) {
    const current = rfqs.find(r => r.id === rfqId);
    setRfqs(prev => prev.map(r => r.id === rfqId ? { ...r, status: newStatus } : r));
    if (current) saveRfq({ ...current, status: newStatus });
  }

  function handleDeleteRfq(rfqId) {
    setRfqs(prev => prev.filter(r => r.id !== rfqId));
    dbDelete("rfqs", rfqId).catch(() => {});
    setSelectedRfq(null);
  }

  function handleUpdateRfqField(rfqId, field, value) {
    const current = rfqs.find(r => r.id === rfqId);
    const coerced = field === "quantity" ? (parseInt(value) || 0) : value;
    setRfqs(prev => prev.map(r => r.id === rfqId ? { ...r, [field]: coerced } : r));
    if (current) saveRfq({ ...current, [field]: coerced });
  }

  function toggleSupplier(supplierId) {
    setFormData(prev => ({
      ...prev,
      supplierIds: prev.supplierIds.includes(supplierId) ? prev.supplierIds.filter(id => id !== supplierId) : [...prev.supplierIds, supplierId]
    }));
  }

  function handleDeleteQuote(quoteId) {
    setQuotes(prev => {
      const updated = prev.filter(q => q.id !== quoteId);
      return updated.map(q => ({ ...q, score: computeQuoteScore(q, updated) }));
    });
    dbDelete("quotes", quoteId).catch(() => {});
  }

  async function scoreQuoteWithLLM(quote, rfq) {
    const context = [
      `Supplier: ${quote.supplierName || "Unknown"}`,
      `Country: ${quote.countryOfOrigin || "Unknown"}`,
      `Unit Price: $${quote.unitPrice ?? "N/A"}`,
      `Lead Time: ${quote.leadTime || "N/A"}`,
      `MOQ: ${quote.moq ?? "N/A"}`,
      `Payment Terms: ${quote.paymentTerms || "N/A"}`,
      `Certifications: ${(quote.certifications || []).join(", ") || "None listed"}`,
      `RFQ Quantity: ${rfq?.quantity || "N/A"}`,
      `RFQ Requirements: ${rfq?.requirements || "None specified"}`
    ].join("\n");
    try {
      const resp = await fetch("/api/chat", {
        method: "POST",
        headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("auth_token")}` },
        body: JSON.stringify({
          model: modelId,
          messages: [
            { role: "system", content: SUPPLIER_SCORING_PROMPT },
            { role: "user", content: context }
          ]
        })
      });
      const data = await resp.json();
      const text = data.choices?.[0]?.message?.content || "";
      const match = text.match(/```score-data\n([\s\S]*?)\n```/);
      if (match) return JSON.parse(match[1]);
    } catch (e) {}
    return null;
  }

  async function handleQuoteUpload(e, supplier, rfqId) {
    const file = e.target.files[0];
    if (!file) return;
    setUploading(supplier.id);
    try {
      const parsed = await parseUploadedFile(file);
      const truncated = parsed.text.length > 12000 ? parsed.text.slice(0, 12000) + "\n...[truncated]" : parsed.text;
      const res = await fetch("/api/chat", {
        method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("auth_token")}` },
        body: JSON.stringify({
          model: modelId,
          messages: [
            { role: "system", content: QUOTE_EXTRACTION_PROMPT },
            { role: "user", content: `Extract quote data from this document:\n\n--- ${parsed.filename} ---\n${truncated}\n--- END ---` }
          ]
        })
      });
      if (!res.ok) throw new Error("API error");
      const data = await res.json();
      const reply = data.choices?.[0]?.message?.content || "";
      const extracted = extractQuoteData(reply);

      if (extracted) {
        const category = classifyCountry(extracted.countryOfOrigin || supplier.country || "");
        const newQuote = {
          id: generateId(), rfqId, supplierId: supplier.id,
          supplierName: extracted.supplierName || supplier.name,
          unitPrice: parseFloat(extracted.unitPrice) || 0,
          totalPrice: parseFloat(extracted.totalPrice) || 0,
          leadTime: extracted.leadTime || "",
          moq: parseInt(extracted.moq) || 0,
          paymentTerms: extracted.paymentTerms || "",
          shippingTerms: extracted.shippingTerms || "",
          certifications: extracted.certifications || [],
          countryOfOrigin: extracted.countryOfOrigin || supplier.country || "",
          category, validUntil: extracted.validUntil || "",
          notes: extracted.notes || "", score: 0,
          rawDocument: truncated, filename: parsed.filename
        };
        const allQuotes = [...quotes, newQuote];
        const computedScore = computeQuoteScore(newQuote, allQuotes);
        const quoteToSave = { ...newQuote, score: computedScore };
        setQuotes(prev => {
          const updated = [...prev, quoteToSave];
          return updated.map(q => ({ ...q, score: computeQuoteScore(q, updated) }));
        });
        saveQuote(quoteToSave);
        // Auto-score with LLM (async, non-blocking)
        const rfqObj = rfqs.find(r => r.id === rfqId);
        scoreQuoteWithLLM(quoteToSave, rfqObj).then(scoreResult => {
          if (!scoreResult) return;
          const scoredQuote = { ...quoteToSave, llmScore: scoreResult.overall, llmBreakdown: scoreResult.breakdown, llmSummary: scoreResult.summary };
          setQuotes(prev => prev.map(q => q.id === quoteToSave.id ? scoredQuote : q));
          saveQuote(scoredQuote);
        }).catch(() => {});
        // Also save updated RFQ status if it changed
        if (rfqObj && rfqObj.status === "sent") saveRfq({ ...rfqObj, status: "quotes_received" });
        // Auto-update RFQ status
        if (rfqId) {
          setRfqs(prev => prev.map(r => {
            if (r.id === rfqId && r.status === "sent") return { ...r, status: "quotes_received" };
            return r;
          }));
        }
        setExpandedSupplier(supplier.id);
      }
    } catch (err) {
      console.error("Quote upload error:", err);
    } finally {
      setUploading(null);
      e.target.value = "";
    }
  }

  async function handleDemoQuote(supplier, rfqId) {
    const rfqObj = rfqs.find(r => r.id === rfqId);
    if (!rfqObj) return;
    const prompt = DEMO_QUOTE_PROMPT
      .replace("{supplierName}", supplier.name || "Unknown Supplier")
      .replace("{country}", supplier.country || "Unknown")
      .replace("{region}", supplier.category || "offshore")
      .replace("{capabilities}", supplier.capabilities || "General manufacturing")
      .replace("{certifications}", (supplier.certifications || []).join(", ") || "None listed")
      .replace("{unitPrice}", supplier.unitPrice != null ? `$${supplier.unitPrice}` : "unknown")
      .replace("{rfqDescription}", rfqObj?.description || "")
      .replace("{quantity}", rfqObj?.quantity || "unspecified")
      .replace("{requirements}", rfqObj?.requirements || "None specified")
      .replace("{todayISO}", new Date().toISOString().slice(0, 10));

    setUploading(supplier.id);
    setDemoGenerating(prev => ({ ...prev, [supplier.id]: true }));
    try {
      const res = await fetch("/api/chat", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "Authorization": `Bearer ${localStorage.getItem("auth_token")}`
        },
        body: JSON.stringify({
          model: modelId,
          messages: [{ role: "user", content: prompt }]
        })
      });
      if (!res.ok) throw new Error("API error");
      const data = await res.json();
      const reply = data.choices?.[0]?.message?.content || "";
      const extracted = extractQuoteData(reply);

      if (extracted) {
        const category = classifyCountry(extracted.countryOfOrigin || supplier.country || "");
        const newQuote = {
          id: generateId(), rfqId, supplierId: supplier.id,
          supplierName: extracted.supplierName || supplier.name,
          unitPrice: parseFloat(extracted.unitPrice) || 0,
          totalPrice: parseFloat(extracted.totalPrice) || 0,
          leadTime: extracted.leadTime || "",
          moq: parseInt(extracted.moq) || 0,
          paymentTerms: extracted.paymentTerms || "",
          shippingTerms: extracted.shippingTerms || "",
          certifications: extracted.certifications || [],
          countryOfOrigin: extracted.countryOfOrigin || supplier.country || "",
          category, validUntil: extracted.validUntil || "",
          notes: extracted.notes || "", score: 0,
          filename: "Demo Quote (AI Generated)"
        };
        const allQuotes = [...quotes, newQuote];
        const computedScore = computeQuoteScore(newQuote, allQuotes);
        const quoteToSave = { ...newQuote, score: computedScore };
        setQuotes(prev => {
          const updated = [...prev, quoteToSave];
          return updated.map(q => ({ ...q, score: computeQuoteScore(q, updated) }));
        });
        saveQuote(quoteToSave);
        scoreQuoteWithLLM(quoteToSave, rfqObj).then(scoreResult => {
          if (!scoreResult) return;
          const scoredQuote = { ...quoteToSave, llmScore: scoreResult.overall, llmBreakdown: scoreResult.breakdown, llmSummary: scoreResult.summary };
          setQuotes(prev => prev.map(q => q.id === quoteToSave.id ? scoredQuote : q));
          saveQuote(scoredQuote);
        }).catch(() => {});
        if (rfqObj && rfqObj.status === "sent") saveRfq({ ...rfqObj, status: "quotes_received" });
        if (rfqId) {
          setRfqs(prev => prev.map(r => {
            if (r.id === rfqId && r.status === "sent") return { ...r, status: "quotes_received" };
            return r;
          }));
        }
        setExpandedSupplier(supplier.id);
        setDemoQuoteError(prev => ({ ...prev, [supplier.id]: null }));
      } else {
        throw new Error("No quote data returned");
      }
    } catch (err) {
      console.error("Demo quote error:", err);
      setDemoQuoteError(prev => ({ ...prev, [supplier.id]: err.message }));
    } finally {
      setUploading(null);
      setDemoGenerating(prev => ({ ...prev, [supplier.id]: false }));
    }
  }

  // RFQ Detail View
  if (selectedRfq) {
    const rfq = rfqs.find(r => r.id === selectedRfq);
    if (!rfq) { setSelectedRfq(null); return null; }
    const rfqSuppliers = suppliers.filter(s => rfq.suppliers.includes(s.id));
    const st = statusColors[rfq.status] || statusColors.draft;

    // Sort suppliers
    const sortedSuppliers = [...rfqSuppliers].sort((a, b) => {
      const aStatus = getSupplierStatus(a, rfq, quotes);
      const bStatus = getSupplierStatus(b, rfq, quotes);
      if (sortBy === "status") {
        return (supplierStatusOrder[aStatus] || 2) - (supplierStatusOrder[bStatus] || 2);
      }
      if (sortBy === "score") {
        const aQuote = (quotes || []).find(q => q.supplierId === a.id);
        const bQuote = (quotes || []).find(q => q.supplierId === b.id);
        return (bQuote?.score || 0) - (aQuote?.score || 0);
      }
      if (sortBy === "price") {
        const aQuote = (quotes || []).find(q => q.supplierId === a.id);
        const bQuote = (quotes || []).find(q => q.supplierId === b.id);
        return (aQuote?.unitPrice || Infinity) - (bQuote?.unitPrice || Infinity);
      }
      return 0;
    });

    const quotedCount = rfqSuppliers.filter(s => (quotes || []).some(q => q.supplierId === s.id || q.supplierName.toLowerCase() === s.name.toLowerCase())).length;

    return (
      <div style={{ flex: 1, overflowY: "auto", padding: 24, background: "#111827" }}>
        <button onClick={() => setSelectedRfq(null)} style={{ background: "none", border: "none", color: "#60A5FA", cursor: "pointer", fontSize: 13, marginBottom: 16, display: "flex", alignItems: "center", gap: 4 }}>
          {"\u2190"} Back to RFQs
        </button>

        {/* Editable header */}
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "start", marginBottom: 20 }}>
          <div style={{ flex: 1 }}>
            <input value={rfq.title} onChange={e => handleUpdateRfqField(rfq.id, "title", e.target.value)}
              style={{ fontSize: 22, fontWeight: 700, color: "#F1F5F9", background: "transparent", border: "none", borderBottom: "1px solid transparent", outline: "none", width: "100%", padding: "2px 0" }}
              onFocus={e => e.target.style.borderBottomColor = "#3B82F6"} onBlur={e => e.target.style.borderBottomColor = "transparent"} />
            <textarea value={rfq.description || ""} onChange={e => handleUpdateRfqField(rfq.id, "description", e.target.value)}
              placeholder="Add description / specifications..."
              rows={2} style={{ color: "#94A3B8", fontSize: 13, marginTop: 4, background: "transparent", border: "none", borderBottom: "1px solid transparent", outline: "none", width: "100%", resize: "none", padding: "2px 0", fontFamily: "inherit" }}
              onFocus={e => e.target.style.borderBottomColor = "#3B82F6"} onBlur={e => e.target.style.borderBottomColor = "transparent"} />
            {/* Requirements */}
            <div style={{ marginTop: 10 }}>
              <div style={{ fontSize: 10, fontWeight: 600, color: "#64748B", textTransform: "uppercase", marginBottom: 4 }}>Requirements</div>
              <textarea
                value={rfq.requirements || ""}
                onChange={e => handleUpdateRfqField(rfq.id, "requirements", e.target.value)}
                placeholder="Technical or compliance requirements (certifications, materials, specs)..."
                rows={2}
                style={{ color: "#94A3B8", fontSize: 13, background: "transparent", border: "none", borderBottom: "1px solid transparent", outline: "none", width: "100%", resize: "none", padding: "2px 0", fontFamily: "inherit" }}
                onFocus={e => e.target.style.borderBottomColor = "#3B82F6"}
                onBlur={e => e.target.style.borderBottomColor = "transparent"}
              />
            </div>
          </div>
          <span style={{ padding: "4px 12px", borderRadius: 6, fontSize: 12, fontWeight: 600, background: st.bg, color: st.text, flexShrink: 0, marginLeft: 12 }}>{st.label}</span>
        </div>

        {/* Editable stats */}
        <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 12, marginBottom: 20 }}>
          <div style={{ background: "#1E293B", borderRadius: 10, padding: 14, border: "1px solid #374151" }}>
            <div style={{ fontSize: 10, fontWeight: 600, color: "#64748B", textTransform: "uppercase" }}>Quantity</div>
            <input value={rfq.quantity || ""} onChange={e => handleUpdateRfqField(rfq.id, "quantity", e.target.value)}
              type="number" placeholder="TBD"
              style={{ fontSize: 20, fontWeight: 700, color: "#F1F5F9", marginTop: 4, background: "transparent", border: "none", outline: "none", width: "100%", padding: 0 }} />
          </div>
          <div style={{ background: "#1E293B", borderRadius: 10, padding: 14, border: "1px solid #374151" }}>
            <div style={{ fontSize: 10, fontWeight: 600, color: "#64748B", textTransform: "uppercase" }}>Target Date</div>
            <input value={rfq.targetDate || ""} onChange={e => handleUpdateRfqField(rfq.id, "targetDate", e.target.value)}
              type="date"
              style={{ fontSize: 14, fontWeight: 600, color: "#F1F5F9", marginTop: 6, background: "transparent", border: "none", outline: "none", width: "100%", padding: 0 }} />
          </div>
          <div style={{ background: "#1E293B", borderRadius: 10, padding: 14, border: "1px solid #374151" }}>
            <div style={{ fontSize: 10, fontWeight: 600, color: "#64748B", textTransform: "uppercase" }}>Quote Coverage</div>
            <div style={{ fontSize: 20, fontWeight: 700, color: "#F1F5F9", marginTop: 4 }}>{quotedCount} / {rfqSuppliers.length}</div>
            <div style={{ width: "100%", height: 4, background: "#374151", borderRadius: 2, marginTop: 4 }}>
              <div style={{ width: `${rfqSuppliers.length > 0 ? (quotedCount / rfqSuppliers.length * 100) : 0}%`, height: "100%", background: quotedCount === rfqSuppliers.length ? "#22C55E" : "#3B82F6", borderRadius: 2, transition: "width 0.3s" }} />
            </div>
          </div>
        </div>

        {/* Action buttons */}
        <div style={{ display: "flex", gap: 8, marginBottom: 16, flexWrap: "wrap" }}>
          {rfq.status === "draft" && (
            <button onClick={() => handleStatusChange(rfq.id, "sent")} style={{ padding: "8px 16px", background: "#3B82F6", color: "white", border: "none", borderRadius: 8, fontSize: 13, fontWeight: 600, cursor: "pointer" }}>
              Send RFQ to Suppliers
            </button>
          )}
          {rfq.status === "sent" && (
            <button onClick={() => handleStatusChange(rfq.id, "quotes_received")} style={{ padding: "8px 16px", background: "#F59E0B", color: "#1E293B", border: "none", borderRadius: 8, fontSize: 13, fontWeight: 600, cursor: "pointer" }}>
              Mark Quotes Received
            </button>
          )}
          {(rfq.status === "quotes_received" || rfq.status === "sent") && (
            <button onClick={() => handleStatusChange(rfq.id, "closed")} style={{ padding: "8px 16px", background: "#22C55E", color: "white", border: "none", borderRadius: 8, fontSize: 13, fontWeight: 600, cursor: "pointer" }}>
              Close RFQ
            </button>
          )}
          <button onClick={() => handleDeleteRfq(rfq.id)} style={{ padding: "8px 16px", background: "transparent", color: "#EF4444", border: "1px solid #EF444440", borderRadius: 8, fontSize: 13, cursor: "pointer", marginLeft: "auto" }}>
            Delete RFQ
          </button>
        </div>

        {/* Sort controls */}
        <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 12 }}>
          <span style={{ fontSize: 12, color: "#64748B" }}>Sort by:</span>
          {[{ id: "status", label: "Status" }, { id: "score", label: "Score" }, { id: "price", label: "Price" }].map(s => (
            <button key={s.id} onClick={() => setSortBy(s.id)} style={{
              padding: "4px 10px", borderRadius: 6, fontSize: 11, fontWeight: 600, cursor: "pointer", border: "none",
              background: sortBy === s.id ? "#3B82F6" : "#1E293B", color: sortBy === s.id ? "white" : "#94A3B8"
            }}>{s.label}</button>
          ))}
        </div>

        {/* Supplier cards */}
        <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
          {sortedSuppliers.length === 0 ? (
            <div style={{ color: "#64748B", fontSize: 13, textAlign: "center", padding: 40 }}>
              No suppliers added yet.{" "}
              <button onClick={onGoToChat} style={{ background: "none", border: "none", color: "#3B82F6", cursor: "pointer", fontSize: 13, textDecoration: "underline", padding: 0 }}>
                Go to Chat &amp; Discovery
              </button>
              {" "}to search for suppliers, then click a map pin to add them here.
            </div>
          ) : sortedSuppliers.map(s => {
            const status = getSupplierStatus(s, rfq, quotes);
            const supplierQuotes = (quotes || []).filter(q => q.supplierId === s.id || q.supplierName.toLowerCase() === s.name.toLowerCase());
            const bestQuote = supplierQuotes.length > 0 ? supplierQuotes.reduce((a, b) => a.score > b.score ? a : b) : null;
            const isExpanded = expandedSupplier === s.id;
            const statusBadge = {
              responded: { bg: "#064E3B", text: "#6EE7B7", label: "Responded" },
              invited: { bg: "#1E3A5F", text: "#60A5FA", label: "Invited" },
              shortlisted: { bg: "#374151", text: "#9CA3AF", label: "Shortlisted" }
            }[status];

            return (
              <div key={s.id} style={{ background: "#1E293B", borderRadius: 12, border: isExpanded ? "1px solid #3B82F6" : "1px solid #374151", overflow: "hidden", transition: "border-color 0.15s" }}>
                {/* Card header - always visible */}
                <div onClick={() => setExpandedSupplier(isExpanded ? null : s.id)} style={{
                  display: "flex", alignItems: "center", gap: 12, padding: "14px 16px", cursor: "pointer"
                }}>
                  <div style={{ width: 36, height: 36, borderRadius: 10, background: bestQuote ? "#064E3B" : "#374151", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 15, fontWeight: 700, color: "#E2E8F0", flexShrink: 0 }}>
                    {bestQuote ? "\u2713" : s.name.charAt(0)}
                  </div>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontWeight: 600, color: "#F1F5F9", fontSize: 14 }}>{s.name}</div>
                    <div style={{ fontSize: 11, color: "#64748B" }}>{s.country} {"\u2022"} {s.category || classifyCountry(s.country)}</div>
                  </div>
                  <span style={{ padding: "3px 10px", borderRadius: 6, fontSize: 10, fontWeight: 600, background: statusBadge.bg, color: statusBadge.text }}>{statusBadge.label}</span>
                  {(() => {
                    const sq = (quotes || []).find(q => q.supplierId === s.id);
                    if (!sq) return null;
                    const displayScore = sq.llmScore ?? (sq.score > 0 ? sq.score : null);
                    if (displayScore != null) {
                      const color = displayScore >= 70 ? { bg: "#064E3B", text: "#6EE7B7" } : displayScore >= 40 ? { bg: "#3B2F08", text: "#FBBF24" } : { bg: "#7F1D1D", text: "#FCA5A5" };
                      return <span style={{ padding: "2px 8px", borderRadius: 10, fontSize: 11, fontWeight: 700, background: color.bg, color: color.text }}>{displayScore}/100</span>;
                    }
                    const hasQuote = (quotes || []).some(q => q.supplierId === s.id);
                    return hasQuote ? <span style={{ fontSize: 11, color: "#4B5563" }}>Scoring…</span> : null;
                  })()}
                  {bestQuote && (
                    <div style={{ textAlign: "right", marginRight: 8 }}>
                      <div style={{ fontWeight: 800, color: "#6EE7B7", fontSize: 18 }}>${bestQuote.unitPrice.toFixed(2)}</div>
                      <div style={{ fontSize: 10, color: "#94A3B8" }}>Score: {bestQuote.llmScore ?? bestQuote.score}</div>
                    </div>
                  )}
                  <span style={{ color: "#64748B", fontSize: 14, transition: "transform 0.2s", transform: isExpanded ? "rotate(180deg)" : "rotate(0)" }}>{"\u25BC"}</span>
                </div>

                {/* Expanded content */}
                {isExpanded && (
                  <div style={{ borderTop: "1px solid #374151", padding: 16 }}>
                    {/* Quotes for this supplier */}
                    {supplierQuotes.length > 0 ? (
                      <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
                        {supplierQuotes.map(q => (
                          <div key={q.id} style={{ background: "#0F172A", borderRadius: 8, padding: 14, border: "1px solid #374151" }}>
                            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "start", marginBottom: 10 }}>
                              <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                                <span style={{ fontSize: 13, fontWeight: 700, color: "#F1F5F9" }}>Quote</span>
                                {q.filename && <span style={{ fontSize: 10, color: "#64748B", background: "#374151", padding: "1px 6px", borderRadius: 4 }}>{q.filename}</span>}
                              </div>
                              <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                                <div style={{
                                  padding: "2px 10px", borderRadius: 10, fontSize: 12, fontWeight: 700,
                                  background: q.score >= 70 ? "#064E3B" : q.score >= 40 ? "#3B2F08" : "#7F1D1D20",
                                  color: q.score >= 70 ? "#6EE7B7" : q.score >= 40 ? "#FBBF24" : "#FCA5A5"
                                }}>{q.score}/100</div>
                                <button onClick={(e) => { e.stopPropagation(); handleDeleteQuote(q.id); }} style={{
                                  background: "none", border: "none", color: "#EF4444", cursor: "pointer", fontSize: 14, padding: "2px 6px", borderRadius: 4
                                }} title="Delete quote">{"\u2715"}</button>
                              </div>
                            </div>
                            <div style={{ display: "grid", gridTemplateColumns: "repeat(4, 1fr)", gap: 10 }}>
                              <div><div style={{ fontSize: 9, color: "#64748B", textTransform: "uppercase", fontWeight: 600 }}>Unit Price</div><div style={{ fontSize: 16, fontWeight: 800, color: "#6EE7B7" }}>${q.unitPrice.toFixed(2)}</div></div>
                              <div><div style={{ fontSize: 9, color: "#64748B", textTransform: "uppercase", fontWeight: 600 }}>Lead Time</div><div style={{ fontSize: 13, fontWeight: 600, color: "#E2E8F0" }}>{q.leadTime || "N/A"}</div></div>
                              <div><div style={{ fontSize: 9, color: "#64748B", textTransform: "uppercase", fontWeight: 600 }}>MOQ</div><div style={{ fontSize: 13, fontWeight: 600, color: "#E2E8F0" }}>{q.moq ? q.moq.toLocaleString() : "N/A"}</div></div>
                              <div><div style={{ fontSize: 9, color: "#64748B", textTransform: "uppercase", fontWeight: 600 }}>Payment</div><div style={{ fontSize: 13, fontWeight: 600, color: "#E2E8F0" }}>{q.paymentTerms || "N/A"}</div></div>
                            </div>
                            {(q.certifications?.length > 0 || q.shippingTerms || q.countryOfOrigin) && (
                              <div style={{ display: "flex", gap: 8, marginTop: 8, flexWrap: "wrap" }}>
                                {q.countryOfOrigin && <span style={{ fontSize: 10, color: "#94A3B8", background: "#374151", padding: "2px 6px", borderRadius: 4 }}>Origin: {q.countryOfOrigin}</span>}
                                {q.shippingTerms && <span style={{ fontSize: 10, color: "#94A3B8", background: "#374151", padding: "2px 6px", borderRadius: 4 }}>{q.shippingTerms}</span>}
                                {(q.certifications || []).map((c, i) => <span key={i} style={{ fontSize: 10, color: "#60A5FA", background: "#1E3A5F", padding: "2px 6px", borderRadius: 4 }}>{c}</span>)}
                              </div>
                            )}
                            {q.notes && <div style={{ fontSize: 11, color: "#94A3B8", marginTop: 6, fontStyle: "italic" }}>{q.notes}</div>}
                          </div>
                        ))}
                      </div>
                    ) : (
                      <div style={{ color: "#64748B", fontSize: 12, textAlign: "center", padding: "12px 0" }}>No quotes uploaded yet</div>
                    )}

                    {/* Upload & Demo buttons */}
                    <div style={{ marginTop: 10 }}>
                      {/* File upload */}
                      <input type="file" accept=".pdf,.docx,.xlsx,.csv,.txt" style={{ display: "none" }}
                        ref={el => { if (el) fileInputRefs.current[s.id] = el; }}
                        onChange={e => handleQuoteUpload(e, s, rfq.id)} />
                      <button onClick={() => fileInputRefs.current[s.id]?.click()}
                        disabled={uploading === s.id}
                        style={{
                          padding: "8px 16px", background: (uploading === s.id && !demoGenerating[s.id]) ? "#374151" : "#1E293B",
                          color: "#E2E8F0", border: "1px dashed #4B5563", borderRadius: 8, fontSize: 12,
                          cursor: uploading === s.id ? "default" : "pointer", width: "100%",
                          display: "flex", alignItems: "center", justifyContent: "center", gap: 6
                        }}>
                        {uploading === s.id && !demoGenerating[s.id] ? (
                          <><span className="spinning" style={{ display: "inline-block" }}>{"\u23F3"}</span> Extracting quote data...</>
                        ) : (
                          <><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg> Upload Quote Document</>
                        )}
                      </button>

                      {/* Or divider */}
                      <div style={{ display: "flex", alignItems: "center", gap: 8, margin: "8px 0" }}>
                        <div style={{ flex: 1, height: 1, background: "#374151" }} />
                        <span style={{ fontSize: 11, color: "#4B5563" }}>or</span>
                        <div style={{ flex: 1, height: 1, background: "#374151" }} />
                      </div>

                      {/* Demo button */}
                      <button onClick={() => handleDemoQuote(s, rfq.id)}
                        disabled={uploading === s.id}
                        style={{
                          padding: "8px 16px", background: (uploading === s.id && demoGenerating[s.id]) ? "#374151" : "#0F2B1A",
                          color: "#6EE7B7", border: "1px dashed #065F46", borderRadius: 8, fontSize: 12,
                          cursor: uploading === s.id ? "default" : "pointer", width: "100%",
                          display: "flex", alignItems: "center", justifyContent: "center", gap: 6
                        }}>
                        {uploading === s.id && demoGenerating[s.id] ? (
                          <><span className="spinning" style={{ display: "inline-block" }}>{"\u23F3"}</span> Generating...</>
                        ) : (
                          <><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg> Load Demo Quote</>
                        )}
                      </button>

                      {/* Demo error */}
                      {demoQuoteError[s.id] && (
                        <div style={{ marginTop: 6, fontSize: 11, color: "#FCA5A5", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                          <span>Error: {demoQuoteError[s.id]}</span>
                          <button onClick={() => setDemoQuoteError(prev => ({ ...prev, [s.id]: null }))}
                            style={{ background: "none", border: "none", cursor: "pointer", color: "#6B7280", fontSize: 12 }}>&times;</button>
                        </div>
                      )}

                      {/* Sample PDF download link */}
                      <div style={{ marginTop: 8, textAlign: "center" }}>
                        <a href="/sample-quote.pdf" download
                          style={{ fontSize: 11, color: "#64748B", textDecoration: "none" }}
                          onMouseOver={e => e.currentTarget.style.color = "#94A3B8"}
                          onMouseOut={e => e.currentTarget.style.color = "#64748B"}>
                          Download sample PDF for upload
                        </a>
                      </div>
                    </div>
                    {(() => {
                      const sq = (quotes || []).find(q => q.supplierId === s.id);
                      if (!sq?.llmBreakdown) return null;
                      const dims = [
                        { key: "price", label: "Price Competitiveness" },
                        { key: "leadTime", label: "Lead Time" },
                        { key: "certifications", label: "Certifications" },
                        { key: "riskProfile", label: "Risk Profile" },
                        { key: "paymentTerms", label: "Payment Terms" }
                      ];
                      return (
                        <div style={{ marginTop: 14, background: "#0F172A", borderRadius: 8, padding: 12, border: "1px solid #1E293B" }}>
                          <div style={{ fontSize: 12, fontWeight: 700, color: "#94A3B8", marginBottom: 10 }}>AI Assessment</div>
                          {dims.map(({ key, label }) => {
                            const val = sq.llmBreakdown[key] || 0;
                            const barColor = val >= 70 ? "#10B981" : val >= 40 ? "#F59E0B" : "#EF4444";
                            const textColor = val >= 70 ? "#6EE7B7" : val >= 40 ? "#FBBF24" : "#FCA5A5";
                            return (
                              <div key={key} style={{ marginBottom: 8 }}>
                                <div style={{ display: "flex", justifyContent: "space-between", marginBottom: 3 }}>
                                  <span style={{ fontSize: 11, color: "#94A3B8" }}>{label}</span>
                                  <span style={{ fontSize: 11, fontWeight: 700, color: textColor }}>{val}</span>
                                </div>
                                <div style={{ height: 4, background: "#374151", borderRadius: 2 }}>
                                  <div style={{ height: 4, borderRadius: 2, width: `${val}%`, background: barColor }} />
                                </div>
                              </div>
                            );
                          })}
                          {sq.llmSummary && <div style={{ marginTop: 8, fontSize: 12, color: "#94A3B8", lineHeight: 1.6 }}>{sq.llmSummary}</div>}
                          <button
                            onClick={(e) => {
                              e.stopPropagation();
                              const rfqObj = rfqs.find(r => r.id === selectedRfq);
                              scoreQuoteWithLLM(sq, rfqObj).then(result => {
                                if (!result) return;
                                const updated = { ...sq, llmScore: result.overall, llmBreakdown: result.breakdown, llmSummary: result.summary };
                                setQuotes(prev => prev.map(q => q.id === sq.id ? updated : q));
                                saveQuote(updated);
                              }).catch(() => {});
                            }}
                            style={{ marginTop: 8, fontSize: 11, color: "#3B82F6", background: "none", border: "1px solid #1E3A5F", borderRadius: 4, padding: "3px 8px", cursor: "pointer" }}
                          >
                            ↻ Re-score
                          </button>
                        </div>
                      );
                    })()}
                  </div>
                )}
              </div>
            );
          })}
        </div>
      </div>
    );
  }

  // RFQ List View
  return (
    <div style={{ flex: 1, overflowY: "auto", padding: 24, background: "#111827" }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 20 }}>
        <div>
          <h2 style={{ fontSize: 20, fontWeight: 700, color: "#F1F5F9", margin: 0 }}>RFQ Management</h2>
          <p style={{ color: "#94A3B8", fontSize: 13, marginTop: 4 }}>Create and manage Requests for Quotation</p>
        </div>
        <button onClick={() => setShowForm(!showForm)} style={{
          padding: "8px 16px", background: "#3B82F6", color: "white", border: "none", borderRadius: 8,
          fontSize: 13, fontWeight: 600, cursor: "pointer", display: "flex", alignItems: "center", gap: 6
        }}>
          + Create New RFQ
        </button>
      </div>

      {/* Create form */}
      {showForm && (
        <div style={{ background: "#1E293B", borderRadius: 12, padding: 20, marginBottom: 20, border: "1px solid #374151" }}>
          <h3 style={{ fontSize: 15, fontWeight: 600, color: "#F1F5F9", marginBottom: 14, marginTop: 0 }}>New RFQ</h3>
          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
            <div>
              <label style={{ fontSize: 11, fontWeight: 600, color: "#94A3B8", display: "block", marginBottom: 4, textTransform: "uppercase" }}>Part / Component Name</label>
              <input value={formData.title} onChange={e => setFormData(p => ({ ...p, title: e.target.value }))} placeholder="e.g. CNC Aluminum Housing" style={{ width: "100%", padding: "8px 12px", background: "#0F172A", border: "1px solid #374151", borderRadius: 6, color: "#F1F5F9", fontSize: 13, boxSizing: "border-box" }} />
            </div>
            <div>
              <label style={{ fontSize: 11, fontWeight: 600, color: "#94A3B8", display: "block", marginBottom: 4, textTransform: "uppercase" }}>Quantity</label>
              <input value={formData.quantity} onChange={e => setFormData(p => ({ ...p, quantity: e.target.value }))} type="number" placeholder="e.g. 5000" style={{ width: "100%", padding: "8px 12px", background: "#0F172A", border: "1px solid #374151", borderRadius: 6, color: "#F1F5F9", fontSize: 13, boxSizing: "border-box" }} />
            </div>
            <div style={{ gridColumn: "span 2" }}>
              <label style={{ fontSize: 11, fontWeight: 600, color: "#94A3B8", display: "block", marginBottom: 4, textTransform: "uppercase" }}>Description / Specifications</label>
              <textarea value={formData.description} onChange={e => setFormData(p => ({ ...p, description: e.target.value }))} rows={3} placeholder="Material requirements, tolerances, surface finish..." style={{ width: "100%", padding: "8px 12px", background: "#0F172A", border: "1px solid #374151", borderRadius: 6, color: "#F1F5F9", fontSize: 13, resize: "vertical", boxSizing: "border-box" }} />
            </div>
            <div>
              <label style={{ fontSize: 11, fontWeight: 600, color: "#94A3B8", display: "block", marginBottom: 4, textTransform: "uppercase" }}>Target Delivery Date</label>
              <input value={formData.targetDate} onChange={e => setFormData(p => ({ ...p, targetDate: e.target.value }))} type="date" style={{ width: "100%", padding: "8px 12px", background: "#0F172A", border: "1px solid #374151", borderRadius: 6, color: "#F1F5F9", fontSize: 13, boxSizing: "border-box" }} />
            </div>
          </div>

          {/* Supplier selection */}
          {suppliers.length > 0 && (
            <div style={{ marginTop: 14 }}>
              <label style={{ fontSize: 11, fontWeight: 600, color: "#94A3B8", display: "block", marginBottom: 6, textTransform: "uppercase" }}>Select Suppliers ({formData.supplierIds.length} selected)</label>
              <div style={{ maxHeight: 200, overflowY: "auto", display: "flex", flexDirection: "column", gap: 4, background: "#0F172A", borderRadius: 8, padding: 8, border: "1px solid #374151" }}>
                {suppliers.filter(s => !s.eliminated).map(s => {
                  const selected = formData.supplierIds.includes(s.id);
                  return (
                    <div key={s.id} onClick={() => toggleSupplier(s.id)} style={{
                      display: "flex", alignItems: "center", gap: 8, padding: "6px 10px", borderRadius: 6,
                      cursor: "pointer", background: selected ? "#1E3A5F" : "transparent",
                      border: selected ? "1px solid #3B82F6" : "1px solid transparent"
                    }}>
                      <div style={{ width: 16, height: 16, borderRadius: 4, border: selected ? "none" : "1px solid #4B5563", background: selected ? "#3B82F6" : "transparent", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 10, color: "white", flexShrink: 0 }}>
                        {selected && "\u2713"}
                      </div>
                      <span style={{ fontSize: 12, color: "#E2E8F0", fontWeight: 500 }}>{s.name}</span>
                      <span style={{ fontSize: 10, color: "#64748B", marginLeft: "auto" }}>{s.country}</span>
                      <span style={{
                        fontSize: 9, padding: "1px 5px", borderRadius: 4, fontWeight: 600,
                        background: s.category === "domestic" ? "#064E3B" : s.category === "nearshore" ? "#1E3A5F" : "#3B2F08",
                        color: s.category === "domestic" ? "#6EE7B7" : s.category === "nearshore" ? "#60A5FA" : "#FBBF24"
                      }}>{s.category}</span>
                    </div>
                  );
                })}
              </div>
            </div>
          )}

          <div style={{ display: "flex", gap: 8, marginTop: 14 }}>
            <button onClick={handleCreate} disabled={!formData.title.trim()} style={{
              padding: "8px 20px", background: !formData.title.trim() ? "#374151" : "#3B82F6", color: "white",
              border: "none", borderRadius: 8, fontSize: 13, fontWeight: 600, cursor: !formData.title.trim() ? "default" : "pointer"
            }}>Create RFQ</button>
            <button onClick={() => setShowForm(false)} style={{ padding: "8px 20px", background: "transparent", color: "#94A3B8", border: "1px solid #374151", borderRadius: 8, fontSize: 13, cursor: "pointer" }}>Cancel</button>
          </div>
        </div>
      )}

      {/* RFQ list */}
      {rfqs.length === 0 ? (
        <div style={{ textAlign: "center", padding: "60px 0", color: "#64748B" }}>
          <div style={{ fontSize: 40, marginBottom: 12 }}>{"\uD83D\uDCCB"}</div>
          <div style={{ fontSize: 16, fontWeight: 500, color: "#94A3B8" }}>No RFQs yet</div>
          <div style={{ fontSize: 13, marginTop: 4 }}>Create an RFQ or add suppliers from the map to get started</div>
        </div>
      ) : (
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(300px, 1fr))", gap: 12 }}>
          {rfqs.map(rfq => {
            const st = statusColors[rfq.status] || statusColors.draft;
            const supplierCount = rfq.suppliers.length;
            const quotedCount = rfq.suppliers.filter(sid => (quotes || []).some(q => q.supplierId === sid)).length;
            return (
              <div key={rfq.id} onClick={() => setSelectedRfq(rfq.id)} style={{
                background: "#1E293B", borderRadius: 12, padding: 16, border: "1px solid #374151",
                cursor: "pointer", transition: "border-color 0.15s"
              }} onMouseEnter={e => e.currentTarget.style.borderColor = "#3B82F6"} onMouseLeave={e => e.currentTarget.style.borderColor = "#374151"}>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "start", marginBottom: 8 }}>
                  <h3 style={{ fontSize: 15, fontWeight: 600, color: "#F1F5F9", margin: 0 }}>{rfq.title}</h3>
                  <span style={{ padding: "2px 8px", borderRadius: 4, fontSize: 10, fontWeight: 600, background: st.bg, color: st.text, flexShrink: 0 }}>{st.label}</span>
                </div>
                <p style={{ fontSize: 12, color: "#64748B", margin: "0 0 10px", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{rfq.description || "No description"}</p>
                <div style={{ display: "flex", gap: 16, fontSize: 11, color: "#94A3B8" }}>
                  <span>{supplierCount} supplier{supplierCount !== 1 ? "s" : ""}</span>
                  {quotedCount > 0 && <span style={{ color: "#6EE7B7" }}>{quotedCount} quoted</span>}
                  <span>Qty: {rfq.quantity ? rfq.quantity.toLocaleString() : "TBD"}</span>
                  <span>{formatDate(rfq.createdAt)}</span>
                </div>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

// QuoteUploadView removed - quote upload is now integrated into RfqManagementView

// ─── View 4: Quote Analysis & Decision ──────────────────────────────────────

function QuoteAnalysisView({ quotes, suppliers }) {
  const [sortField, setSortField] = useState("score");
  const [sortDir, setSortDir] = useState(-1);

  const catColors = { domestic: { bg: "#064E3B", text: "#6EE7B7", label: "\uD83C\uDDFA\uD83C\uDDF8 Domestic" }, nearshore: { bg: "#1E3A5F", text: "#60A5FA", label: "\uD83C\uDDF2\uD83C\uDDFD Nearshore" }, offshore: { bg: "#3B2F08", text: "#FBBF24", label: "\uD83C\uDF0F Offshore" } };

  // Best per category
  const bestByCategory = useMemo(() => {
    const result = {};
    ["domestic", "nearshore", "offshore"].forEach(cat => {
      const catQuotes = quotes.filter(q => q.category === cat);
      if (catQuotes.length > 0) {
        result[cat] = catQuotes.reduce((best, q) => q.score > best.score ? q : best, catQuotes[0]);
      }
    });
    return result;
  }, [quotes]);

  // Sorted quotes
  const sortedQuotes = useMemo(() => {
    return [...quotes].sort((a, b) => {
      let aVal = a[sortField], bVal = b[sortField];
      if (typeof aVal === "string") aVal = aVal.toLowerCase();
      if (typeof bVal === "string") bVal = bVal.toLowerCase();
      if (aVal < bVal) return -1 * sortDir;
      if (aVal > bVal) return 1 * sortDir;
      return 0;
    });
  }, [quotes, sortField, sortDir]);

  function handleSort(field) {
    if (sortField === field) setSortDir(d => d * -1);
    else { setSortField(field); setSortDir(-1); }
  }

  // Decision flowchart logic
  const decision = useMemo(() => {
    if (quotes.length === 0) return null;
    const domestic = bestByCategory.domestic;
    const nearshore = bestByCategory.nearshore;
    const offshore = bestByCategory.offshore;
    const avgPrice = quotes.reduce((sum, q) => sum + (q.unitPrice || 0), 0) / quotes.length;
    const budget = avgPrice * 1.1; // 10% above average as budget threshold

    let path = [];
    let recommendation = null;

    path.push({ id: "start", label: "Start Evaluation", type: "start", active: true });
    path.push({ id: "check-domestic", label: "Check Domestic Options", type: "decision", active: true });

    if (domestic) {
      if (domestic.unitPrice <= budget) {
        path.push({ id: "domestic-price-ok", label: `Domestic Price $${domestic.unitPrice.toFixed(2)} < Budget`, type: "action", active: true });
        const leadOk = parseLeadTimeDays(domestic.leadTime) <= 42; // 6 weeks
        path.push({ id: "domestic-lead", label: leadOk ? "Lead Time OK" : "Lead Time Too Long", type: "decision", active: true });
        if (leadOk) {
          path.push({ id: "recommend-domestic", label: `Recommend: ${domestic.supplierName}`, type: "result", active: true });
          recommendation = { category: "domestic", quote: domestic, reason: "Best domestic option within budget and acceptable lead time" };
        } else {
          path.push({ id: "check-nearshore", label: "Check Nearshore", type: "decision", active: true });
          if (nearshore) {
            path.push({ id: "recommend-nearshore", label: `Recommend: ${nearshore.supplierName}`, type: "result", active: true });
            recommendation = { category: "nearshore", quote: nearshore, reason: "Nearshore option preferred due to domestic lead time constraints" };
          } else if (offshore) {
            path.push({ id: "recommend-offshore", label: `Recommend: ${offshore.supplierName} (with risk notes)`, type: "result", active: true });
            recommendation = { category: "offshore", quote: offshore, reason: "Offshore option as fallback - review supply chain risks" };
          }
        }
      } else {
        path.push({ id: "domestic-price-high", label: "Domestic Price Exceeds Budget", type: "action", active: true });
        path.push({ id: "check-nearshore-2", label: "Check Nearshore Options", type: "decision", active: true });
        if (nearshore && nearshore.unitPrice <= budget * 0.8) {
          path.push({ id: "nearshore-savings", label: `Nearshore $${nearshore.unitPrice.toFixed(2)} - Good Savings`, type: "action", active: true });
          path.push({ id: "recommend-nearshore-2", label: `Recommend: ${nearshore.supplierName}`, type: "result", active: true });
          recommendation = { category: "nearshore", quote: nearshore, reason: "Nearshore provides significant cost savings vs domestic" };
        } else if (offshore) {
          path.push({ id: "check-offshore", label: "Check Offshore", type: "decision", active: true });
          path.push({ id: "recommend-offshore-2", label: `Recommend: ${offshore.supplierName} (with risk notes)`, type: "result", active: true });
          recommendation = { category: "offshore", quote: offshore, reason: "Offshore option for maximum cost savings - review risks" };
        }
      }
    } else if (nearshore) {
      path.push({ id: "no-domestic", label: "No Domestic Options", type: "action", active: true });
      path.push({ id: "recommend-nearshore-3", label: `Recommend: ${nearshore.supplierName}`, type: "result", active: true });
      recommendation = { category: "nearshore", quote: nearshore, reason: "Best available nearshore option" };
    } else if (offshore) {
      path.push({ id: "no-domestic-nearshore", label: "No Domestic/Nearshore", type: "action", active: true });
      path.push({ id: "recommend-offshore-3", label: `Recommend: ${offshore.supplierName}`, type: "result", active: true });
      recommendation = { category: "offshore", quote: offshore, reason: "Only offshore options available" };
    }

    return { path, recommendation };
  }, [quotes, bestByCategory]);

  if (quotes.length === 0) {
    return (
      <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", background: "#111827", color: "#64748B", flexDirection: "column", gap: 8 }}>
        <div style={{ fontSize: 40 }}>{"\uD83D\uDCCA"}</div>
        <div style={{ fontSize: 16, fontWeight: 500, color: "#94A3B8" }}>No quotes to analyze</div>
        <div style={{ fontSize: 13 }}>Upload quotes in the Quote Upload view first</div>
      </div>
    );
  }

  return (
    <div style={{ flex: 1, overflowY: "auto", padding: 24, background: "#111827" }}>
      <h2 style={{ fontSize: 20, fontWeight: 700, color: "#F1F5F9", margin: "0 0 20px" }}>Quote Analysis & Decision</h2>

      {/* Best per category */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 12, marginBottom: 24 }}>
        {["domestic", "nearshore", "offshore"].map(cat => {
          const best = bestByCategory[cat];
          const cc = catColors[cat];
          return (
            <div key={cat} style={{ background: "#1E293B", borderRadius: 12, padding: 16, border: `1px solid ${best ? (cat === "domestic" ? "#064E3B" : cat === "nearshore" ? "#1E3A5F" : "#3B2F08") : "#374151"}` }}>
              <div style={{ fontSize: 12, fontWeight: 600, color: cc.text, marginBottom: 8 }}>{cc.label}</div>
              {best ? (
                <div>
                  <div style={{ fontSize: 16, fontWeight: 700, color: "#F1F5F9" }}>{best.supplierName}</div>
                  <div style={{ fontSize: 22, fontWeight: 800, color: cc.text, margin: "6px 0" }}>${best.unitPrice.toFixed(2)}</div>
                  <div style={{ fontSize: 12, color: "#94A3B8" }}>{best.leadTime || "N/A"} lead time</div>
                  <div style={{ fontSize: 11, color: "#64748B", marginTop: 4 }}>Score: {best.score}/100</div>
                </div>
              ) : (
                <div style={{ color: "#64748B", fontSize: 13 }}>No quotes in this category</div>
              )}
            </div>
          );
        })}
      </div>

      {/* Comparison table */}
      <div style={{ background: "#1E293B", borderRadius: 12, border: "1px solid #374151", overflow: "hidden", marginBottom: 24 }}>
        <div style={{ padding: "12px 16px", borderBottom: "1px solid #374151", fontSize: 14, fontWeight: 600, color: "#F1F5F9" }}>
          Comparison Table
        </div>
        <div style={{ overflowX: "auto" }}>
          <table style={{ width: "100%", borderCollapse: "collapse", fontSize: 12 }}>
            <thead>
              <tr style={{ background: "#0F172A" }}>
                {[
                  { field: "supplierName", label: "Supplier" },
                  { field: "countryOfOrigin", label: "Origin" },
                  { field: "category", label: "Category" },
                  { field: "unitPrice", label: "Unit Price" },
                  { field: "leadTime", label: "Lead Time" },
                  { field: "moq", label: "MOQ" },
                  { field: "paymentTerms", label: "Terms" },
                  { field: "score", label: "Score" }
                ].map(col => (
                  <th key={col.field} onClick={() => handleSort(col.field)} style={{
                    padding: "8px 12px", textAlign: "left", color: "#64748B", fontWeight: 600,
                    fontSize: 10, textTransform: "uppercase", borderBottom: "1px solid #374151",
                    cursor: "pointer", userSelect: "none"
                  }}>
                    {col.label} {sortField === col.field ? (sortDir === 1 ? "\u25B2" : "\u25BC") : ""}
                  </th>
                ))}
              </tr>
            </thead>
            <tbody>
              {sortedQuotes.map(q => {
                const cc = catColors[q.category] || catColors.offshore;
                return (
                  <tr key={q.id} style={{ borderBottom: "1px solid #374151" }}>
                    <td style={{ padding: "8px 12px", fontWeight: 600, color: "#F1F5F9" }}>{q.supplierName}</td>
                    <td style={{ padding: "8px 12px", color: "#94A3B8" }}>{q.countryOfOrigin || "-"}</td>
                    <td style={{ padding: "8px 12px" }}>
                      <span style={{ padding: "2px 6px", borderRadius: 4, fontSize: 10, fontWeight: 600, background: cc.bg, color: cc.text }}>{q.category}</span>
                    </td>
                    <td style={{ padding: "8px 12px", fontWeight: 700, color: "#F1F5F9" }}>{q.unitPrice ? `$${q.unitPrice.toFixed(2)}` : "-"}</td>
                    <td style={{ padding: "8px 12px", color: "#D1D5DB" }}>{q.leadTime || "-"}</td>
                    <td style={{ padding: "8px 12px", color: "#D1D5DB" }}>{q.moq ? q.moq.toLocaleString() : "-"}</td>
                    <td style={{ padding: "8px 12px", color: "#94A3B8", fontSize: 11 }}>{q.paymentTerms || "-"}</td>
                    <td style={{ padding: "8px 12px" }}>
                      <div style={{
                        display: "inline-flex", padding: "2px 8px", borderRadius: 10, fontSize: 11, fontWeight: 700,
                        background: q.score >= 70 ? "#064E3B" : q.score >= 40 ? "#3B2F08" : "#7F1D1D20",
                        color: q.score >= 70 ? "#6EE7B7" : q.score >= 40 ? "#FBBF24" : "#FCA5A5"
                      }}>{q.score}</div>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>

      {/* Decision Flowchart */}
      {decision && decision.path.length > 0 && (
        <div style={{ background: "#1E293B", borderRadius: 12, border: "1px solid #374151", padding: 20 }}>
          <h3 style={{ fontSize: 15, fontWeight: 600, color: "#F1F5F9", marginTop: 0, marginBottom: 16 }}>Sourcing Decision Flowchart</h3>
          <div style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: 0 }}>
            {decision.path.map((node, i) => {
              const typeStyles = {
                start: { bg: "#581C87", border: "#A855F7", text: "#E9D5FF", radius: 20 },
                decision: { bg: "#78350F", border: "#F59E0B", text: "#FEF3C7", radius: 4 },
                action: { bg: "#1E3A5F", border: "#3B82F6", text: "#BFDBFE", radius: 8 },
                result: { bg: "#064E3B", border: "#22C55E", text: "#DCFCE7", radius: 16 }
              };
              const style = typeStyles[node.type] || typeStyles.action;
              return (
                <React.Fragment key={node.id}>
                  {i > 0 && (
                    <div style={{ width: 2, height: 20, background: "#4B5563" }} />
                  )}
                  {i > 0 && (
                    <div style={{ width: 0, height: 0, borderLeft: "6px solid transparent", borderRight: "6px solid transparent", borderTop: "6px solid #4B5563", marginBottom: 4 }} />
                  )}
                  <div style={{
                    padding: "10px 20px", borderRadius: style.radius, background: style.bg,
                    border: `2px solid ${style.border}`, color: style.text,
                    fontSize: 12, fontWeight: 600, textAlign: "center",
                    maxWidth: 320, width: "100%"
                  }}>
                    {node.label}
                  </div>
                </React.Fragment>
              );
            })}
          </div>

          {/* Recommendation box */}
          {decision.recommendation && (
            <div style={{ marginTop: 20, padding: 16, background: "#064E3B", border: "1px solid #22C55E", borderRadius: 10 }}>
              <div style={{ fontSize: 12, fontWeight: 700, color: "#6EE7B7", marginBottom: 6 }}>RECOMMENDATION</div>
              <div style={{ fontSize: 16, fontWeight: 700, color: "#F1F5F9" }}>{decision.recommendation.quote.supplierName}</div>
              <div style={{ fontSize: 13, color: "#D1D5DB", marginTop: 4 }}>{decision.recommendation.reason}</div>
              <div style={{ display: "flex", gap: 16, marginTop: 8, fontSize: 13 }}>
                <span style={{ color: "#6EE7B7", fontWeight: 700 }}>${decision.recommendation.quote.unitPrice.toFixed(2)}</span>
                <span style={{ color: "#94A3B8" }}>{decision.recommendation.quote.leadTime}</span>
                <span style={{ color: "#94A3B8" }}>Score: {decision.recommendation.quote.score}</span>
              </div>
            </div>
          )}

          {/* Scoring legend */}
          <div style={{ marginTop: 16, padding: 12, background: "#0F172A", borderRadius: 8, border: "1px solid #374151" }}>
            <div style={{ fontSize: 11, fontWeight: 600, color: "#64748B", marginBottom: 6 }}>SCORING WEIGHTS</div>
            <div style={{ display: "flex", gap: 16, flexWrap: "wrap", fontSize: 11, color: "#94A3B8" }}>
              <span>Price: 30%</span>
              <span>Lead Time: 20%</span>
              <span>Certifications: 20%</span>
              <span>Supply Chain Risk: 15%</span>
              <span>Payment Terms: 15%</span>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

// ─── Main Component ─────────────────────────────────────────────────────────

function StrategicSourcingAgent({ onBack }) {
  // Navigation
  const [activeView, setActiveView] = useState("discovery");
  const [sidebarCollapsed, setSidebarCollapsed] = useState(false);

  // Chat state
  // Chat persistence
  const [chatSessions, setChatSessions] = useState([]);
  const [activeChatId, setActiveChatId] = useState(null);
  const activeChatIdRef = React.useRef(activeChatId);
  const [messages, setMessages] = useState([]);
  const [input, setInput] = useState("");
  const [loading, setLoading] = useState(false);
  const [loadingStatus, setLoadingStatus] = useState("Analyzing...");
  const [activeAction, setActiveAction] = useState(null);

  // Settings
  const [modelId, setModelId] = useState("nvidia/nemotron-3-nano-30b-a3b:free");
  const [showSettings, setShowSettings] = useState(false);

  // Data state
  const [suppliers, setSuppliers] = useState([]);
  const [rfqs, setRfqs] = useState([]);
  const [quotes, setQuotes] = useState([]);

  // File upload state
  const [uploadedFile, setUploadedFile] = useState(null);
  const [uploadError, setUploadError] = useState("");

  // Load chat sessions from server on mount
  useEffect(() => {
    dbGet("sourcingChats").then(data => {
      if (Array.isArray(data) && data.length > 0) setChatSessions(data);
    }).catch(() => {});
  }, []);
  useEffect(() => {
    dbGet("rfqs").then(data => { if (Array.isArray(data) && data.length > 0) setRfqs(data); }).catch(() => {});
    dbGet("quotes").then(data => { if (Array.isArray(data) && data.length > 0) setQuotes(data); }).catch(() => {});
    dbGet("suppliers").then(data => {
      if (!Array.isArray(data) || data.length === 0) return;
      // Deduplicate by name, preferring stable IDs (sup_ prefix)
      const byName = new Map();
      for (const s of data) {
        const existing = byName.get(s.name);
        if (!existing) { byName.set(s.name, s); }
        else if (s.id.startsWith('sup_') && !existing.id.startsWith('sup_')) {
          dbDelete("suppliers", existing.id).catch(() => {});
          byName.set(s.name, s);
        } else if (!s.id.startsWith('sup_') && existing.id.startsWith('sup_')) {
          dbDelete("suppliers", s.id).catch(() => {});
        }
      }
      setSuppliers(Array.from(byName.values()));
    }).catch(() => {});
  }, []);
  // Auto-save suppliers to DB when they change
  useEffect(() => {
    if (suppliers.length === 0) return;
    suppliers.forEach(s => dbUpsert("suppliers", s).catch(() => {}));
  }, [suppliers]);
  React.useEffect(() => { activeChatIdRef.current = activeChatId; }, [activeChatId]);

  // Auto-save current chat to server
  useEffect(() => {
    if (messages.length <= 1) return;
    const userMsgs = messages.filter(m => m.role === "user");
    if (userMsgs.length === 0) return;
    const title = userMsgs[0].content.slice(0, 60) + (userMsgs[0].content.length > 60 ? "..." : "");
    const sesId = activeChatIdRef.current || (() => { const id = generateId(); setActiveChatId(id); return id; })();
    const now = new Date().toISOString();
    setChatSessions(prev => {
      const existing = prev.find(s => s.id === sesId);
      const session = {
        id: sesId,
        title,
        messages,
        createdAt: existing?.createdAt || now,
        updatedAt: now
      };
      dbUpsert("sourcingChats", session).catch(() => {});
      const idx = prev.findIndex(s => s.id === sesId);
      if (idx === -1) return [...prev, session];
      return prev.map(s => s.id === sesId ? { ...s, ...session } : s);
    });
  }, [messages]);

  function loadChatSession(session) {
    setMessages(session.messages);
    setActiveChatId(session.id);
    // Clear suppliers before replaying so old chat's suppliers don't persist
    setSuppliers([]);
    // Restore suppliers from loaded chat's messages
    session.messages.forEach(msg => {
      if (msg.role === "assistant") processVizData(msg.content);
    });
  }

  function deleteChatSession(sessionId) {
    setChatSessions(prev => prev.filter(s => s.id !== sessionId));
    dbDelete("sourcingChats", sessionId).catch(() => {});
    if (activeChatId === sessionId) {
      setMessages([]);
      setActiveChatId(null);
      setSuppliers([]);
    }
  }

  function saveRfq(rfq) { dbUpsert("rfqs", rfq).catch(() => {}); }
  function saveQuote(quote) { dbUpsert("quotes", quote).catch(() => {}); }

  async function handleCreateRfqFromChat() {
    const last20 = messages.slice(-20);
    let extracted = null;
    try {
      const resp = await fetch("/api/chat", {
        method: "POST",
        headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("auth_token")}` },
        body: JSON.stringify({
          model: modelId,
          messages: [
            { role: "system", content: RFQ_EXTRACTION_PROMPT },
            { role: "user", content: "Extract RFQ details from this conversation:\n\n" + last20.map(m => `${m.role}: ${m.content}`).join("\n") }
          ]
        })
      });
      const data = await resp.json();
      const text = data.choices?.[0]?.message?.content || "";
      const match = text.match(/```rfq-data\n([\s\S]*?)\n```/);
      if (match) extracted = JSON.parse(match[1]);
    } catch (e) {}
    const newRfq = {
      id: generateId(),
      title: extracted?.name || "New RFQ",
      description: extracted?.description || "",
      quantity: parseInt(extracted?.quantity) || 0,
      targetDate: extracted?.targetDate || "",
      requirements: extracted?.requirements || "",
      suppliers: [],
      status: "draft",
      createdAt: new Date().toISOString()
    };
    setRfqs(prev => [...prev, newRfq]);
    saveRfq(newRfq);
    setActiveView("rfq");
  }

  function startNewChat() {
    setMessages([]);
    setActiveChatId(null);
    setSuppliers([]);
  }

  // Derived: set of supplier IDs in any RFQ
  const rfqSupplierIds = useMemo(() => {
    const ids = new Set();
    rfqs.forEach(r => r.suppliers.forEach(id => ids.add(id)));
    return ids;
  }, [rfqs]);

  // Badge counts
  const counts = {
    discovery: suppliers.length,
    rfq: rfqs.length,
    analysis: quotes.length > 0 ? 1 : 0
  };

  // ─── Viz-data processing ─────────────────────────────────────────────────

  function processVizData(text) {
    const blocks = extractVizData(text);
    const newEliminations = [];

    blocks.forEach(block => {
      switch (block.type) {
        case "supplier-map":
          if (block.suppliers) {
            const incoming = block.suppliers.map(s => ({
              ...s,
              id: s.id || stableSupplierIdFromName(s.name),
              category: s.region || classifyCountry(s.country || ""),
              eliminated: false,
              inRfq: false
            }));
            setSuppliers(prev => {
              const existing = new Map(prev.map(s => [s.name, s]));
              incoming.forEach(s => {
                const old = existing.get(s.name);
                if (old) {
                  existing.set(s.name, { ...old, ...s, id: old.id, inRfq: old.inRfq, eliminated: old.eliminated });
                } else {
                  existing.set(s.name, s);
                }
              });
              return Array.from(existing.values());
            });
          }
          break;
        case "elimination-log":
          if (block.eliminations) {
            newEliminations.push(...block.eliminations);
            setSuppliers(prev => prev.map(s => {
              const elim = block.eliminations.find(e => e.supplier === s.name);
              if (elim) return { ...s, rating: "eliminated", eliminated: true };
              return s;
            }));
          }
          break;
        case "supplier-update":
          if (block.updates) {
            setSuppliers(prev => prev.map(s => {
              const updates = block.updates.filter(u => u.name === s.name);
              if (updates.length === 0) return s;
              const updated = { ...s };
              updates.forEach(u => { updated[u.field] = u.value; });
              return updated;
            }));
          }
          break;
      }
    });
    return newEliminations;
  }

  // ─── Add supplier to RFQ from map ─────────────────────────────────────────

  function handleAddToRfqFromMap(supplierId) {
    // Mark supplier as in RFQ
    setSuppliers(prev => prev.map(s => s.id === supplierId ? { ...s, inRfq: true } : s));

    // Add to first draft RFQ, or create one
    const existingDraft = rfqs.find(r => r.status === "draft");
    if (existingDraft) {
      if (!existingDraft.suppliers.includes(supplierId)) {
        const updatedRfq = { ...existingDraft, suppliers: [...existingDraft.suppliers, supplierId] };
        setRfqs(prev => prev.map(r => r.id === existingDraft.id ? updatedRfq : r));
        saveRfq(updatedRfq);
      }
    } else {
      const newRfq = {
        id: generateId(),
        title: (() => { const userMsgs = messages.filter(m => m.role === "user"); return userMsgs.length > 0 ? userMsgs[0].content.slice(0, 50) : "New RFQ"; })(),
        description: "",
        quantity: 0,
        targetDate: "",
        suppliers: [supplierId],
        status: "draft",
        createdAt: new Date().toISOString()
      };
      setRfqs(prev => [...prev, newRfq]);
      saveRfq(newRfq);
    }
  }

  // ─── Chat functions ───────────────────────────────────────────────────────

  async function searchWeb(query) {
    try {
      const res = await fetch("/api/search", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ query }) });
      if (!res.ok) return { results: [] };
      return await res.json();
    } catch { return { results: [] }; }
  }

  function formatSearchContext(results) {
    if (!results || results.length === 0) return "";
    let ctx = "\n\n--- SEARCH RESULTS ---\n";
    results.forEach((r, i) => { ctx += `${i + 1}. **${r.title}**\n   URL: ${r.link}\n   ${r.snippet}\n`; });
    ctx += "--- END SEARCH RESULTS ---\nAnalyze these suppliers. Include a supplier-map viz-data block with lat/lng coordinates, contact info, certifications, pricing, and rankingScore for each supplier found.";
    return ctx;
  }

  async function sendMessage(overrideText, searchQuery) {
    const text = overrideText || input.trim();
    if (!text || loading) return;
    const userMsg = { role: "user", content: text };
    const newMessages = [...messages, userMsg];
    setMessages(newMessages);
    setInput("");
    setLoading(true);
    setActiveAction(null);

    let searchResults = null;
    let augmentedText = text;

    if (searchQuery) {
      setLoadingStatus("Searching for suppliers...");
      const searchData = await searchWeb(searchQuery);
      if (searchData.results && searchData.results.length > 0) {
        searchResults = searchData.results;
        augmentedText = text + formatSearchContext(searchData.results);
      }
      setLoadingStatus("Analyzing results...");
    } else {
      setLoadingStatus("Analyzing...");
    }

    try {
      const apiMessages = [
        { role: "system", content: SOURCING_SYSTEM_PROMPT },
        ...newMessages.slice(0, -1).map(m => ({ role: m.role === "assistant" ? "assistant" : "user", content: m.content })),
        { role: "user", content: augmentedText }
      ];
      const res = await fetch("/api/chat", {
        method: "POST", headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ model: modelId, messages: apiMessages })
      });
      if (!res.ok) throw new Error(`API error: ${res.status}`);
      const data = await res.json();
      const reply = data.choices?.[0]?.message?.content || "I couldn't process that request.";
      const newEliminations = processVizData(reply);
      setMessages(prev => [...prev, {
        role: "assistant", content: reply, sources: searchResults,
        eliminations: newEliminations.length > 0 ? newEliminations : null
      }]);
    } catch (err) {
      setMessages(prev => [...prev, { role: "assistant", content: `Error: ${err.message}` }]);
    } finally {
      setLoading(false);
    }
  }

  async function handleFileSelect(e) {
    const file = e.target.files[0];
    if (!file) return;
    setUploadError("");
    try {
      const parsed = await parseUploadedFile(file);
      const truncated = parsed.text.length > 12000 ? parsed.text.slice(0, 12000) + "\n...[truncated]" : parsed.text;
      setUploadedFile({ filename: parsed.filename, text: truncated, pageCount: parsed.pageCount });
    } catch (err) {
      setUploadError("Failed to parse file: " + err.message);
      setUploadedFile(null);
    }
    e.target.value = "";
  }

  function handleSend() {
    const text = input.trim();
    if (!text && !uploadedFile) return;
    let fullText = text;
    if (uploadedFile) {
      fullText = (text ? text + "\n\n" : "Please analyze this document:\n\n") +
        `--- UPLOADED FILE: ${uploadedFile.filename}${uploadedFile.pageCount ? ` (${uploadedFile.pageCount} pages)` : ""} ---\n${uploadedFile.text}\n--- END FILE ---`;
      setUploadedFile(null);
    }
    if (activeAction && activeAction.searchEnabled) {
      sendMessage(fullText, text + " suppliers manufacturers USA");
    } else {
      sendMessage(fullText);
    }
  }

  function handleSettingsOpen() {
    setShowSettings(true);
  }

  return (
    <div style={{ display: "flex", height: "100vh", width: "100vw", overflow: "hidden", background: "#111827" }}>
      {/* Sidebar */}
      <Sidebar
        activeView={activeView}
        onNavigate={setActiveView}
        counts={counts}
        collapsed={sidebarCollapsed}
        onToggleCollapse={() => setSidebarCollapsed(c => !c)}
        onBack={onBack}
        onSettings={handleSettingsOpen}
      />

      {/* Main content */}
      <div style={{ flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }}>
        {/* Top bar */}
        <div style={{ height: 48, background: "#0F172A", display: "flex", alignItems: "center", padding: "0 20px", gap: 12, flexShrink: 0, borderBottom: "1px solid #1E293B" }}>
          <span style={{ fontSize: 15, fontWeight: 700, color: "#F1F5F9" }}>
            {NAV_ITEMS.find(n => n.id === activeView)?.icon} {NAV_ITEMS.find(n => n.id === activeView)?.label}
          </span>
          <div style={{ flex: 1 }} />
          {suppliers.length > 0 && (
            <span style={{ fontSize: 11, color: "#64748B" }}>{suppliers.filter(s => !s.eliminated).length} suppliers discovered</span>
          )}
          {rfqs.length > 0 && (
            <span style={{ padding: "2px 8px", background: "#1E3A5F", borderRadius: 6, fontSize: 11, color: "#60A5FA", fontWeight: 600 }}>{rfqs.length} RFQs</span>
          )}
          {quotes.length > 0 && (
            <span style={{ padding: "2px 8px", background: "#064E3B", borderRadius: 6, fontSize: 11, color: "#6EE7B7", fontWeight: 600 }}>{quotes.length} quotes</span>
          )}
        </div>

        {/* View content */}
        {activeView === "discovery" && (
          <ChatDiscoveryView
            messages={messages} input={input} setInput={setInput} loading={loading}
            loadingStatus={loadingStatus} onSend={handleSend} onFileSelect={handleFileSelect}
            uploadedFile={uploadedFile} setUploadedFile={setUploadedFile}
            uploadError={uploadError} setUploadError={setUploadError}
            suppliers={suppliers} onAddToRfq={handleAddToRfqFromMap}
            rfqSupplierIds={rfqSupplierIds}
            activeAction={activeAction} setActiveAction={setActiveAction}
            quotes={quotes}
            chatSessions={chatSessions} activeSesId={activeChatId} onLoadChat={loadChatSession}
            onDeleteChat={deleteChatSession} onNewChat={startNewChat}
            onCreateRfq={handleCreateRfqFromChat}
          />
        )}
        {activeView === "rfq" && (
          <RfqManagementView rfqs={rfqs} setRfqs={setRfqs} suppliers={suppliers} quotes={quotes} setQuotes={setQuotes} modelId={modelId} saveRfq={saveRfq} saveQuote={saveQuote} onGoToChat={() => setActiveView("discovery")} />
        )}
        {activeView === "analysis" && (
          <QuoteAnalysisView quotes={quotes} suppliers={suppliers} />
        )}
      </div>

      {/* Settings Modal */}
      {showSettings && window.SettingsModal && (
        <window.SettingsModal
          modelId={modelId}
          onSave={(m) => { if (m && m !== "__custom__") setModelId(m); }}
          onClose={() => setShowSettings(false)}
        />
      )}
    </div>
  );
}

window.StrategicSourcingAgent = StrategicSourcingAgent;
