// SummaryBar — bottom strip aggregating itinerary metrics.
//
// Datetime model:
//   - 開始 = earliest arrival OR departure across all nodes
//   - 終了 = latest arrival OR departure across all nodes
//   - 総旅程時間 = 終了 - 開始 (only shown when at least 2 nodes have times)
//
// Costs:
//   - 旅費 = sum of edge.cost
//   - 諸費用 = sum of node.cost
//   - 合計 = 旅費 + 諸費用
//
// Per-group breakdown shows costs only — group time would be misleading
// across overnight stays (group "Day 1" might span 18 hours including the
// overnight wait, which isn't a useful display).

// ── Cost categorization ────────────────────────────────────────
// Auto-derive the expense category from node properties. 'bed' / 'tent'
// icons → 宿泊費 (lodging); everything else → 雑費 (misc). Edges are always
// 旅費交通費 (transport) by definition. Users can override per-node via
// node.costCategory, otherwise we infer from the icon.
function nodeCostCategory(node){
  if (!node) return 'misc';
  if (node.costCategory) return node.costCategory;
  if (node.icon === 'bed' || node.icon === 'tent') return 'lodging';
  return 'misc';
}
window.nodeCostCategory = nodeCostCategory;

function parseCost(s){
  if (!s) return 0;
  // Strip thousands separators, whitespace, and common currency symbols.
  // 円 (suffix) and the multi-char prefixes A$ / CHF need to come out too
  // so a string like "1,200円" or "A$25.50" yields just the digits.
  const txt = String(s)
    .replace(/A\$/g, '')
    .replace(/CHF/gi, '')
    .replace(/[,¥$€£円元₩฿₫\s]/g, '')
    .trim();
  const n = parseFloat(txt);
  return isFinite(n) ? n : 0;
}

// Format an amount with a specific currency prefix. Integer currencies
// (yen, won, etc.) display whole numbers; fractional currencies (USD,
// EUR, etc.) preserve up to 2 decimal places to avoid rounding loss.
function formatCostWith(symbol, amt){
  const sym = symbol || '¥';
  const v = Math.round((amt || 0) * 100) / 100;
  if (v === Math.floor(v)) return sym + v.toLocaleString('en-US');
  return sym + v.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
}
// Backwards-compat alias used by existing call sites that assume yen.
function formatCost(amt){ return formatCostWith('¥', amt); }

function SummaryBar({ edges, groups, nodes, defaultCurrency }){
  if (!edges) return null;
  nodes = nodes || [];
  const dt = window.tourDateTime;
  const fallbackCur = defaultCurrency || '¥';
  const extractCur = window.extractCurrency || ((_s, fb) => fb || '¥');

  // Trip span — earliest known time → latest known time.
  let earliest = null, latest = null;
  nodes.forEach(n => {
    [n.arrival, n.departure].forEach(s => {
      const d = dt?.toDate(s);
      if (!d) return;
      if (!earliest || d < earliest) earliest = d;
      if (!latest   || d > latest)   latest = d;
    });
  });
  const tripMins = (earliest && latest) ? Math.round((latest - earliest) / 60000) : null;

  // Cost totals split into 5 categories AND further broken out per
  // currency symbol (so a trip mixing ¥ and $ shows two subtotals
  // instead of an incorrect lumped sum). Each category bucket is a Map
  // keyed by the detected currency symbol; values are running totals.
  const addToBucket = (bucket, sym, amt) => {
    bucket.set(sym, (bucket.get(sym) || 0) + amt);
  };
  const transportBucket = new Map();
  const lodgingBucket   = new Map();
  const miscBucket      = new Map();
  const meetingBucket   = new Map();
  const entertainmentBucket = new Map();
  const grandBucket     = new Map();
  edges.forEach(e => {
    const c = parseCost(e.cost);
    if (c <= 0) return;
    const sym = extractCur(e.cost, fallbackCur);
    addToBucket(transportBucket, sym, c);
    addToBucket(grandBucket, sym, c);
  });
  nodes.forEach(n => {
    const c = parseCost(n.cost);
    if (c <= 0) return;
    const sym = extractCur(n.cost, fallbackCur);
    const cat = nodeCostCategory(n);
    if      (cat === 'lodging')       addToBucket(lodgingBucket, sym, c);
    else if (cat === 'meeting')       addToBucket(meetingBucket, sym, c);
    else if (cat === 'entertainment') addToBucket(entertainmentBucket, sym, c);
    else                              addToBucket(miscBucket, sym, c);
    addToBucket(grandBucket, sym, c);
  });
  // Render helper: take a bucket Map and return a "¥3,450 + $25.50"-style
  // string. Order: defaultCurrency first, then others sorted by symbol.
  const renderBucket = (bucket) => {
    const entries = [...bucket.entries()].filter(([_, v]) => v > 0);
    if (entries.length === 0) return formatCostWith(fallbackCur, 0);
    entries.sort((a, b) => {
      if (a[0] === fallbackCur) return -1;
      if (b[0] === fallbackCur) return 1;
      return a[0] < b[0] ? -1 : 1;
    });
    return entries.map(([sym, v]) => formatCostWith(sym, v)).join(' + ');
  };
  const hasAny = (bucket) => [...bucket.values()].some(v => v > 0);

  // Per-group cost chips were previously rendered on the right side of this
  // bar — removed per design feedback because they overlapped with the
  // schedule's per-day breakdown and added noise without clear value.

  return (
    <div className="summary-bar">
      <div className="sum-item" title="総区間数">
        <window.TourIcon name="route" size={13} stroke="currentColor"/>
        区間 <b>{edges.length}</b>
      </div>

      {earliest && (
        <div className="sum-item" title="最も早い時刻（旅程の開始）">
          <window.TourIcon name="flag" size={13} stroke="currentColor"/>
          開始 <b>{formatDtFull(earliest)}</b>
        </div>
      )}
      {latest && earliest && latest.getTime() !== earliest.getTime() && (
        <div className="sum-item" title="最も遅い時刻（旅程の終了）">
          <window.TourIcon name="flag-triangle-right" size={13} stroke="currentColor"/>
          終了 <b>{formatDtCompact(latest, earliest)}</b>
        </div>
      )}
      {tripMins != null && tripMins > 0 && (
        <div className="sum-item" title="開始から終了までの実時間"
             style={{paddingLeft:8, marginLeft:4, borderLeft:'1px solid var(--line)'}}>
          総旅程 <b style={{color:'var(--green-deep)'}}>{dt ? dt.formatDuration(tripMins) : `${tripMins}分`}</b>
        </div>
      )}

      <div className="sum-item" title="矢印（区間）の運賃合計"
           style={{paddingLeft:8, marginLeft:4, borderLeft:'1px solid var(--line)'}}>
        <window.TourIcon name="banknote" size={13} stroke="currentColor"/>
        旅費交通費 <b>{renderBucket(transportBucket)}</b>
      </div>
      <div className="sum-item" title="ホテル・宿泊地の費用合計">
        <window.TourIcon name="bed" size={13} stroke="currentColor"/>
        宿泊費 <b>{renderBucket(lodgingBucket)}</b>
      </div>
      <div className="sum-item" title="入場料・食事・その他の地点費用合計">
        <window.TourIcon name="wallet" size={13} stroke="currentColor"/>
        雑費 <b>{renderBucket(miscBucket)}</b>
      </div>
      {hasAny(meetingBucket) && (
        <div className="sum-item" title="商談・打ち合わせ等の費用合計">
          <window.TourIcon name="briefcase" size={13} stroke="currentColor"/>
          会議費 <b>{renderBucket(meetingBucket)}</b>
        </div>
      )}
      {hasAny(entertainmentBucket) && (
        <div className="sum-item" title="接待・会食等の交際費合計">
          <window.TourIcon name="utensils" size={13} stroke="currentColor"/>
          交際費 <b>{renderBucket(entertainmentBucket)}</b>
        </div>
      )}
      <div className="sum-item" title="全カテゴリの合計（通貨別）"
           style={{paddingLeft:8, marginLeft:4, borderLeft:'1px solid var(--line)'}}>
        合計 <b style={{color:'var(--green-deep)'}}>{renderBucket(grandBucket)}</b>
      </div>

      <div className="sum-spacer"/>

      {edges.length === 0 && nodes.length === 0 && (
        <span style={{fontSize:11, color:'var(--ink-muted)'}}>地点を追加して旅程を組み立てましょう</span>
      )}
    </div>
  );
}

// Compact "9:00" or "4/29 8:00" form for the END row, relative to start.
// If `ref` (start of trip) is on the same date, omit the date.
function formatDtCompact(d, ref){
  if (!d) return '';
  const sameDay = ref && d.getFullYear()===ref.getFullYear()
                     && d.getMonth()===ref.getMonth()
                     && d.getDate()===ref.getDate();
  const hh = d.getHours();
  const mm = String(d.getMinutes()).padStart(2,'0');
  if (sameDay || !ref) return `${hh}:${mm}`;
  return `${d.getMonth()+1}/${d.getDate()} ${hh}:${mm}`;
}

// Full "4/28 9:00" form — used for START so the date is always visible.
function formatDtFull(d){
  if (!d) return '';
  const hh = d.getHours();
  const mm = String(d.getMinutes()).padStart(2,'0');
  return `${d.getMonth()+1}/${d.getDate()} ${hh}:${mm}`;
}

function hexToTint(hex){
  const m = /^#?([0-9a-f]{6})$/i.exec(hex);
  if (!m) return 'var(--bg-mint)';
  const r = parseInt(m[1].slice(0,2),16);
  const g = parseInt(m[1].slice(2,4),16);
  const b = parseInt(m[1].slice(4,6),16);
  const mix = 0.85;
  const blend = c => Math.round(c + (255 - c) * mix);
  return `rgb(${blend(r)},${blend(g)},${blend(b)})`;
}

window.SummaryBar = SummaryBar;
