/* Shared Titan Case helpers, store, navigation, footer, and preview. */

const CFG = window.TC_CONFIG;
const I18N = window.TC_I18N;

const LangCtx = React.createContext({ lang: 'it', t: I18N.it, setLang: function () {} });
const ThemeCtx = React.createContext({ theme: 'light', setTheme: function () {} });

const useLang = () => React.useContext(LangCtx);
const useTheme = () => React.useContext(ThemeCtx);

function useRoute() {
  const [route, setRoute] = React.useState(() => (window.location.hash || '#/').replace(/^#/, '') || '/');
  React.useEffect(() => {
    const onHash = () => {
      setRoute((window.location.hash || '#/').replace(/^#/, '') || '/');
      window.scrollTo(0, 0);
    };
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);
  return route;
}

function navigate(to) {
  window.location.hash = to.charAt(0) === '#' ? to : '#' + to;
}

const Link = ({ to, className, children, onClick, ...rest }) => (
  <a
    href={'#' + to}
    className={className}
    onClick={(event) => {
      if (onClick) onClick(event);
    }}
    {...rest}
  >
    {children}
  </a>
);

function entries(object) {
  return Object.keys(object || {}).map((key) => [key, object[key]]);
}

function buildBodyColors() {
  if (Array.isArray(CFG.bodyColors) && CFG.bodyColors.length) return CFG.bodyColors;
  return entries(CFG.colors.pla).map(([key, value]) => ({
    key,
    material: 'pla',
    ...value
  }));
}

function buildCapColors() {
  if (Array.isArray(CFG.capColors) && CFG.capColors.length) return CFG.capColors;
  return entries(CFG.colors.tpu).map(([key, value]) => ({
    key,
    material: 'tpu',
    ...value
  }));
}

const BODY_COLORS = buildBodyColors();
const CAP_COLORS = buildCapColors();
const SYMBOLS = CFG.symbols || [];

const DEFAULT_CONFIG = {
  device: (CFG.devices.find((device) => device.status === 'live') || CFG.devices[0]).id,
  bodyColor: 'black',
  capColor: 'black',
  customText: 'TITAN',
  symbols: ['◆'],
  qty: 1
};

function normalizeConfig(config) {
  const source = config || {};
  const defaultBody = BODY_COLORS[0] ? BODY_COLORS[0].key : DEFAULT_CONFIG.bodyColor;
  const defaultCap = CAP_COLORS[0] ? CAP_COLORS[0].key : DEFAULT_CONFIG.capColor;
  return {
    ...DEFAULT_CONFIG,
    ...source,
    bodyColor: window.normalizeBodyKey(source.bodyColor || defaultBody),
    capColor: window.normalizeCapKey(source.capColor || defaultCap),
    symbols: Array.isArray(source.symbols) ? source.symbols : []
  };
}

function getBodyColor(key) {
  const normalized = window.normalizeBodyKey(key);
  return BODY_COLORS.find((item) => item.key === normalized || item.slug === normalized) || BODY_COLORS[0] || {
    key: normalized || 'black',
    slug: normalized || 'black',
    displayNameEn: 'Black',
    displayNameIt: 'Nero',
    hex: '#111111',
    type: 'standard'
  };
}

function getCapColor(key) {
  const normalized = window.normalizeCapKey(key);
  return CAP_COLORS.find((item) => item.key === normalized || item.slug === normalized) || CAP_COLORS[0] || {
    key: normalized || 'black',
    slug: normalized || 'black',
    displayNameEn: 'Black',
    displayNameIt: 'Nero',
    hex: '#111111'
  };
}

function getColorLabel(key, lang) {
  const color = BODY_COLORS.concat(CAP_COLORS).find((item) => item.key === key || item.slug === key);
  if (color) {
    return lang === 'en'
      ? (color.displayNameEn || color.name || color.key)
      : (color.displayNameIt || color.displayNameEn || color.name || color.key);
  }
  const t = (I18N[lang] || I18N.it).common;
  return (t.colorLabels && t.colorLabels[key]) || key;
}

function formatMoney(value, lang) {
  const locale = lang === 'en' ? 'en-US' : 'it-IT';
  return new Intl.NumberFormat(locale, {
    style: 'currency',
    currency: CFG.site.currency
  }).format(Number(value || 0) / 100);
}

function fmtEur(value) {
  const lang = (() => {
    try { return localStorage.getItem('tc_lang') || CFG.site.defaultLang || 'it'; }
    catch (e) { return CFG.site.defaultLang || 'it'; }
  })();
  return formatMoney(value, lang);
}

function calcPrice(config) {
  return calcPriceBreakdown(config).total;
}

function calcPriceBreakdown(config) {
  const cfg = normalizeConfig(config);
  const body = getBodyColor(cfg.bodyColor);
  const variant = getPublicVariant(cfg.bodyColor, cfg.capColor);
  const basePrice = variant && Number.isFinite(Number(variant.priceCents))
    ? Number(variant.priceCents)
    : CFG.pricing.basePriceCents;
  const finishExtra = (CFG.pricing.finishesCents && CFG.pricing.finishesCents[body.type]) || 0;
  const textExtra = cfg.customText && cfg.customText.trim() ? CFG.pricing.customTextExtraCents : 0;
  const symbolExtra = (cfg.symbols || []).length * CFG.pricing.symbolExtraCents;
  return {
    base: basePrice,
    finish: variant ? 0 : finishExtra,
    text: textExtra,
    symbols: symbolExtra,
    total: basePrice + (variant ? 0 : finishExtra) + textExtra + symbolExtra
  };
}

function variantIdForConfig(bodyColor, capColor) {
  const variant = CFG.primaryVariant || (CFG.variants && CFG.variants[0]);
  return variant ? variant.id : `var_${window.normalizeBodyKey(bodyColor)}_${window.normalizeCapKey(capColor)}`;
}

function getPublicVariant(bodyColor, capColor) {
  const id = variantIdForConfig(bodyColor, capColor);
  return (CFG.stockByVariant && CFG.stockByVariant[id]) || CFG.primaryVariant || (CFG.variants && CFG.variants[0]);
}

function mergePublicCatalog(data) {
  if (!data) return false;
  CFG.product = data.product || CFG.product;
  CFG.variants = data.variants || CFG.variants || [];
  CFG.primaryVariant = data.primaryVariant || CFG.primaryVariant || (CFG.variants && CFG.variants[0]);
  CFG.stockByVariant = data.stockByVariant || {};
  CFG.combinationAvailability = data.combinationAvailability || {};
  CFG.bodyColors = data.bodyColors || [];
  CFG.capColors = data.capColors || [];
  BODY_COLORS.splice(0, BODY_COLORS.length, ...CFG.bodyColors.map((color) => ({
    key: color.slug || color.key,
    material: 'pla',
    type: 'standard',
    ...color
  })));
  CAP_COLORS.splice(0, CAP_COLORS.length, ...CFG.capColors.map((color) => ({
    key: color.slug || color.key,
    material: 'tpu',
    ...color
  })));
  if (data.compatibilityModels) {
    CFG.devices = data.compatibilityModels
      .filter((model) => model.isSupported)
      .map((model) => ({
        id: model.slug || model.id,
        displayName: model.shortLabel || model.displayName,
        fullName: model.displayName,
        shortName: model.shortLabel || model.displayName,
        heroName: model.shortLabel || model.displayName,
        brand: model.shortLabel || model.displayName,
        model: model.displayName,
        status: 'live',
        productionStatus: 'made_to_order',
        sku: CFG.primaryVariant ? CFG.primaryVariant.sku : 'TC-ELFBAR-BASE',
        dimensions: model.dimensions || { widthMm: 16, heightMm: 108, depthMm: 16 },
        caseDimensions: data.product && data.product.caseDimensions ? data.product.caseDimensions : { widthMm: 18, heightMm: 110, depthMm: 18 },
        capStartMm: data.product && data.product.capStartMm ? data.product.capStartMm : 92,
        legalCompatibilityNote: 'Compatibility names describe physical fit only.'
      }));
    CFG.futureDevices = data.compatibilityModels
      .filter((model) => !model.isSupported && model.isRequestable)
      .map((model) => ({
        id: model.slug || model.id,
        displayName: model.displayName,
        shortName: model.shortLabel || model.displayName,
        status: 'request_open',
        requestCount: 0,
        requestThreshold: 50
      }));
  }
  CFG.localPickup = { ...(CFG.localPickup || {}), ...(data.localPickup || {}) };
  CFG.reviews = data.reviews || [];
  if (data.pricing) {
    CFG.pricing = {
      ...CFG.pricing,
      ...data.pricing
    };
  }
  return true;
}

function persistDraftConfig(config) {
  try {
    sessionStorage.setItem('tc_draft', JSON.stringify(normalizeConfig(config)));
  } catch (e) {}
}

async function submitRecord(endpoint, payload) {
  const record = {
    ...payload,
    createdAt: new Date().toISOString()
  };

  try {
    const response = await fetch(endpoint, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(record)
    });
    const result = await response.json().catch(() => ({}));
    if (!response.ok || !result.ok) {
      const error = result.error || {};
      return {
        ok: false,
        error: error.message || 'Request failed',
        code: error.code || null,
        retryAfterSeconds: error.retryAfterSeconds || null
      };
    }
    return { ok: true, id: result.id };
  } catch (error) {
    return { ok: false, error: error.message };
  }
}

const CART_KEY = 'tc_cart_v1';
const CartStore = (() => {
  let listeners = [];
  let state = load();

  function load() {
    try {
      const raw = localStorage.getItem(CART_KEY) || localStorage.getItem('titan_cart_v2');
      if (raw) {
        const parsed = JSON.parse(raw);
        const items = (parsed.items || []).map((item) => ({
          ...item,
          config: normalizeConfig(item.config),
          qty: item.qty || 1
        }));
        return { items };
      }
    } catch (e) {}
    return { items: [] };
  }

  function save() {
    try { localStorage.setItem(CART_KEY, JSON.stringify(state)); } catch (e) {}
    listeners.forEach((listener) => listener(state));
  }

  return {
    get: () => state,
    subscribe: (listener) => {
      listeners.push(listener);
      return () => {
        listeners = listeners.filter((item) => item !== listener);
      };
    },
    add: (item) => {
      state = {
        items: state.items.concat({
          ...item,
          id: String(Date.now()) + '-' + String(Math.random()).slice(2),
          config: normalizeConfig(item.config),
          qty: item.qty || 1
        })
      };
      save();
    },
    update: (id, patch) => {
      state = {
        items: state.items.map((item) => item.id === id ? { ...item, ...patch } : item)
      };
      save();
    },
    remove: (id) => {
      state = { items: state.items.filter((item) => item.id !== id) };
      save();
    },
    clear: () => {
      state = { items: [] };
      save();
    },
    count: () => state.items.reduce((sum, item) => sum + (item.qty || 1), 0)
  };
})();

function shadeHex(hex, amount) {
  const clean = String(hex || '#888888').replace('#', '');
  const value = parseInt(clean, 16);
  const clamp = (n) => Math.max(0, Math.min(255, n));
  const r = clamp((value >> 16) + amount);
  const g = clamp(((value >> 8) & 255) + amount);
  const b = clamp((value & 255) + amount);
  return '#' + [r, g, b].map((n) => n.toString(16).padStart(2, '0')).join('');
}

function renderBody(key, color) {
  const hex = color.hex;
  const renders = {
    whiteMarble: {
      body: 'linear-gradient(160deg, #fbf8f1 0%, #ebe3d4 45%, #b7ad9b 100%)',
      swatch: 'radial-gradient(circle at 28% 20%, #fbf8f1 0%, #e5ddcf 42%, #aea391 100%)'
    },
    sparkleBlack: {
      body: 'radial-gradient(circle at 22% 18%, rgba(255,255,255,0.22), transparent 10%), linear-gradient(160deg, #303036 0%, #121216 54%, #050506 100%)',
      swatch: 'radial-gradient(circle at 30% 25%, #3a3a42 0%, #17171b 45%, #050506 100%)'
    },
    purpleGradient: {
      body: 'linear-gradient(180deg, #d9bbff 0%, #7b4ad9 48%, #28144b 100%)',
      swatch: 'linear-gradient(160deg, #251243 0%, #7b4ad9 56%, #d9bbff 100%)'
    },
    blueGradient: {
      body: 'linear-gradient(180deg, #b9ddff 0%, #4e7fff 48%, #102a65 100%)',
      swatch: 'linear-gradient(160deg, #0e2a65 0%, #4e7fff 56%, #b9ddff 100%)'
    }
  };
  if (renders[key]) return renders[key];
  return {
    body: `linear-gradient(160deg, ${shadeHex(hex, 28)} 0%, ${hex} 50%, ${shadeHex(hex, -44)} 100%)`,
    swatch: `linear-gradient(160deg, ${shadeHex(hex, 18)} 0%, ${hex} 100%)`
  };
}

function getLiveDevices() {
  return (CFG.devices || []).filter((device) => device.status === 'live');
}

function getHeroDeviceNames() {
  return getLiveDevices().map((device) => device.heroName || device.brand || device.displayName);
}

const Logo = () => (
  <Link to="/" className="tc-logo" aria-label={CFG.company.brandName}>
    <span className="tc-mark" aria-hidden="true"></span>
    <span>{CFG.company.brandName}</span>
  </Link>
);

const Nav = () => {
  const route = useRoute();
  const { lang, t, setLang } = useLang();
  const { theme, setTheme } = useTheme();
  const [open, setOpen] = React.useState(false);
  const [count, setCount] = React.useState(CartStore.count());

  React.useEffect(() => CartStore.subscribe(() => setCount(CartStore.count())), []);
  React.useEffect(() => {
    setOpen(false);
  }, [route]);

  const links = [
    { to: '/product', label: t.nav.shop },
    { to: '/configurator', label: t.nav.customize },
    { to: '/compatibility', label: t.nav.compatibility },
    { to: '/faq', label: t.nav.faq },
    { to: '/contact', label: t.nav.contact }
  ];

  return (
    <>
      <nav className="nav">
        <div className="container nav-inner">
          <Logo />
          <div className="nav-links" aria-label={t.nav.menu}>
            {links.map((link) => (
              <Link key={link.to} to={link.to} className={route.startsWith(link.to) ? 'active' : ''}>
                {link.label}
              </Link>
            ))}
          </div>
          <div className="nav-right">
            <button className="nav-icon-btn" type="button" onClick={() => setLang(lang === 'it' ? 'en' : 'it')} aria-label={t.common.language}>
              {lang.toUpperCase()}
            </button>
            <button className="nav-icon-btn" type="button" onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')} aria-label={t.common.theme}>
              {theme === 'dark' ? 'LIGHT' : 'DARK'}
            </button>
            <button className="nav-cart" type="button" onClick={() => navigate('/cart')}>
              <span>{t.nav.cart}</span>
              <span className="count">{count}</span>
            </button>
            <button className="nav-burger" type="button" onClick={() => setOpen(true)} aria-label={t.nav.menu}>
              <span></span>
            </button>
          </div>
        </div>
      </nav>

      <div className={'mobile-menu' + (open ? ' open' : '')}>
        <div className="mobile-menu-top">
          <Logo />
          <button className="nav-icon-btn" type="button" onClick={() => setOpen(false)} aria-label={t.common.close}>X</button>
        </div>
        {links.map((link, index) => (
          <Link key={link.to} to={link.to}>
            <span>{link.label}</span>
            <span className="mono-sm">{String(index + 1).padStart(2, '0')}</span>
          </Link>
        ))}
        <Link to="/cart">
          <span>{t.nav.cart}</span>
          <span className="mono-sm">{count}</span>
        </Link>
        <div style={{ marginTop: 24 }}>
          <div className="row wrap">
            <button className="btn btn-secondary" type="button" onClick={() => setLang(lang === 'it' ? 'en' : 'it')}>
              {lang.toUpperCase()}
            </button>
            <button className="btn btn-secondary" type="button" onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
              {theme === 'dark' ? t.common.light : t.common.dark}
            </button>
          </div>
        </div>
      </div>
    </>
  );
};

const Ticker = () => {
  const { lang } = useLang();
  const announcement = CFG.announcement || {};
  if (announcement.enabled === false) return null;
  const copy = (announcement.items && announcement.items[lang]) || (announcement.items && announcement.items.it) || {};
  const threshold = formatMoney(CFG.pricing.freeShippingThresholdCents || 5000, lang);
  const items = [
    copy.custom,
    copy.freeShipping && copy.freeShipping.replace('{amount}', threshold),
    announcement.discountCode && copy.discount ? copy.discount.replace('{code}', announcement.discountCode) : ''
  ].filter(Boolean);
  const style = { '--ticker-speed': (announcement.speedSeconds || 72) + 's' };
  return (
    <div className="ticker" style={style}>
      <div className="ticker-track">
        {items.concat(items).map((item, index) => (
          <span key={index}>{item}</span>
        ))}
      </div>
    </div>
  );
};

const Footer = () => {
  const { t, lang } = useLang();
  const disclaimer = lang === 'en' ? CFG.legal.disclaimer : CFG.legal.disclaimerIt;
  return (
    <footer className="footer">
      <div className="container">
        <div className="footer-grid">
          <div className="footer-col">
            <Logo />
            <p>{t.footer.tagline}</p>
            <p>{disclaimer}</p>
          </div>
          <div className="footer-col">
            <h6>{t.footer.shop}</h6>
            <Link to="/product">{t.nav.shop}</Link>
            <Link to="/configurator">{t.nav.customize}</Link>
            <Link to="/compatibility">{t.nav.compatibility}</Link>
          </div>
          <div className="footer-col">
            <h6>{t.footer.support}</h6>
            <Link to="/faq">{t.nav.faq}</Link>
            <Link to="/contact">{t.nav.contact}</Link>
            <Link to="/privacy">{t.footer.privacy}</Link>
            <Link to="/legal">{t.footer.terms}</Link>
            {CFG.company.email
              ? <a href={'mailto:' + CFG.company.email}>{CFG.company.email}</a>
              : <span className="body-muted">{t.contact.notConfigured}</span>}
          </div>
          <div className="footer-col">
            <h6>{t.footer.legal}</h6>
            <p>{CFG.company.legalName}</p>
            {CFG.company.instagram && <a href={CFG.company.instagram}>Instagram</a>}
            {CFG.company.tiktok && <a href={CFG.company.tiktok}>TikTok</a>}
          </div>
        </div>
        <div className="footer-bottom">
          <span>{CFG.site.year} {CFG.company.legalName}. {t.footer.allRights}</span>
          <span>v{CFG.site.version} · {CFG.site.currency}</span>
        </div>
      </div>
    </footer>
  );
};

const StockBadge = ({ stockResult }) => {
  const { t } = useLang();
  const state = getStockLabelKey(stockResult);
  const copy = t.stock[state] || t.stock.out_of_stock;
  const sub = state === 'restocking'
    ? copy.sub.replace('{days}', getRestockEta(stockResult))
    : copy.sub;

  return (
    <span className={'stock-badge stock-' + state}>
      <span className="stock-line">
        <span className="stock-dot"></span>
        <span>{copy.label}</span>
      </span>
      <span className="stock-sub">{sub}</span>
    </span>
  );
};

const ProductPreview = ({ config, size = 'lg', animated = true }) => {
  const cfg = normalizeConfig(config);
  const body = getBodyColor(cfg.bodyColor);
  const cap = getCapColor(cfg.capColor);
  const bodyRender = renderBody(body.key, body);
  const capBg = `linear-gradient(180deg, ${shadeHex(cap.hex, 30)} 0%, ${cap.hex} 46%, ${shadeHex(cap.hex, -38)} 100%)`;
  const text = String(cfg.customText || '').toUpperCase().slice(0, CFG.limits.customTextMax);
  const lightInk = ['whiteMarble', 'matteOrange', 'white', 'orange'].includes(body.key);
  const sizes = {
    sm: { w: 32, h: 196, capH: 32, fz: 7, gap: 7, stage: 220 },
    md: { w: 42, h: 258, capH: 42, fz: 9, gap: 9, stage: 300 },
    lg: { w: 54, h: 330, capH: 54, fz: 11, gap: 11, stage: 380 },
    xl: { w: 66, h: 404, capH: 66, fz: 13, gap: 13, stage: 470 }
  };
  const s = sizes[size] || sizes.lg;
  const style = {
    '--pv-w': s.w + 'px',
    '--pv-h': s.h + 'px',
    '--pv-cap': s.capH + 'px',
    '--pv-fz': s.fz + 'px',
    '--pv-gap': s.gap + 'px',
    '--pv-radius': (s.w * 0.21) + 'px',
    '--body-bg': bodyRender.body,
    '--cap-bg': capBg,
    '--cap-hex': cap.hex,
    '--engrave': lightInk ? 'rgba(18, 20, 20, 0.78)' : 'rgba(255, 255, 255, 0.9)'
  };
  const stageStyle = { '--pv-stage-h': s.stage + 'px' };

  return (
    <div className={'product-preview' + (animated ? '' : ' static')} aria-label="Titan Case preview" style={stageStyle}>
      <div className="preview-shadow"></div>
      <div className="preview-device" style={style}>
        <div className="preview-cap"></div>
        <div className="preview-latch"></div>
        <div className="preview-ring"></div>
        <div className="preview-body">
          <div className="preview-brand">TITAN</div>
          {text && <div className="preview-text">{text}</div>}
          {cfg.symbols && cfg.symbols.length > 0 && (
            <div className="preview-symbols">
              {cfg.symbols.slice(0, CFG.limits.symbolsMax).map((symbol, index) => (
                <span key={index}>{symbol}</span>
              ))}
            </div>
          )}
        </div>
      </div>
    </div>
  );
};

const PageHero = ({ eyebrow, title, sub, children }) => (
  <header className="section-tight">
    <div className="container stack" style={{ gap: 18 }}>
      {eyebrow && <div className="eyebrow">{eyebrow}</div>}
      <h1 className="h-1">{title}</h1>
      {sub && <p className="lead" style={{ maxWidth: 760 }}>{sub}</p>}
      {children}
    </div>
  </header>
);

const SpecRow = ({ k, v, tone }) => (
  <div className="spec-row">
    <span className="spec-key">{k}</span>
    <span className="spec-fill"></span>
    <span className={'spec-val' + (tone ? ' spec-' + tone : '')}>{v}</span>
  </div>
);

const ReviewsSection = () => {
  const { lang } = useLang();
  const reviews = (CFG.reviews || []).filter((review) => review.isVerified);
  if (!reviews.length) return null;
  return (
    <section className="section band">
      <div className="container stack" style={{ gap: 24 }}>
        <div>
          <div className="eyebrow">{lang === 'en' ? 'Verified reviews' : 'Recensioni verificate'}</div>
          <h2 className="h-1">{lang === 'en' ? 'From real Titan Case customers.' : 'Da clienti Titan Case reali.'}</h2>
        </div>
        <div className="grid cols-3">
          {reviews.slice(0, 6).map((review) => (
            <article key={review.id} className="surface-plain stack" style={{ padding: 20 }}>
              <div className="row-between">
                <strong>{'★'.repeat(Math.max(1, Math.min(5, Number(review.rating || 5))))}</strong>
                <span className="tag tag-dot">{lang === 'en' ? 'Verified' : 'Verificata'}</span>
              </div>
              {review.title && <h3 className="h-3">{review.title}</h3>}
              <p className="body-muted">{review.body}</p>
              {review.customerDisplayName && <span className="mono-sm">{review.customerDisplayName}</span>}
            </article>
          ))}
        </div>
      </div>
    </section>
  );
};

Object.assign(window, {
  CFG,
  I18N,
  TC_CONFIG: CFG,
  TC_I18N: I18N,
  LangCtx,
  ThemeCtx,
  useLang,
  useTheme,
  useRoute,
  navigate,
  Link,
  BODY_COLORS,
  CAP_COLORS,
  SYMBOLS,
  DEFAULT_CONFIG,
  normalizeConfig,
  getBodyColor,
  getCapColor,
  getColorLabel,
  formatMoney,
  fmtEur,
  calcPrice,
  calcPriceBreakdown,
  variantIdForConfig,
  getPublicVariant,
  mergePublicCatalog,
  persistDraftConfig,
  submitRecord,
  CartStore,
  shadeHex,
  renderBody,
  getLiveDevices,
  getHeroDeviceNames,
  Logo,
  Nav,
  Ticker,
  Footer,
  StockBadge,
  ProductPreview,
  PageHero,
  SpecRow,
  ReviewsSection
});
