// Brand tokens + shared primitives for The Bach Lists app prototype

const TBL = {
  // Sunset Spritz palette
  ink: '#2a1a1f',
  cream: '#fbeee0',
  creamDeep: '#f5e3cf',
  jam: '#e05a3d',      // primary brand
  jamDark: '#b84525',
  citrus: '#f3b94a',
  sky: '#7a4e8e',
  mint: '#c88fa4',     // warm rose-mint
  sage: '#8ba892',     // for checkmarks/success
  // utility
  line: 'rgba(42,26,31,0.12)',
  mute: 'rgba(42,26,31,0.55)',
  subtle: 'rgba(42,26,31,0.7)',
  // retailer colors
  shein: '#000',
  amazon: '#ff9900',
  etsy: '#eb6d20',
  temu: '#fb7701',
};

const SERIF = '"Instrument Serif", Georgia, serif';
const SANS = 'Geist, -apple-system, "SF Pro", system-ui, sans-serif';
const MONO = '"JetBrains Mono", ui-monospace, monospace';

// ── Regions + currency ──
const REGIONS = {
  UK:             { currency: 'GBP', symbol: '£',   prefix: true,  flag: '🇬🇧' },
  USA:            { currency: 'USD', symbol: '$',   prefix: true,  flag: '🇺🇸' },
  EU:             { currency: 'EUR', symbol: '€',   prefix: true,  flag: '🇪🇺' },
  'AU-NZ':        { currency: 'AUD', symbol: 'A$',  prefix: true,  flag: '🇦🇺' },
  'South Africa': { currency: 'ZAR', symbol: 'R ',  prefix: true,  flag: '🇿🇦' },
  Other:          { currency: 'USD', symbol: '$',   prefix: true,  flag: '🌎' },
};

// Rough FX rates (1 unit of X = N USD). Same table the backend uses, kept in
// sync so client + server convert prices consistently.
const FX_TO_USD = { USD: 1, GBP: 1.27, EUR: 1.09, AUD: 0.64, ZAR: 0.054, CAD: 0.74, JPY: 0.0067 };

function formatPrice(amount, region, fromCurrency) {
  const r = REGIONS[region] || REGIONS.UK;
  const targetCurrency = r.currency;
  let n = Number(amount) || 0;
  // If the source currency is known and differs from the target, convert via USD.
  if (fromCurrency && fromCurrency !== targetCurrency) {
    const fromRate = FX_TO_USD[fromCurrency] || 1;
    const toRate = FX_TO_USD[targetCurrency] || 1;
    n = (n * fromRate) / toRate;
  }
  n = Math.max(1, Math.round(n));
  return r.prefix ? `${r.symbol}${n}` : `${n}${r.symbol}`;
}

// Same math as formatPrice, but returns a raw number so totals/sums across
// mixed-currency items can be computed in a single target currency before display.
// e.g. cartItems.reduce((s, it) => s + convertAmount(it.price, region, it.priceCurrency) * it.qty, 0)
function convertAmount(amount, region, fromCurrency) {
  const r = REGIONS[region] || REGIONS.UK;
  const targetCurrency = r.currency;
  let n = Number(amount) || 0;
  if (fromCurrency && fromCurrency !== targetCurrency) {
    const fromRate = FX_TO_USD[fromCurrency] || 1;
    const toRate = FX_TO_USD[targetCurrency] || 1;
    n = (n * fromRate) / toRate;
  }
  return n;
}

// ── Affiliate configuration ──
// One place to read/update retailer affiliate IDs. Each region owns its own tag —
// there is no "global" affiliate code at any of these retailers. Fill in as new
// programmes are approved.
const AFFILIATE = {
  amazon: {
    // Amazon search URL: https://{domain}/s?k={q}&tag={tag}
    domains: {
      USA:            'amazon.com',
      UK:             'amazon.co.uk',
      EU:             'amazon.es',       // default EU → ES; swap per user later
      'AU-NZ':        'amazon.com.au',
      'South Africa': 'amazon.co.za',    // launched May 2024
    },
    // Amazon Associates tags are separate accounts per region.
    tagsByRegion: {
      USA: 'thebachlists-20',
      // UK / EU / AU / ZA: pending separate registrations
    },
  },
  shein: {
    // Shein regional sites. Search path: /pdsearch/{q}
    domains: {
      USA:           'us.shein.com',
      UK:            'uk.shein.com',
      EU:            'es.shein.com',     // Spain for EU
      'AU-NZ':       'au.shein.com',
      'South Africa':'za.shein.com',
    },
    // Shein affiliate codes are influencer-style: redeemable at checkout, and
    // also passed as a ?ref= URL parameter as a best-effort tracking hint.
    // Always show the code to the user so they can enter it at checkout.
    codesByRegion: {
      UK:            'B3ZDL',
      'South Africa':'X997G',
      EU:            'RG7AX',
    },
  },
  etsy: {
    domain: 'www.etsy.com',
    // Etsy affiliate: pending (Awin/ShareASale)
    tagsByRegion: {},
  },
  temu: {
    domain: 'www.temu.com',
    // Temu affiliate: pending
    tagsByRegion: {},
  },
};

// ── Contact addresses ──
const CONTACT = {
  primary:       'info@thebachlists.com',
  orderTracking: 'track@thebachlists.com',
  press:         'hello@thebachlists.com',
};

// Build a tagged retailer URL for a given item query + retailer + region.
// Falls back to a plain search URL when no affiliate programme exists for that region.
function buildAffiliateUrl(query, retailer, region) {
  const q = encodeURIComponent(query || '');
  const R = region || 'UK';

  if (retailer === 'Amazon') {
    const domain = AFFILIATE.amazon.domains[R] || 'amazon.com';
    const tag    = AFFILIATE.amazon.tagsByRegion[R];
    return `https://${domain}/s?k=${q}${tag ? `&tag=${tag}` : ''}`;
  }
  if (retailer === 'Shein') {
    const domain = AFFILIATE.shein.domains[R] || 'us.shein.com';
    const code   = AFFILIATE.shein.codesByRegion[R];
    return `https://${domain}/pdsearch/${q}/${code ? `?ref=${code}` : ''}`;
  }
  if (retailer === 'Etsy') {
    return `https://${AFFILIATE.etsy.domain}/search?q=${q}`;
  }
  if (retailer === 'Temu') {
    return `https://${AFFILIATE.temu.domain}/search_result.html?search_key=${q}`;
  }
  return `https://www.google.com/search?q=${q}`;
}

// If the retailer uses an influencer/promo code at checkout, return it so the UI
// can surface it to the user. Currently only Shein works this way.
function getAffiliateCheckoutCode(retailer, region) {
  if (retailer === 'Shein') {
    return (AFFILIATE.shein.codesByRegion && AFFILIATE.shein.codesByRegion[region]) || null;
  }
  return null;
}

// ── Product ID + regional URL helpers ──
// Given a product URL, pull out the retailer's unique ID so we can generate URLs
// for every region. Keeps the same regex patterns as the backend extract-product
// endpoint so old items (without stored regionUrls) still work in any region.
function extractProductId(url, retailer) {
  try {
    const u = new URL(url);
    if (retailer === 'Amazon') {
      const m = u.pathname.match(/\/(?:dp|gp\/product|gp\/aw\/d)\/([A-Z0-9]{10})/i);
      return m ? m[1].toUpperCase() : null;
    }
    if (retailer === 'Shein') {
      const m = u.pathname.match(/-p-(\d+)\.html/);
      return m ? m[1] : null;
    }
    if (retailer === 'Etsy') {
      const m = u.pathname.match(/\/listing\/(\d+)/);
      return m ? m[1] : null;
    }
    if (retailer === 'Temu') {
      const pathMatch = u.pathname.match(/-g-(\d+)\.html/);
      if (pathMatch) return pathMatch[1];
      const qMatch = u.searchParams.get('goods_id');
      return qMatch || null;
    }
    return null;
  } catch (e) { return null; }
}

function generateRegionalUrls(retailer, productId, originalUrl, originalRegion) {
  const urls = {};
  if (originalRegion && originalUrl) urls[originalRegion] = originalUrl;
  if (!productId) return urls;

  if (retailer === 'Amazon') {
    const domains = { USA: 'amazon.com', UK: 'amazon.co.uk', EU: 'amazon.es', 'AU-NZ': 'amazon.com.au', 'South Africa': 'amazon.co.za' };
    Object.entries(domains).forEach(([region, domain]) => {
      if (!urls[region]) urls[region] = `https://www.${domain}/dp/${productId}`;
    });
  } else if (retailer === 'Shein') {
    const domains = {
      USA: 'us.shein.com', UK: 'uk.shein.com', EU: 'es.shein.com',
      'AU-NZ': 'au.shein.com', 'South Africa': 'za.shein.com',
    };
    Object.entries(domains).forEach(([region, domain]) => {
      if (!urls[region]) urls[region] = `https://${domain}/pdsearch/${productId}`;
    });
  } else if (retailer === 'Etsy') {
    ['USA','UK','EU','AU-NZ','South Africa'].forEach(region => {
      if (!urls[region]) urls[region] = `https://www.etsy.com/listing/${productId}`;
    });
  } else if (retailer === 'Temu') {
    ['USA','UK','EU','AU-NZ','South Africa'].forEach(region => {
      if (!urls[region]) urls[region] = originalUrl;
    });
  }

  return urls;
}

// For any item that has a realUrl but no (or partial) regionUrls, fill them in
// by extracting the product ID on the fly. Idempotent — items that already have
// full regionUrls pass through unchanged.
function enrichItemWithRegionUrls(item) {
  if (!item || !item.realUrl || !item.src) return item;
  if (item.regionUrls && Object.keys(item.regionUrls).length >= 4) return item;
  const pid = extractProductId(item.realUrl, item.src);
  if (!pid) return item;
  const urls = generateRegionalUrls(item.src, pid, item.realUrl, null);
  return { ...item, productId: item.productId || pid, regionUrls: { ...(item.regionUrls || {}), ...urls } };
}

// ── Theme aesthetic gradients ──
const THEME_GRADIENTS = {
  coastal: 'linear-gradient(135deg, #cfe0e8 0%, #e8d4c5 100%)',
  disco: 'linear-gradient(135deg, #e8a3c4 0%, #c56d98 50%, #7a4e8e 100%)',
  nashville: 'linear-gradient(135deg, #f3b94a 0%, #e05a3d 100%)',
  tropical: 'linear-gradient(135deg, #f5e3cf 0%, #e8c99a 50%, #c88fa4 100%)',
  ski: 'linear-gradient(135deg, #e0e8ea 0%, #c6c0cc 100%)',
  vegas: 'linear-gradient(135deg, #7a4e8e 0%, #e05a3d 100%)',
  garden: 'linear-gradient(135deg, #c6d4b8 0%, #f0d4c0 100%)',
  parisian: 'linear-gradient(135deg, #e8d8c4 0%, #b8939a 100%)',
  lasttoast: 'linear-gradient(135deg, #fbd9b0 0%, #e05a3d 50%, #7a4e8e 100%)',
  apres: 'linear-gradient(135deg, #dce4ea 0%, #c88fa4 100%)',
  bali: 'linear-gradient(135deg, #e8b87a 0%, #c4605a 100%)',
  fiesta: 'linear-gradient(135deg, #f3b94a 0%, #e05a3d 40%, #7a4e8e 100%)',
};

// ── Logo mark (small) ──
function LogoMark({ size = 22, color = TBL.ink, accent = TBL.jam }) {
  return (
    <svg width={size} height={size * 1.27} viewBox="0 0 72 92">
      <rect x="4" y="6" width="56" height="80" rx="2" fill="none" stroke={color} strokeWidth="3"/>
      <path d="M18 56 L34 72 L68 18" stroke={accent} strokeWidth="7" strokeLinecap="round" strokeLinejoin="round" fill="none"/>
    </svg>
  );
}

function LogoLockup({ color = TBL.ink, accent = TBL.jam, size = 1 }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
      <LogoMark size={22 * size} color={color} accent={accent}/>
      <div style={{ fontFamily: SERIF, fontSize: 20 * size, color, letterSpacing: -0.3, lineHeight: 1 }}>
        <span style={{ fontStyle: 'italic' }}>The Bach</span> Lists
      </div>
    </div>
  );
}

// ── Buttons ──
function PrimaryBtn({ children, onClick, full, style = {}, size = 'md' }) {
  const sizes = {
    sm: { padY: 10, padX: 18, font: 13 },
    md: { padY: 14, padX: 22, font: 14 },
    lg: { padY: 17, padX: 28, font: 15 },
  };
  const sz = sizes[size];
  return (
    <button onClick={onClick} style={{
      background: TBL.jam, color: TBL.cream, border: 'none',
      padding: `${sz.padY}px ${sz.padX}px`, borderRadius: 999,
      fontFamily: SANS, fontSize: sz.font, fontWeight: 500, cursor: 'pointer',
      width: full ? '100%' : 'auto', letterSpacing: -0.1,
      boxShadow: '0 1px 2px rgba(224,90,61,0.25), 0 4px 12px rgba(224,90,61,0.2)',
      ...style,
    }}>{children}</button>
  );
}

function SecondaryBtn({ children, onClick, full, style = {}, size = 'md' }) {
  const sizes = {
    sm: { padY: 9, padX: 16, font: 13 },
    md: { padY: 13, padX: 20, font: 14 },
    lg: { padY: 16, padX: 26, font: 15 },
  };
  const sz = sizes[size];
  return (
    <button onClick={onClick} style={{
      background: 'transparent', color: TBL.ink, border: `1.5px solid ${TBL.ink}`,
      padding: `${sz.padY}px ${sz.padX}px`, borderRadius: 999,
      fontFamily: SANS, fontSize: sz.font, fontWeight: 500, cursor: 'pointer',
      width: full ? '100%' : 'auto', letterSpacing: -0.1,
      ...style,
    }}>{children}</button>
  );
}

// ── Chip ──
function Chip({ children, active, onClick, color = TBL.jam, size = 'md' }) {
  const pad = size === 'sm' ? '6px 11px' : '8px 14px';
  const font = size === 'sm' ? 12 : 13;
  return (
    <button onClick={onClick} style={{
      background: active ? color : 'transparent',
      border: `1.5px solid ${active ? color : 'rgba(42,26,31,0.18)'}`,
      color: active ? TBL.cream : TBL.ink,
      padding: pad, borderRadius: 999,
      fontFamily: SANS, fontSize: font, fontWeight: 500, cursor: 'pointer',
      letterSpacing: -0.1, whiteSpace: 'nowrap',
    }}>{children}</button>
  );
}

// ── Card ──
function Card({ children, style = {}, pad = 20 }) {
  return (
    <div style={{
      background: '#fff', borderRadius: 20, padding: pad,
      border: `1px solid ${TBL.line}`,
      ...style,
    }}>{children}</div>
  );
}

// ── Eyebrow (uppercase caption) ──
function Eyebrow({ children, color = TBL.jam, style = {} }) {
  return (
    <div style={{
      fontFamily: MONO, fontSize: 10, letterSpacing: 2.2, textTransform: 'uppercase',
      color, fontWeight: 500, ...style,
    }}>{children}</div>
  );
}

// ── Progress bar (gradient) ──
function GradientProgress({ pct = 40, height = 6 }) {
  return (
    <div style={{ height, background: 'rgba(42,26,31,0.08)', borderRadius: 999, overflow: 'hidden' }}>
      <div style={{
        width: `${pct}%`, height: '100%',
        background: `linear-gradient(90deg, ${TBL.jam} 0%, ${TBL.mint} 100%)`,
        borderRadius: 999,
      }}/>
    </div>
  );
}

// ── Retailer badge ──
function RetailerBadge({ name, size = 'sm' }) {
  const colors = { Shein: TBL.shein, Amazon: TBL.amazon, Etsy: TBL.etsy, Temu: TBL.temu };
  const pad = size === 'sm' ? '3px 7px' : '5px 10px';
  const font = size === 'sm' ? 9 : 11;
  return (
    <span style={{
      background: colors[name] || TBL.ink, color: '#fff',
      padding: pad, borderRadius: 4, fontFamily: MONO, fontSize: font,
      letterSpacing: 0.5, fontWeight: 500, textTransform: 'uppercase',
    }}>{name}</span>
  );
}

// ── SubLabel (field caption) ──
function SubLabel({ children }) {
  return <div style={{ fontFamily: MONO, fontSize: 10, letterSpacing: 2, textTransform: 'uppercase', color: TBL.mute, marginBottom: 8 }}>{children}</div>;
}

// ── Stepper (+/- number control) ──
function Stepper({ val, min = 1, max = 12, onChange }) {
  return (
    <div style={{ display: 'inline-flex', alignItems: 'center', background: '#fff', border: `1px solid ${TBL.line}`, borderRadius: 999, overflow: 'hidden' }}>
      <button onClick={()=>onChange && onChange(Math.max(min, val-1))} style={{ width: 36, height: 36, border: 'none', background: 'transparent', fontSize: 18, cursor: 'pointer', color: TBL.ink }}>−</button>
      <div style={{ width: 32, textAlign: 'center', fontFamily: SERIF, fontStyle: 'italic', fontSize: 18, color: TBL.ink }}>{val}</div>
      <button onClick={()=>onChange && onChange(Math.min(max, val+1))} style={{ width: 36, height: 36, border: 'none', background: 'transparent', fontSize: 18, cursor: 'pointer', color: TBL.ink }}>+</button>
    </div>
  );
}

// ── Palette dots ──
function PaletteDots({ colors, size = 12 }) {
  return (
    <div style={{ display: 'flex', gap: 4 }}>
      {colors.map((c, i) => (
        <div key={i} style={{
          width: size, height: size, borderRadius: 999, background: c,
          border: '1.5px solid #fff', boxShadow: '0 0 0 0.5px rgba(42,26,31,0.15)',
        }}/>
      ))}
    </div>
  );
}

// ── iPhone frame (styled wrapper around IOSDevice for our aesthetic) ──
function Phone({ children, title, label }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 12 }}>
      {label && (
        <div style={{ fontFamily: MONO, fontSize: 10, letterSpacing: 2, textTransform: 'uppercase', color: 'rgba(60,50,40,0.65)' }}>
          {label}
        </div>
      )}
      <div style={{
        width: 390, height: 844, borderRadius: 52, overflow: 'hidden',
        background: TBL.cream, position: 'relative',
        boxShadow: '0 40px 80px rgba(0,0,0,0.18), 0 0 0 10px #1a1514, 0 0 0 11px rgba(0,0,0,0.15)',
        fontFamily: SANS,
      }}>
        {/* dynamic island */}
        <div style={{
          position: 'absolute', top: 11, left: '50%', transform: 'translateX(-50%)',
          width: 120, height: 34, borderRadius: 20, background: '#000', zIndex: 100,
        }}/>
        {/* status bar */}
        <div style={{
          position: 'absolute', top: 0, left: 0, right: 0, height: 54, zIndex: 50,
          display: 'flex', justifyContent: 'space-between', alignItems: 'center',
          padding: '18px 32px 0', color: TBL.ink, fontSize: 15, fontWeight: 600,
          pointerEvents: 'none',
        }}>
          <div>9:41</div>
          <div style={{ display: 'flex', gap: 5, alignItems: 'center' }}>
            <svg width="17" height="11" viewBox="0 0 17 11"><rect x="0" y="7" width="3" height="4" rx="0.6" fill={TBL.ink}/><rect x="4.5" y="5" width="3" height="6" rx="0.6" fill={TBL.ink}/><rect x="9" y="2.5" width="3" height="8.5" rx="0.6" fill={TBL.ink}/><rect x="13.5" y="0" width="3" height="11" rx="0.6" fill={TBL.ink}/></svg>
            <svg width="15" height="11" viewBox="0 0 15 11"><path d="M7.5 10.5C8.3 10.5 9 9.8 9 9C9 8.2 8.3 7.5 7.5 7.5C6.7 7.5 6 8.2 6 9C6 9.8 6.7 10.5 7.5 10.5Z M2.5 5C4 3.5 5.7 2.8 7.5 2.8C9.3 2.8 11 3.5 12.5 5L13.5 4C11.7 2.2 9.7 1.2 7.5 1.2C5.3 1.2 3.3 2.2 1.5 4L2.5 5Z M4.5 7C5.3 6.2 6.3 5.8 7.5 5.8C8.7 5.8 9.7 6.2 10.5 7L11.5 6C10.3 4.8 9 4.2 7.5 4.2C6 4.2 4.7 4.8 3.5 6L4.5 7Z" fill={TBL.ink}/></svg>
            <svg width="24" height="11" viewBox="0 0 24 11"><rect x="0.5" y="0.5" width="20" height="10" rx="2.5" stroke={TBL.ink} strokeOpacity="0.4" fill="none"/><rect x="2" y="2" width="17" height="7" rx="1" fill={TBL.ink}/></svg>
          </div>
        </div>
        {/* content */}
        <div style={{ height: '100%', overflow: 'hidden' }}>
          {children}
        </div>
        {/* home indicator */}
        <div style={{
          position: 'absolute', bottom: 8, left: '50%', transform: 'translateX(-50%)',
          width: 134, height: 5, borderRadius: 999, background: 'rgba(42,26,31,0.35)',
          zIndex: 100,
        }}/>
      </div>
    </div>
  );
}

// ── Product image with graceful fallback to emoji + gradient ──
// Used wherever we display a product thumbnail. If the src fails to load (broken
// URL, hotlink protection, CORS), we quietly fall back to the emoji on the gradient.
function ProductImage({ src, alt, emoji, gradient, fit = 'cover', fontSize = 32 }) {
  const [failed, setFailed] = React.useState(false);
  const hasImage = !!src && !failed;
  return (
    <div style={{
      width: '100%', height: '100%',
      background: gradient || TBL.creamDeep,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      fontSize, overflow: 'hidden', position: 'relative',
    }}>
      {hasImage ? (
        <img
          src={src}
          alt={alt || ''}
          loading="lazy"
          referrerPolicy="no-referrer"
          onError={() => setFailed(true)}
          style={{ width: '100%', height: '100%', objectFit: fit, display: 'block' }}
        />
      ) : (
        <span>{emoji || '🎀'}</span>
      )}
    </div>
  );
}

// ── Toast (small feedback pill at bottom of app frame) ──
function Toast({ message, onDismiss, duration = 2500 }) {
  React.useEffect(() => {
    if (!message) return;
    const t = setTimeout(onDismiss, duration);
    return () => clearTimeout(t);
  }, [message, duration, onDismiss]);
  if (!message) return null;
  return (
    <div style={{
      position: 'absolute', bottom: 20, left: '50%', transform: 'translateX(-50%)',
      background: TBL.ink, color: TBL.cream, padding: '12px 22px', borderRadius: 999,
      fontFamily: SANS, fontSize: 13, fontWeight: 500,
      boxShadow: '0 10px 30px rgba(0,0,0,0.3)', zIndex: 300,
      display: 'flex', alignItems: 'center', gap: 10,
      maxWidth: 'calc(100% - 40px)',
      whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
    }}>
      <span>✓</span>
      <span>{message}</span>
    </div>
  );
}

Object.assign(window, {
  TBL, SERIF, SANS, MONO, THEME_GRADIENTS,
  REGIONS, formatPrice, convertAmount,
  AFFILIATE, CONTACT, buildAffiliateUrl, getAffiliateCheckoutCode,
  extractProductId, generateRegionalUrls, enrichItemWithRegionUrls,
  LogoMark, LogoLockup, PrimaryBtn, SecondaryBtn, Chip, Card, Eyebrow,
  GradientProgress, RetailerBadge, PaletteDots, Phone,
  SubLabel, Stepper, Toast, ProductImage,
});
