/* YeYe Expat Centre — Pages (all translated) */
const P = window.YEYE;
const GHL_READ_BASE = 'https://ghl-read-service-ib6dfdthbq-ew.a.run.app';
const GHL_WRITE_BASE = (window.YEYE_CONFIG && (window.YEYE_CONFIG.WRITE_API_URL || window.YEYE_CONFIG.GHL_WRITE_API_URL)) || 'https://ghl-write-service-ib6dfdthbq-ew.a.run.app';
const GHL_WRITE_KEY = (window.YEYE_CONFIG && (window.YEYE_CONFIG.WRITE_API_KEY || window.YEYE_CONFIG.GHL_WRITE_API_KEY)) || '';

function PageHead({ title, sub, actions }) {
  return (
    <div className="phead">
      <div className="pt"><h1 className="h1">{title}</h1>{sub && <div className="muted">{sub}</div>}</div>
      {actions && <div className="flex gap-8 wrap">{actions}</div>}
    </div>
  );
}
function svcName(s, t, lang = 'en') {
  const nameKey = 'services.name.' + s.k;
  const translatedName = t(nameKey);
  if (translatedName !== nameKey) return translatedName;
  const legacyKey = 'svc.' + s.k;
  const translatedLegacy = t(legacyKey);
  return translatedLegacy === legacyKey ? (localizedText(s.name, lang) || s.k) : translatedLegacy;
}
function localizedText(value, lang = 'en') {
  if (!value || typeof value !== 'object') return value;
  return value[lang] || value.en || value.tr || value.cs || '';
}
function svcCatName(s, t) {
  const translated = t('scat.' + s.cat);
  return translated === 'scat.' + s.cat ? (s.catName || (P.catLabels && P.catLabels[s.cat]) || s.cat) : translated;
}
const CURRENCY_RATES = { EUR: 1, CZK: 24.24, TRY: 53.72 };
function eurValue(s) {
  const m = String((s && s.p) || '').match(/€\s*([0-9]+(?:[.,][0-9]+)?)/);
  return m ? Number(m[1].replace(',', '.')) : null;
}
function moneyLabel(value, currency) {
  if (!Number.isFinite(value)) return '';
  const digits = currency === 'CZK' ? 0 : 2;
  const amount = Number(value).toLocaleString('tr-TR', { minimumFractionDigits: digits, maximumFractionDigits: digits });
  if (currency === 'CZK') return amount + ' CZK';
  if (currency === 'TRY') return amount + ' TL';
  return '€' + amount;
}
function svcPrice(s, currency = 'EUR') {
  const eur = eurValue(s);
  if (eur == null) return s.priceLabel || s.p || 'Ask for price';
  return moneyLabel(eur * (CURRENCY_RATES[currency] || 1), currency) + (s.u || '');
}

/* ===== SERVICES — real catalog grouped by category ===== */
function isFreshUserEmail() {
  try {
    const u = window.YEYE_AUTH && window.YEYE_AUTH.getState && window.YEYE_AUTH.getState().user;
    const e = u && u.email;
    return !!e && ['toptenvideoyou@gmail.com', 'testblue.demo+20260619@yeye-internal.example.com'].includes(e.toLowerCase());
  } catch (_) { return false; }
}
function serviceVariantIsDiy(variant) {
  return !!variant && (
    variant.labelKey === 'svc.variant.diy'
    || variant.tier === 'DIY'
    || /_diy$/.test(String(variant.k || ''))
  );
}

function serviceVariantsForMode(variants, mode) {
  const rows = Array.isArray(variants) ? variants : [];
  if (mode === 'diy') return rows.filter(serviceVariantIsDiy);
  if (mode === 'professional') return rows.filter((variant) => !serviceVariantIsDiy(variant));
  return rows;
}

function ServiceCard({ s, openModal, forceUnowned, purchased, serviceMode = 'all' }) {
  const { t, lang, currency } = useT();
  const allTabs = Array.isArray(s.tabs) ? s.tabs : [];
  const tabs = serviceMode === 'all' ? allTabs : allTabs.filter((tab) => {
    const variants = Array.isArray(tab.variants) ? tab.variants : [];
    if (!variants.length) return serviceMode === 'professional';
    return serviceVariantsForMode(variants, serviceMode).length > 0;
  });
  const [selectedTab, setSelectedTab] = useState(tabs[0] && tabs[0].k);
  const soloVariantHost = (!s.family || !tabs.length) && Array.isArray(s.variants) && s.variants.length > 0 ? s : null;
  const activeTab = tabs.find((tab) => tab.k === selectedTab) || tabs[0] || soloVariantHost;
  const [selectedVariant, setSelectedVariant] = useState(activeTab && activeTab.variants && activeTab.variants[0] && activeTab.variants[0].k);
  const activeVariants = !s.comingSoon && activeTab
    ? serviceVariantsForMode(activeTab.variants, serviceMode)
    : [];
  useEffect(() => {
    if (!tabs.some((tab) => tab.k === selectedTab)) setSelectedTab(tabs[0] && tabs[0].k);
    setSelectedVariant(activeVariants[0] && activeVariants[0].k);
  }, [selectedTab, serviceMode]);
  const activeVariant = activeVariants.find((variant) => variant.k === selectedVariant) || activeVariants[0];
  const localizeAskForPrice = (v) => (v === 'Ask for price' ? t('svc.comingSoon') : v);
  const familyPrice = activeTab ? localizeAskForPrice(svcPrice({ p: (activeVariant && activeVariant.price) || activeTab.price, priceLabel: (activeVariant && activeVariant.priceLabel) || activeTab.priceLabel, u: (activeVariant && activeVariant.u) || activeTab.u }, currency)) : '';
  const familyPriceLabel = (activeVariant && activeVariant.priceLabel) || (activeTab && activeTab.priceLabel);
  const price = localizeAskForPrice(svcPrice(s, currency));
  const owned = purchased || (s.owned && !forceUnowned);
  const title = svcName(s, t, lang);
  const catLabel = svcCatName(s, t);
  const handleNotifyMe = () => {
    openModal('ticket', { catK: 'sro', subject: 'Notify me: ' + title });
  };
  const handleFamilyReview = () => {
    if (!activeTab) return;
    if (s.comingSoon) {
      handleNotifyMe();
      return;
    }
    if (!s.family && activeVariant) {
      openModal('service', {
        ...s,
        k: activeVariant.k || s.k,
        parentK: s.k,
        p: activeVariant.price || s.p,
        priceLabel: activeVariant.priceLabel || s.priceLabel,
        u: activeVariant.u || s.u,
        payUrl: activeVariant.payUrl != null ? activeVariant.payUrl : s.payUrl,
        description: activeVariant.description || s.description,
        deliverables: activeVariant.deliverables || s.deliverables,
        _activeTabKey: s.k,
        _activeVariantKey: activeVariant.k,
      });
      return;
    }
    openModal('service', { ...s, _activeTabKey: activeTab.k, _activeVariantKey: activeVariant && activeVariant.k });
  };
  if ((s.family && tabs.length) || (soloVariantHost && activeVariants.length > 0)) {
    return (
      <Card className="card-pad svc-card">
        <header className="svc-card-head">
          <div className="hd-ic" style={{ width: 40, height: 40, borderRadius: 11, flexShrink: 0, background: owned ? 'var(--brand-50)' : 'var(--accent-50)', color: owned ? 'var(--brand-600)' : 'var(--accent-600)' }}><Icon name={P.catIcon[s.cat]} size={19} /></div>
          {s.comingSoon && <Badge tone="warn">{t('svc.comingSoon')}</Badge>}
          {owned && <Badge tone="ok" dot>{t('c.active')}</Badge>}
        </header>
        <div className="strong svc-card-title">{title}</div>
        <div className="svc-card-body">
          {s.family && tabs.length > 0 && (
            <Seg items={tabs.map((tab) => ({ value: tab.k, label: localizedText(tab.label, lang) || tab.k }))} value={activeTab.k} onChange={setSelectedTab} />
          )}
          {activeVariants.length > 1 && (
            <Seg items={activeVariants.map((variant) => ({ value: variant.k, label: variant.labelKey ? t(variant.labelKey) : (localizedText(variant.label, lang) || variant.k) }))} value={activeVariant && activeVariant.k} onChange={setSelectedVariant} />
          )}
          <div>
            <div className="strong tnum" style={{ fontSize: 18 }}>{familyPrice}</div>
          </div>
        </div>
        <footer className="svc-card-footer">
          <span className="strong tnum" style={{ fontSize: 14 }}>{familyPrice}</span>
          {s.comingSoon ? (
            <Btn variant="primary" size="sm" icon="bell" onClick={handleNotifyMe}>{t('svc.notifyMe')}</Btn>
          ) : owned ? (
            <div className="flex ac gap-8">
              <Btn variant="ghost" size="sm" icon="search" onClick={handleFamilyReview}>{t('c.review')}</Btn>
              <Btn variant="primary" size="sm" icon="shopping-cart" onClick={handleFamilyReview}>{t('svc.buyAgain')}</Btn>
            </div>
          ) : (
            <Btn variant="primary" size="sm" icon="search" onClick={handleFamilyReview}>{t('c.review')}</Btn>
          )}
        </footer>
      </Card>
    );
  }
  return (
    <Card className="card-pad svc-card">
      <header className="svc-card-head">
        <div className="hd-ic" style={{ width: 40, height: 40, borderRadius: 11, flexShrink: 0, background: owned ? 'var(--brand-50)' : 'var(--accent-50)', color: owned ? 'var(--brand-600)' : 'var(--accent-600)' }}><Icon name={P.catIcon[s.cat]} size={19} /></div>
        {s.comingSoon && <Badge tone="warn">{t('svc.comingSoon')}</Badge>}
        {owned && <Badge tone="ok" dot>{t('c.active')}</Badge>}
      </header>
      <div className="svc-card-body">
        <div>
          <div className="strong svc-card-title">{title}</div>
          <div className="svc-card-cat">{catLabel}</div>
        </div>
        <div>
          <div className="strong tnum" style={{ fontSize: 18 }}>{price}</div>
        </div>
      </div>
      <footer className="svc-card-footer">
        <span className="strong tnum" style={{ fontSize: 14 }}>{price}</span>
        {s.comingSoon ? (
          <Btn variant="primary" size="sm" icon="bell" onClick={handleNotifyMe}>{t('svc.notifyMe')}</Btn>
        ) : owned ? (
          <div className="flex ac gap-8">
            <Btn variant="ghost" size="sm" icon="search" onClick={() => openModal('service', s)}>{t('c.review')}</Btn>
            <Btn variant="primary" size="sm" icon="shopping-cart" onClick={() => openModal('service', s)}>{t('svc.buyAgain')}</Btn>
          </div>
        ) : (
          <Btn variant="primary" size="sm" icon="search" onClick={() => openModal('service', s)}>{t('c.review')}</Btn>
        )}
      </footer>
    </Card>
  );
}

function serviceFocusKeys(s) {
  const keys = [s.k];
  if (s.family && Array.isArray(s.tabs)) {
    s.tabs.forEach((tab) => {
      keys.push(tab.k);
      if (Array.isArray(tab.variants)) tab.variants.forEach((variant) => keys.push(variant.k));
    });
  }
  return keys.join(' ');
}

function ServiceCategoryStrip({ cats, visibleServices, ownedKeys, t }) {
  const rows = (cats || []).map((cat) => {
    const count = visibleServices.filter((s) => s.cat === cat && !ownedKeys.has(s.k) && !s.comingSoon).length;
    return { cat, count };
  }).filter((row) => row.count > 0);
  if (!rows.length) return null;
  return (
    <nav className="service-cat-strip" aria-label={t('c.availableServices')}>
      {rows.map(({ cat, count }) => (
        <a className="service-cat-chip" key={cat} href={'#services-cat-' + cat}>
          <Icon name={P.catIcon[cat]} size={15} />
          <span>{svcCatName({ cat }, t)}</span>
          <span className="dim mono">{count}</span>
        </a>
      ))}
    </nav>
  );
}

function purchasedServiceDetail(base, purchase, t, lang, currency) {
  const key = String((purchase && purchase.k) || (base && base.k) || '');
  const fallback = {
    title: svcName(base, t, lang),
    category: svcCatName(base, t),
    mode: '',
    price: svcPrice(base, currency),
  };
  if (!base || !base.family || !Array.isArray(base.tabs)) return fallback;
  for (const tab of base.tabs) {
    const variants = Array.isArray(tab.variants) ? tab.variants : [];
    const picked = variants.find((variant) => variant.k === key) || (tab.k === key ? variants[0] : null);
    if (!picked) continue;
    return {
      title: localizedText(tab.label, lang) || fallback.title,
      category: fallback.title,
      mode: localizedText(picked.label, lang) || t(picked.labelKey || '') || '',
      price: svcPrice({ ...base, p: picked.price || tab.price || base.p, priceLabel: picked.priceLabel || tab.priceLabel || base.priceLabel, u: picked.u || tab.u || base.u }, currency),
    };
  }
  return fallback;
}

function catalogServiceForPurchase(key) {
  const raw = String(key || '');
  const normalize = typeof window.YEYE_NORMALIZE_SERVICE_KEY === 'function' ? window.YEYE_NORMALIZE_SERVICE_KEY : (value) => value;
  const normalized = normalize(raw);
  for (const service of (P.services || [])) {
    const keys = [service.k];
    if (service.family && Array.isArray(service.tabs)) {
      service.tabs.forEach((tab) => {
        keys.push(tab.k);
        if (Array.isArray(tab.variants)) tab.variants.forEach((variant) => keys.push(variant.k));
      });
    }
    if (keys.some((item) => item === raw || normalize(item) === normalized)) return service;
  }
  return null;
}

function isDiyPurchasedService(purchase) {
  if (!purchase) return false;
  const key = String(purchase.k || purchase.key || purchase.serviceKey || purchase.productKey || '').toLowerCase();
  const name = localizedText(purchase.name, 'en') || purchase.serviceName || purchase.title || '';
  if (purchase.tier === 'DIY-Docs' || /_diy$/.test(key) || /\s—\sDIY$/i.test(String(name))) return true;
  for (const service of (P.services || [])) {
    const options = service.family && Array.isArray(service.tabs) ? service.tabs : [service];
    for (const option of options) {
      if (option.k === key && (option.tier === 'DIY-Docs' || /_diy$/.test(String(option.k || '')) || /\s—\sDIY$/i.test(String(localizedText(option.name, 'en') || option.label || '')))) return true;
      const variant = (option.variants || []).find((item) => String(item.k || '').toLowerCase() === key);
      if (variant && (variant.tier === 'DIY-Docs' || variant.tier === 'DIY' || variant.labelKey === 'svc.variant.diy' || /_diy$/.test(String(variant.k || '')))) return true;
    }
  }
  return false;
}
window.YEYE_IS_DIY_PURCHASE = isDiyPurchasedService;

function PurchasedServiceSummary({ service, purchase, openModal }) {
  const { t, lang, currency } = useT();
  const detail = purchasedServiceDetail(service, purchase, t, lang, currency);
  const status = (purchase && purchase.status) || 'active';
  return (
    <div className="owned-service-card">
      <div className="owned-service-accent" />
      <div className="owned-service-top">
        <div className="owned-service-icon"><Icon name={P.catIcon[service.cat] || 'package-check'} size={19} /></div>
        <Badge tone={status === 'cancelled' ? 'bad' : status === 'paused' ? 'warn' : 'ok'} dot>{t('st.' + status)}</Badge>
      </div>
      <div className="owned-service-body">
        <div className="eyebrow">{detail.category}</div>
        <h3>{detail.title}</h3>
        {detail.mode && <div className="owned-service-mode">{detail.mode}</div>}
      </div>
      <div className="owned-service-foot">
        <strong className="tnum">{detail.price}</strong>
        <Btn variant="ghost" size="sm" icon="settings" onClick={() => openModal('manageService', { purchase, service })}>{t('c.manage')}</Btn>
      </div>
    </div>
  );
}

function ServicesPage({ openModal, purchasedServices, blankProfile }) {
  const { t } = useT();
  const [serviceFilter, setServiceFilter] = useState(() => {
    const requested = new URLSearchParams(window.location.search || '').get('filter');
    return ['all', 'professional', 'diy'].includes(requested) ? requested : 'all';
  });
  const fresh = blankProfile || isFreshUserEmail();
  const normalizeServiceKey = typeof window.YEYE_NORMALIZE_SERVICE_KEY === 'function' ? window.YEYE_NORMALIZE_SERVICE_KEY : (key) => key;
  const purchasedKeys = new Set((purchasedServices || []).map((x) => normalizeServiceKey(x.k)));
  const familyKeys = (s) => {
    const keys = [s.k];
    if (s.family && Array.isArray(s.tabs)) {
      s.tabs.forEach((tab) => {
        keys.push(tab.k);
        if (Array.isArray(tab.variants)) tab.variants.forEach((variant) => keys.push(variant.k));
      });
    }
    return keys.map((key) => normalizeServiceKey(key));
  };
  const purchaseForService = (s) => {
    const keys = new Set(familyKeys(s));
    return (purchasedServices || []).find((row) => keys.has(normalizeServiceKey(row.k))) || null;
  };
  const isOwned = (s) => familyKeys(s).some((key) => purchasedKeys.has(key)) || (!fresh && s.owned);
  const serviceHasMode = (service, mode) => {
    const options = service.family && Array.isArray(service.tabs) ? service.tabs : [service];
    const variants = options.flatMap((option) => Array.isArray(option.variants) ? option.variants : []);
    if (variants.length) return serviceVariantsForMode(variants, mode).length > 0;
    return mode === 'professional' && service.tier !== 'DIY' && !String(service.k || '').endsWith('_diy');
  };
  const changeServiceFilter = (nextFilter) => {
    setServiceFilter(nextFilter);
    const params = new URLSearchParams(window.location.search || '');
    if (nextFilter === 'all') params.delete('filter');
    else params.set('filter', nextFilter);
    const query = params.toString();
    try { window.history.replaceState({}, '', window.location.pathname + (query ? '?' + query : '') + window.location.hash); } catch (_) {}
  };
  const visibleServices = P.services.filter((s) => (
    !s.hiddenFromGrid && (serviceFilter === 'all' || serviceHasMode(s, serviceFilter))
  ));
  const owned = visibleServices.filter((s) => isOwned(s));
  const ownedKeys = new Set(owned.map((s) => s.k));
  const availableServices = visibleServices.filter((s) => !ownedKeys.has(s.k) && !s.comingSoon);
  const availableCount = availableServices.length;
  const comingSoonCount = visibleServices.filter((s) => !ownedKeys.has(s.k) && s.comingSoon).length;
  return (
    <>
      <div className="services-filter mb-20">
        <Seg items={[
          { value: 'all', label: t('services.filter.all') },
          { value: 'professional', label: t('services.filter.professional') },
          { value: 'diy', label: t('services.filter.diy') },
        ]} value={serviceFilter} onChange={changeServiceFilter} />
      </div>
      <ServiceCategoryStrip cats={P.serviceCats} visibleServices={visibleServices} ownedKeys={ownedKeys} t={t} />
      {owned.length > 0 && (
        <>
          <div className="flex ac gap-8 mb-12"><div className="eyebrow">{t('c.myServices')}</div><Badge tone="ok">{owned.length}</Badge></div>
          <div className="grid g-12 svc-grid mb-24" style={{ gap: 16 }}>
            {owned.map((s) => {
              const purchase = purchaseForService(s) || { id: 'owned-' + s.k, k: s.k, status: 'active' };
              return <div className="col-3" key={s.k} data-service-keys={serviceFocusKeys(s)}><PurchasedServiceSummary service={s} purchase={purchase} openModal={openModal} /></div>;
            })}
          </div>
        </>
      )}
      <div className="flex ac gap-8 mb-16 wrap">
        <div className="eyebrow">{t('c.availableServices')}</div>
        <Badge tone="neut">{availableCount}</Badge>
        {comingSoonCount > 0 && <span className="dim" style={{ fontSize: 12.5 }}>{t('svc.comingSoonCount').replace('{n}', comingSoonCount)}</span>}
      </div>
      {P.serviceCats.map((cat) => {
        const allInCat = visibleServices.filter((s) => s.cat === cat && !ownedKeys.has(s.k));
        const catComingSoon = allInCat.length > 0 && allInCat.every((s) => s.comingSoon);
        if (catComingSoon) {
          return (
            <div key={cat} id={'services-cat-' + cat} className="mb-24">
              <div className="flex ac gap-10 mb-12">
                <div className="hd-ic" style={{ width: 30, height: 30, borderRadius: 8 }}><Icon name={P.catIcon[cat]} size={16} /></div>
                <div className="h3" style={{ whiteSpace: 'nowrap', flexShrink: 0 }}>{svcCatName({ cat }, t)}</div>
              </div>
              <div className="flex ac jc gap-10" style={{ padding: '28px 20px' }}>
                <Icon name="clock" size={18} />
                <div className="h4" style={{ margin: 0 }}>{t('svc.comingSoon')}</div>
              </div>
            </div>
          );
        }
        const list = allInCat
          .filter((s) => !s.comingSoon)
          .map((s, i) => ({ s, i }))
          .sort((a, b) => {
            const ar = Number.isFinite(a.s.sortRank) ? a.s.sortRank : (a.s.family ? (a.s.eyebrow === 'most_requested' ? 0 : 1) : 3);
            const br = Number.isFinite(b.s.sortRank) ? b.s.sortRank : (b.s.family ? (b.s.eyebrow === 'most_requested' ? 0 : 1) : 3);
            return ar - br || a.i - b.i;
          })
          .map((row) => row.s);
        if (!list.length) return null;
        return (
          <div key={cat} id={'services-cat-' + cat} className="mb-24">
            <div className="flex ac gap-10 mb-12">
              <div className="hd-ic" style={{ width: 30, height: 30, borderRadius: 8 }}><Icon name={P.catIcon[cat]} size={16} /></div>
              <div className="h3" style={{ whiteSpace: 'nowrap', flexShrink: 0 }}>{svcCatName({ cat }, t)}</div>
              <span className="dim" style={{ fontSize: 12.5 }}>{list.length}</span>
            </div>
            <div className="grid g-12 svc-grid" style={{ gap: 16 }}>
              {list.map((s) => <div className="col-3" key={s.k} data-service-keys={serviceFocusKeys(s)}><ServiceCard s={s} openModal={openModal} forceUnowned={fresh} purchased={purchasedKeys.has(s.k)} serviceMode={serviceFilter} /></div>)}
            </div>
          </div>
        );
      })}
    </>
  );
}

function PurchasedServicesPage({ purchasedServices, openModal, go, blankProfile }) {
  const { t, lang, currency } = useT();
  const rows = purchasedServices || [];
  const cart = useCartState();
  const hasDiyPurchase = rows.some(isDiyPurchasedService);
  const normalizeServiceKey = typeof window.YEYE_NORMALIZE_SERVICE_KEY === 'function' ? window.YEYE_NORMALIZE_SERVICE_KEY : (key) => key;
  const processSeen = new Set();
  const processApplications = (blankProfile ? [] : (P.services || []))
    .filter((s) => s.owned)
    .concat(rows.map((row) => catalogServiceForPurchase(row.k) || row))
    .map((svc) => {
      const processType = svc.k === 'blue_card' ? 'blue_card' : (svc.k === 'emp_card' ? 'employee_card' : '');
      if (!processType || processSeen.has(processType)) return null;
      processSeen.add(processType);
      return { key: processType, labelKey: svc.k };
    })
    .filter(Boolean);
  return (
    <>
      <PageHead title={t('nav.purchasedServices')} sub={t('sub.purchasedServices')}
        actions={<Btn variant="primary" icon="grid-2x2" onClick={() => go('services')}>{t('nav.services')}</Btn>} />
      {hasDiyPurchase && <div className="mb-20"><DiyPrecheckNudge cartItems={cart.items} hasDiyPurchase /></div>}
      {processApplications.length > 0 && (
        <div className="mb-20">
          <div className="flex ac gap-8 mb-12"><div className="eyebrow">{t('dash.applications')}</div><Badge tone="info">{processApplications.length}</Badge></div>
          <div className="grid g-12" style={{ gap: 16 }}>
            {processApplications.map((app) => (
              <div className="col-6" key={app.key}>
                <ProcessTrackerCard ct={{ key: app.key }} />
              </div>
            ))}
          </div>
        </div>
      )}
      <Card>
        <CardHead icon="package-check" title={t('svc.purchasedTitle')} sub={rows.length + ' ' + t('svc.itemsWord')} />
        <div className="card-bd">
          {rows.length === 0 ? (
            <div className="muted" style={{ padding: 18, textAlign: 'center' }}>{t('svc.noPurchased')}</div>
          ) : (
            <div className="purchased-list">
              {rows.map((row) => {
                const svc = catalogServiceForPurchase(row.k) || row;
                return (
                  <div className="purchased-row" key={row.id || row.k}>
                    <div className="purchased-icon"><Icon name={P.catIcon[svc.cat] || 'package-check'} size={18} /></div>
                    <div className="purchased-main">
                      <h3>{svcName(svc, t, lang)}</h3>
                      <p>{svcCatName(svc, t)}</p>
                    </div>
                    <div className="purchased-price tnum">{svcPrice(svc, currency)}</div>
                    <Badge tone={row.status === 'cancelled' ? 'bad' : row.status === 'paused' ? 'warn' : 'ok'} dot>{t('st.' + row.status)}</Badge>
                    <Btn variant="ghost" size="sm" icon="settings" onClick={() => openModal('manageService', { purchase: row, service: svc })}>{t('c.manage')}</Btn>
                  </div>
                );
              })}
            </div>
          )}
        </div>
      </Card>
    </>
  );
}

const DOCGEN_LIBRARY_TEMPLATES = {
  application: {
    labelKey: 'docgen.doc.application', descKey: 'docgen.doc.application.desc', icon: 'file-text',
    documentKey: 'application_form', templateId: 'application_form',
    fillFormType: (serviceForm) => serviceForm === 'employee_card' ? 'employee_card_form' : serviceForm,
    fieldForm: (serviceForm) => serviceForm === 'employee_card' ? 'employee_card' : serviceForm,
    match: (file, serviceForm) => {
      const text = `${file.name || file.fileName || file.title || ''} ${file.url || file.webViewLink || ''}`.toLowerCase();
      if (serviceForm === 'employee_card') return /employee.*card|1yrdc1kfkr1es2pwcveu1rbzdeX2lq2du/i.test(text);
      return /blue.*card|1bzga_fxl0nqzykgw2_lyzfmm_ahff9r3/i.test(text);
    },
  },
  'work-contract': {
    labelKey: 'docgen.doc.workContract', descKey: 'docgen.doc.workContract.desc', icon: 'briefcase-business',
    documentKey: 'work_contract', templateId: 'truck_driver_contract',
    fillFormType: () => 'employee_onboarding', fieldForm: () => 'employee_onboarding',
    match: (file) => /pracovni|pracovní|employment contract|work contract|smlouva/i.test(String(file.name || file.fileName || file.title || '')),
  },
  salary: {
    labelKey: 'docgen.doc.salary', descKey: 'docgen.doc.salary.desc', icon: 'badge-dollar-sign',
    documentKey: 'salary_certificate', templateId: 'salary_certificate',
    fillFormType: () => 'employee_onboarding', fieldForm: () => 'employee_onboarding',
    match: (file) => /mzdov|mzda|wage|salary/i.test(String(file.name || file.fileName || file.title || '')),
  },
  poa: {
    labelKey: 'docgen.doc.poa', descKey: 'docgen.doc.poa.desc', icon: 'stamp',
    documentKey: 'power_of_attorney_salih', templateId: 'poa_salih',
    fillFormType: () => 'employee_onboarding', fieldForm: () => 'employee_onboarding',
    match: (file) => /plna moc|plná moc|power of attorney|poa/i.test(String(file.name || file.fileName || file.title || '')),
  },
  accommodation: {
    labelKey: 'docgen.doc.accommodation', descKey: 'docgen.doc.accommodation.desc', icon: 'house',
    documentKey: 'accommodation_confirmation', templateId: 'accommodation_confirmation',
    fillFormType: () => 'employee_onboarding', fieldForm: () => 'employee_onboarding',
    match: (file) => /accommodation|ubytovani|ubytování/i.test(String(file.name || file.fileName || file.title || '')),
  },
};

const DOCGEN_PERSON_REQUIRED_FIELDS = [
  'application_type', 'appType', 'first_name', 'firstName', 'last_name', 'lastName', 'email', 'phone',
  'date_of_birth', 'dateOfBirth', 'place_of_birth', 'country_of_birth', 'empccountryofbirth_country_list',
  'nationality', 'nationality_country_list', 'gender', 'marital_status', 'occupation', 'highest_education',
  'numChildren', 'how_many_children_do_you_have', 'numSiblings', 'how_many_siblings_do_you_have',
];
const DOCGEN_PASSPORT_REQUIRED_FIELDS = [
  'passport_number', 'passport_date_of_issue', 'passport_expiry_date', 'passport_expiry',
  'passport_place_of_issue', 'passport_country_of_issue', 'passport_country_of_issue_country_list',
];
const DOCGEN_RESIDENCE_REQUIRED_FIELDS = [
  'resCountry', 'country_residence', 'country_residence_country_list',
  'resMunicipality', 'municipality_in_residence', 'resDistrict', 'district',
  'resStreetNumber', 'street_number', 'resBuildingNumber', 'building_no', 'resPostalCode', 'zip_code',
];
const DOCGEN_CZECHIA_ADDRESS_REQUIRED_FIELDS = [
  'municipality_in_czechia', 'district_in_czechia', 'street_number_in_czechia',
  'building_number_in_czechia', 'postalzip_code_in_czechia', 'arrival_date',
];
const DOCGEN_EMPLOYMENT_REQUIRED_FIELDS = [
  'cpcomanyname', 'company_name', 'employer_name', 'contactemployee_job_position', 'job_position',
  'company_address_country', 'company_address_country_country_list', 'company_address_municipality',
  'company_address_district', 'company_address_street', 'company_address_building_number',
  'company_address_postal_zip_code',
  'employee_contract_start_date', 'contract_start', 'employee_contract_end_date', 'contract_end',
  'contactemployee_work_address', 'place_of_work', 'salary',
];
const DOCGEN_CARD_REQUIRED_FIELDS = [
  ...DOCGEN_PERSON_REQUIRED_FIELDS,
  ...DOCGEN_PASSPORT_REQUIRED_FIELDS,
  ...DOCGEN_RESIDENCE_REQUIRED_FIELDS,
  ...DOCGEN_CZECHIA_ADDRESS_REQUIRED_FIELDS,
  ...DOCGEN_EMPLOYMENT_REQUIRED_FIELDS,
];
const DOCGEN_EMPLOYEE_ONBOARDING_REQUIRED_FIELDS = DOCGEN_CARD_REQUIRED_FIELDS;

const DOCGEN_HARD_REQUIRED_FIELDS = {
  blue_card: DOCGEN_CARD_REQUIRED_FIELDS,
  blue_card_form: DOCGEN_CARD_REQUIRED_FIELDS,
  employee_card: DOCGEN_CARD_REQUIRED_FIELDS,
  employee_card_form: DOCGEN_CARD_REQUIRED_FIELDS,
  employee_onboarding: DOCGEN_EMPLOYEE_ONBOARDING_REQUIRED_FIELDS,
  application: DOCGEN_CARD_REQUIRED_FIELDS,
  application_form: DOCGEN_CARD_REQUIRED_FIELDS,
  'work-contract': ['first_name', 'last_name', ...DOCGEN_PASSPORT_REQUIRED_FIELDS, ...DOCGEN_EMPLOYMENT_REQUIRED_FIELDS],
  work_contract: ['first_name', 'last_name', ...DOCGEN_PASSPORT_REQUIRED_FIELDS, ...DOCGEN_EMPLOYMENT_REQUIRED_FIELDS],
  salary: ['first_name', 'last_name', ...DOCGEN_EMPLOYMENT_REQUIRED_FIELDS],
  salary_certificate: ['first_name', 'last_name', ...DOCGEN_EMPLOYMENT_REQUIRED_FIELDS],
  poa: ['first_name', 'last_name', 'date_of_birth', 'place_of_birth', 'nationality', ...DOCGEN_PASSPORT_REQUIRED_FIELDS],
  power_of_attorney: ['first_name', 'last_name', 'date_of_birth', 'place_of_birth', 'nationality', ...DOCGEN_PASSPORT_REQUIRED_FIELDS],
  power_of_attorney_salih: ['first_name', 'last_name', 'date_of_birth', 'place_of_birth', 'nationality', ...DOCGEN_PASSPORT_REQUIRED_FIELDS],
  accommodation: ['first_name', 'last_name', 'date_of_birth', ...DOCGEN_CZECHIA_ADDRESS_REQUIRED_FIELDS],
  accommodation_confirmation: ['first_name', 'last_name', 'date_of_birth', ...DOCGEN_CZECHIA_ADDRESS_REQUIRED_FIELDS],
};

function normalizeDocgenFieldKey(value) {
  return String(value || '')
    .replace(/^(?:contact|business)[.\s_-]+/i, '')
    .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '_')
    .replace(/^_+|_+$/g, '');
}

function docgenRowIdentifiers(row) {
  return [row?.fieldName, row?.fieldKey, row?.key, row?.formKey, row?.updateKey]
    .filter(Boolean)
    .map(normalizeDocgenFieldKey);
}

function docgenHasValue(value) {
  if (Array.isArray(value)) return value.some(docgenHasValue);
  if (value === undefined || value === null) return false;
  const normalized = String(value).trim().toLowerCase();
  return normalized !== '' && normalized !== '—' && normalized !== 'eksik';
}

function filterDocgenRequiredRows(rows, documentSlug) {
  const knownDocumentSlug = Object.prototype.hasOwnProperty.call(DOCGEN_HARD_REQUIRED_FIELDS, documentSlug);
  const hardRequired = new Set((DOCGEN_HARD_REQUIRED_FIELDS[documentSlug] || []).map(normalizeDocgenFieldKey));
  return (rows || []).filter((row) => {
    const missing = ![row?.value, row?.v].some(docgenHasValue);
    const required = !knownDocumentSlug || row?.required === true || docgenRowIdentifiers(row).some((key) => hardRequired.has(key));
    return missing && required;
  });
}

function inferDocgenSchemaSectionId(row, schemaRows) {
  const canonicalSectionId = window.YEYE_FIELD_MAPPING?.sectionIdFor?.(row);
  if (canonicalSectionId) return canonicalSectionId;
  const wanted = new Set(docgenRowIdentifiers(row));
  const match = (schemaRows || []).find((schemaRow) => docgenRowIdentifiers(schemaRow).some((key) => wanted.has(key)));
  return String(match?.sectionId || row?.sectionId || '');
}

function docgenSectionGroup(sectionId) {
  const groups = {
    contact_kisisel_iletisim: 'contact',
    personal_information: 'personal',
    company: 'company',
    eob_calisma_izin: 'company',
    last_employment: 'lastEmployment',
    residence_abroad: 'residence',
    czechia_address: 'czechia',
    shipping_address_shippingsameasczechia_no_ise_gosterilir: 'shipping',
    passport_travel_document: 'passport',
    spouse_maritalstatus_married_ise: 'family',
    children_1_4_dinamik: 'family',
    parents: 'family',
    siblings_1_4_dinamik: 'family',
  };
  return groups[sectionId] || 'other';
}

function groupDocgenRows(rows, schemaRows, t) {
  const groups = new Map();
  (rows || []).forEach((row) => {
    const schemaSectionId = inferDocgenSchemaSectionId(row, schemaRows);
    const group = docgenSectionGroup(schemaSectionId);
    if (!groups.has(group)) groups.set(group, { id: group, schemaSectionId, title: t(`docgen.section.${group}`), rows: [] });
    groups.get(group).rows.push({ ...row, __docgenSectionId: schemaSectionId });
  });
  return Array.from(groups.values());
}

function docgenFiles(payload) {
  return [].concat(payload?.documents || [], payload?.generated || [], payload?.generatedDocs || [], payload?.files || [])
    .flatMap((file) => file?.files?.length ? file.files : [file])
    .filter(Boolean);
}

function normalizeDocgenResult(payload, doc, base) {
  const files = docgenFiles(payload);
  const matchedFile = files.find((file) => docgenFileMatches(file, doc)) ||
    files.find((file) => doc.match && doc.match(file, doc.serviceFormType)) ||
    files.find((file) => file.pdfUrl || file.downloadUrl || file.url || file.webViewLink || file.webContentLink) ||
    {};
  const pdfUrls = [].concat(matchedFile.pdfUrl || [], matchedFile.pdfUrls || [], payload.pdfUrls || [], payload.pdfUrl || []).filter(Boolean);
  const payloadPdfUrl = [].concat(payload.pdfUrls || []).filter(Boolean)[0] || '';
  const documentUrl = matchedFile.pdfUrl || matchedFile.downloadUrl || matchedFile.url || matchedFile.webViewLink || matchedFile.webContentLink ||
    payloadPdfUrl || payload.downloadUrl || payload.documentUrl || '';
  const documentId = matchedFile.pdfId || matchedFile.id || matchedFile.fileId || driveFileId(documentUrl) || payload.documentId || payload.primaryFileId || payload.pdfId || '';
  const directDownloadUrl = matchedFile.pdfUrl || matchedFile.downloadUrl || payload.downloadUrl || '';
  return {
    ...payload,
    pdfUrls,
    documentUrl,
    previewUrl: docgenPreviewUrl(documentUrl, documentId, base),
    downloadUrl: directDownloadUrl || (documentId && base ? `${base}/public/download/${encodeURIComponent(documentId)}` : documentUrl),
    downloadDocxUrl: documentId && base ? `${base}/public/download/${encodeURIComponent(documentId)}?format=docx` : '',
    folderUrl: payload.folderUrl || matchedFile.folderUrl || (payload.folder && payload.folder.url) || '',
    fileName: matchedFile.name || matchedFile.fileName || payload.fileName || '',
    placeholdersReplaced: payload.placeholdersReplaced ?? matchedFile.placeholdersReplaced ?? (payload.documents && payload.documents[0] && payload.documents[0].placeholdersReplaced) ?? 0,
  };
}

function docgenFileMatches(file, doc) {
  if (!file || !doc) return false;
  const haystack = [
    file.documentKey,
    file.document_key,
    file.templateId,
    file.template_id,
    file.type,
    file.key,
    file.name,
    file.fileName,
    file.title,
    file.url,
    file.webViewLink,
    file.pdfUrl,
  ].filter(Boolean).join(' ').toLowerCase();
  return [doc.documentKey, doc.templateId, doc.slug]
    .filter(Boolean)
    .some((value) => haystack.includes(String(value).toLowerCase().replace(/^tpl_/, '')));
}

function appendPdfHash(url) {
  const raw = String(url || '');
  return raw && !raw.includes('#') ? `${raw}#toolbar=0&navpanes=0&scrollbar=1` : raw;
}

function docgenPreviewUrl(url, fileId, baseUrl) {
  const raw = String(url || '');
  if (!raw) return '';
  if (/\.pdf(?:$|[?#])/i.test(raw)) return appendPdfHash(raw);
  if (fileId && /(?:docs|drive)\.google\.com\//i.test(raw) && baseUrl) {
    return appendPdfHash(`${String(baseUrl).replace(/\/$/, '')}/public/download/${encodeURIComponent(fileId)}?inline=1`);
  }
  if (/docs\.google\.com\/document\/d\/[^/]+\/edit/i.test(raw)) return raw.replace(/\/edit(?:[?#].*)?$/i, '/preview');
  if (/drive\.google\.com\/file\/d\/[^/]+\/view/i.test(raw)) return raw.replace(/\/view(?:[?#].*)?$/i, '/preview');
  return raw;
}

function DocGeneratorPage({ purchasedServices, contact, fieldMappings, onRefresh, onOptimisticUpdate }) {
  const { t, lang, currency } = useT();
  const diyServices = (purchasedServices || []).filter(isDiyPurchasedService);
  const [expandedServices, setExpandedServices] = React.useState(() => ({}));
  const [selectedDocId, setSelectedDocId] = React.useState('');
  const [results, setResults] = React.useState({});
  const [phase, setPhase] = React.useState('idle');
  const [error, setError] = React.useState('');
  const [statusIndex, setStatusIndex] = React.useState(0);
  const [generationCounts, setGenerationCounts] = React.useState({});
  const [fieldDrafts, setFieldDrafts] = React.useState({});
  const [savedFieldValues, setSavedFieldValues] = React.useState({});
  const [fieldModalOpen, setFieldModalOpen] = React.useState(false);
  const [savingFields, setSavingFields] = React.useState(false);
  const requestRef = React.useRef(0);
  const contactId = contact && (contact.contactId || contact.id);
  const docTemplates = ['application', 'work-contract', 'salary', 'poa', 'accommodation'];
  const serviceRows = diyServices.map((purchase, index) => {
    const service = catalogServiceForPurchase(purchase.k) || purchase;
    const detail = purchasedServiceDetail(service, purchase, t, lang, currency);
    const rawKey = String(purchase.k || purchase.key || purchase.serviceKey || purchase.productKey || service.k || '').toLowerCase();
    const normalizedKey = typeof window.YEYE_NORMALIZE_SERVICE_KEY === 'function' ? window.YEYE_NORMALIZE_SERVICE_KEY(rawKey) : rawKey.replace(/_diy$/, '');
    const declaredFormType = String(purchase.formType || purchase.form_type || service.formType || service.form_type || '').toLowerCase();
    let formType = '';
    if (['blue_card', 'blue_card_diy'].includes(rawKey) || normalizedKey === 'blue_card') formType = 'blue_card';
    else if (['employee_card', 'employee_card_diy', 'emp_card', 'emp_card_diy'].includes(rawKey) || ['employee_card', 'emp_card'].includes(normalizedKey)) formType = 'employee_card';
    else if (['employee_onboarding', 'employee_onboarding_diy'].includes(rawKey) || normalizedKey === 'employee_onboarding') formType = 'employee_onboarding';
    else if (['ce', 'company_establishment', 'sro_establishment', 'sro_establishment_diy'].includes(rawKey) || ['ce', 'company_establishment', 'sro_establishment'].includes(normalizedKey)) formType = 'ce';
    else if (declaredFormType === 'employee_card_form') formType = 'employee_card';
    else if (declaredFormType === 'company_establishment') formType = 'ce';
    else if (['blue_card', 'employee_card', 'employee_onboarding', 'ce'].includes(declaredFormType)) formType = declaredFormType;
    const isCardService = formType === 'blue_card' || formType === 'employee_card';
    const serviceId = String(purchase.id || rawKey || 'service') + '-' + index;
    const documents = (isCardService ? docTemplates : ['application']).map((slug) => {
      const template = DOCGEN_LIBRARY_TEMPLATES[slug] || DOCGEN_LIBRARY_TEMPLATES.application;
      const fillFormType = typeof template.fillFormType === 'function' ? template.fillFormType(formType) : formType;
      const fieldForm = typeof template.fieldForm === 'function' ? template.fieldForm(formType) : formType;
      return ({
      ...template,
      slug,
      id: serviceId + '-' + slug,
      serviceFormType: formType,
      formType: fillFormType,
      fieldForm,
      documentKey: template.documentKey,
      templateId: template.templateId,
      disabled: !formType,
    });
    });
    return { purchase, service, detail, serviceId, documents };
  });
  const allDocuments = serviceRows.reduce((items, row) => items.concat(row.documents), []);
  const selectedDoc = allDocuments.find((doc) => doc.id === selectedDocId) || null;
  const selectedResult = selectedDoc ? results[selectedDoc.id] : null;
  const rawMappedRows = selectedDoc && window.YEYE_FIELD_MAPPING
    ? window.YEYE_FIELD_MAPPING.forForm(fieldMappings || [], selectedDoc.fieldForm || selectedDoc.formType, contact || {})
    : [];
  const mappedRows = rawMappedRows.map((row) => {
    const savedKey = docgenRowIdentifiers(row).find((key) => Object.prototype.hasOwnProperty.call(savedFieldValues, key));
    return savedKey ? { ...row, value: savedFieldValues[savedKey], v: savedFieldValues[savedKey] } : row;
  });
  const requiredFieldSlug = selectedDoc?.slug === 'application' ? selectedDoc.formType : selectedDoc?.slug;
  const selectedRows = filterDocgenRequiredRows(mappedRows, requiredFieldSlug);
  const selectedRowGroups = groupDocgenRows(selectedRows, fieldMappings || [], t);

  const countKey = React.useCallback((doc) => `yeye-docgen-count-${contactId || 'unknown'}-${doc.formType}-${doc.slug}`, [contactId]);
  const readCount = React.useCallback((doc) => {
    try { return Math.max(0, parseInt(localStorage.getItem(countKey(doc)) || '0', 10) || 0); } catch (_) { return 0; }
  }, [countKey]);
  const selectedCount = selectedDoc ? (generationCounts[selectedDoc.id] ?? readCount(selectedDoc)) : 0;

  React.useEffect(() => {
    if (phase !== 'running') return undefined;
    setStatusIndex(0);
    const timer = window.setInterval(() => setStatusIndex((value) => (value + 1) % 3), 3500);
    return () => window.clearInterval(timer);
  }, [phase]);
  React.useEffect(() => () => { requestRef.current += 1; }, []);
  React.useEffect(() => { setSavedFieldValues({}); }, [contactId]);

  const generateDocument = React.useCallback(async (activeContact, doc) => {
    const cfg = window.YEYE_CONFIG || {};
    const base = String(cfg.FILL_API_URL || '').replace(/\/$/, '');
    if (!base) throw new Error('backend-not-configured');
    const activeContactId = activeContact && (activeContact.contactId || activeContact.id);
    if (!activeContactId) throw new Error('missing-contact');
    const url = new URL(base + '/public/fill');
    url.searchParams.set('form_type', doc.formType);
    if (doc.documentKey) url.searchParams.set('document_key', doc.documentKey);
    url.searchParams.set('create_pdf', 'true');
    url.searchParams.set('sync_sheet', 'false');
    url.searchParams.set('target', 'clientview');
    const contactName = [activeContact.firstName, activeContact.lastName].filter(Boolean).join(' ') || activeContact.name || activeContact.email || '';
    const response = await fetch(url.toString(), {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', ...(cfg.FILL_API_KEY ? { 'X-API-Key': cfg.FILL_API_KEY } : {}) },
      body: JSON.stringify({
        contactId: activeContactId,
        contactName,
        formType: doc.formType,
        documentKey: doc.documentKey,
        contactFields: {},
        target: 'clientview',
      }),
    });
    if (!response.ok) {
      const responseText = await response.text().catch(() => '');
      throw new Error('http-' + response.status + (responseText ? ': ' + responseText.slice(0, 120) : ''));
    }
    return normalizeDocgenResult(await response.json().catch(() => ({})), doc, base);
  }, []);

  const runGeneration = React.useCallback(async () => {
    if (!selectedDoc || selectedDoc.disabled || phase === 'running') return;
    const request = requestRef.current + 1;
    requestRef.current = request;
    setPhase('running');
    setError('');
    try {
      const payload = await generateDocument(contact, selectedDoc);
      if (requestRef.current !== request) return;
      const nextCount = readCount(selectedDoc) + 1;
      try { localStorage.setItem(countKey(selectedDoc), String(nextCount)); } catch (_) { /* Storage can be unavailable in private mode. */ }
      setGenerationCounts((previous) => ({ ...previous, [selectedDoc.id]: nextCount }));
      setResults((previous) => ({ ...previous, [selectedDoc.id]: payload }));
      setPhase('success');
      if (window.YEYE_TOAST) window.YEYE_TOAST(t('docgen.success'));
    } catch (generationError) {
      if (requestRef.current !== request) return;
      console.warn('DocGen failed', generationError);
      setError(t('docgen.errorGeneric'));
      setPhase('error');
    }
  }, [contact, countKey, generateDocument, phase, readCount, selectedDoc, t]);

  const startDocumentGeneration = () => {
    if (selectedRows.length) {
      setFieldModalOpen(true);
      return;
    }
    if (window.YEYE_TOAST) window.YEYE_TOAST(t('docgen.allRequiredReady'));
    runGeneration();
  };

  const selectDocument = (doc) => {
    if (doc.disabled) return;
    requestRef.current += 1;
    setSelectedDocId(doc.id);
    setPhase(results[doc.id] ? 'success' : 'idle');
    setError('');
    setFieldDrafts({});
    setFieldModalOpen(false);
  };
  const translatedStatus = (key, fallback) => {
    const value = t(key);
    return value === key ? fallback : value;
  };
  const statusMessages = [
    translatedStatus('docgen.rotating.1', t('docgen.generating')),
    translatedStatus('docgen.rotating.2', 'Fetching your data'),
    translatedStatus('docgen.rotating.3', 'Almost done'),
  ];
  const previewUrl = selectedResult && selectedResult.previewUrl;
  const saveMissingFields = async () => {
    if (!selectedDoc || !selectedRows.length || savingFields) return;
    setSavingFields(true);
    try {
      const patch = await saveApplicationFormAnswers(contact, fieldDrafts, selectedRows, selectedDoc.fieldForm || selectedDoc.formType);
      const savedValues = {};
      selectedRows.forEach((row) => {
        const draftKey = [row.updateKey, row.fieldName, row.key, row.formKey]
          .find((key) => key && Object.prototype.hasOwnProperty.call(fieldDrafts, key));
        if (!draftKey) return;
        docgenRowIdentifiers(row).forEach((identifier) => { savedValues[identifier] = fieldDrafts[draftKey]; });
      });
      setSavedFieldValues((previous) => ({ ...previous, ...savedValues }));
      if (onOptimisticUpdate) onOptimisticUpdate(contactId, patch);
      const remainingRows = selectedRows.filter((row) => {
        const draftKey = [row.updateKey, row.fieldName, row.key, row.formKey]
          .find((key) => key && Object.prototype.hasOwnProperty.call(fieldDrafts, key));
        return !draftKey || !docgenHasValue(fieldDrafts[draftKey]);
      });
      setFieldDrafts({});
      setFieldModalOpen(false);
      if (onRefresh) await Promise.resolve(onRefresh());
      if (window.YEYE_TOAST) window.YEYE_TOAST(t('form.savedGhl') || 'Saved');
      if (!remainingRows.length) {
        if (window.YEYE_TOAST) window.YEYE_TOAST(t('docgen.allRequiredReady'));
        await runGeneration();
      }
    } catch (err) {
      console.warn('DocGen field save failed', err);
      if (window.YEYE_TOAST) window.YEYE_TOAST((err && err.message) || 'Save failed');
    } finally {
      setSavingFields(false);
    }
  };
  return (
    <>
      <PageHead title={t('docgen.pageTitle')} sub={t('docgen.pageIntro')} />
      <section aria-label={t('docgen.pageTitle')}>
        {diyServices.length === 0 ? (
          <Card>
            <div className="card-bd" style={{ padding: 24, textAlign: 'center' }}>
              <div style={{ color: 'var(--ink-500)', fontSize: 13.5 }}>{t('docgen.emptyState')}</div>
            </div>
          </Card>
        ) : (
          <div className="docgen-wizard">
            <aside className="docgen-services-panel">
              <div className="flex ac gap-8 mb-12">
                <div className="eyebrow">{t('docgen.leftTitle')}</div>
                <Badge tone="info">{diyServices.length}</Badge>
              </div>
              <div className="docgen-service-list">
                {serviceRows.map((row, index) => {
                  const isExpanded = expandedServices[row.serviceId] ?? index === 0;
                  return (
                    <Card className="docgen-service-card" key={row.serviceId}>
                      <button type="button" className="docgen-service-toggle" aria-expanded={isExpanded} onClick={() => setExpandedServices((previous) => ({ ...previous, [row.serviceId]: !isExpanded }))}>
                        <span className="docgen-service-icon"><Icon name={P.catIcon[row.service.cat] || 'package-check'} size={17} /></span>
                        <span>{row.detail.title}</span>
                        <Icon name={isExpanded ? 'chevron-up' : 'chevron-down'} size={15} />
                      </button>
                      {isExpanded && (
                        <div className="docgen-document-list">
                          {row.documents.map((doc) => (
                            <button type="button" key={doc.id} disabled={doc.disabled} className={'docgen-document-row' + (selectedDocId === doc.id ? ' is-selected' : '') + (doc.disabled ? ' is-disabled' : '')} onClick={() => selectDocument(doc)}>
                              <Icon name={doc.icon} size={15} />
                              <span>{t(doc.labelKey)}</span>
                              {doc.disabled && <small>{t('docgen.templateComingSoon')}</small>}
                            </button>
                          ))}
                        </div>
                      )}
                    </Card>
                  );
                })}
              </div>
            </aside>

            <main className="docgen-detail-panel">
              <Card style={{ height: '100%' }}>
                {!selectedDoc ? (
                  <div className="docgen-panel-empty"><Icon name="mouse-pointer-click" size={28} /><span>{t('docgen.selectDoc')}</span></div>
                ) : (
                  <div className="card-bd docgen-detail-body">
                    <div className="docgen-detail-heading">
                      <span className="docgen-detail-icon"><Icon name={selectedDoc.icon} size={22} /></span>
                      <div><div className="h2">{t(selectedDoc.labelKey)}</div><div className="muted">{t(selectedDoc.descKey)}</div></div>
                    </div>
                    <div className="docgen-count"><Icon name="history" size={14} />{t('docgen.generatedNTimes').replace('{n}', selectedCount)}</div>
                    <div className="docgen-field-summary">
                      <div className="docgen-missing-head">
                        <div>
                          <div className="strong">{t('docgen.fieldsTitle')}</div>
                          <div className="muted" style={{ fontSize: 12 }}>{t('docgen.fieldsSub')}</div>
                        </div>
                        {selectedRows.length > 0 && <Badge tone="info">{selectedRows.length}</Badge>}
                      </div>
                      {selectedRows.length > 0 ? (
                        <Btn variant="ghost" icon="form-input" onClick={() => setFieldModalOpen(true)}>
                          {t('docgen.openFieldsBtn')}
                        </Btn>
                      ) : (
                        <div className="muted" style={{ fontSize: 12 }}>{t('docgen.allRequiredReady')}</div>
                      )}
                    </div>
                    <div style={{ marginTop: 'auto' }}>
                      <Btn className="btn-block" variant="primary" size="lg" icon="file-plus-2" disabled={phase === 'running'} onClick={startDocumentGeneration}>
                        {phase === 'running' ? t('docgen.generating') : t('docgen.generateBtn')}
                      </Btn>
                      <div className="muted" style={{ fontSize: 12, marginTop: 10 }}>{t('docgen.readyToGenerate')}</div>
                    </div>
                  </div>
                )}
              </Card>
            </main>

            <aside className="docgen-preview-panel">
              <Card>
                <CardHead icon="scan-eye" title={t('docgen.previewTitle')} />
                <div className="card-bd docgen-preview-body">
                  {phase === 'running' ? (
                    <div className="docgen-preview-status" role="status" aria-live="polite"><span className="docgen-spinner docgen-loading-spinner" /><div>{statusMessages[statusIndex]}</div></div>
                  ) : phase === 'error' ? (
                    <div className="docgen-preview-status is-error"><Icon name="circle-x" size={30} /><div>{error}</div><Btn variant="primary" size="sm" icon="refresh-cw" onClick={runGeneration}>{t('docgen.regenerateBtn')}</Btn></div>
                  ) : selectedResult ? (
                    <>
                      {previewUrl ? (
                        <iframe className="docgen-preview-frame" title={t(selectedDoc.labelKey)} src={previewUrl} />
                      ) : (
                        <div className="docgen-panel-empty"><Icon name="file-search" size={28} /><span>{t('doc.noPreview')}</span></div>
                      )}
                      <div className="docgen-preview-actions">
                        {selectedResult.downloadUrl && <a className="btn btn-primary" href={selectedResult.downloadUrl} download={selectedResult.fileName || true}><Icon name="download" size={16} />{t('docgen.downloadPdf')}</a>}
                        {selectedResult.downloadDocxUrl && <a className="btn btn-ghost" href={selectedResult.downloadDocxUrl} download={selectedResult.fileName || true}><Icon name="download" size={16} />{t('docgen.downloadDocx')}</a>}
                        <Btn variant="ghost" icon="refresh-cw" onClick={runGeneration}>{t('docgen.regenerateBtn')}</Btn>
                      </div>
                      <div className="docgen-fields-filled">{t('docgen.fieldsFilled').replace('{n}', selectedResult.placeholdersReplaced || 0)}</div>
                    </>
                  ) : (
                    <div className="docgen-panel-empty"><Icon name="file-search" size={28} /><span>{t('docgen.previewEmpty')}</span></div>
                  )}
                </div>
              </Card>
            </aside>
          </div>
        )}
      </section>
      {fieldModalOpen && selectedDoc && (
        <Modal
          title={t('docgen.completeMissingTitle')}
          sub={t(selectedDoc.labelKey)}
          icon="form-input"
          onClose={() => !savingFields && setFieldModalOpen(false)}
          footer={(
            <>
              <Btn variant="ghost" disabled={savingFields} onClick={() => setFieldModalOpen(false)}>{t('c.cancel')}</Btn>
              <Btn variant="ghost" icon="wand" disabled={savingFields} onClick={() => {
                const missingCount = selectedRows.length;
                const confirmMsg = (t('docgen.generateAnywayConfirm') || 'You have {n} missing required field(s). Generate anyway?').replace('{n}', missingCount);
                if (window.confirm(confirmMsg)) {
                  setFieldModalOpen(false);
                  runGeneration();
                }
              }}>{t('docgen.generateAnyway') || 'Generate anyway'}</Btn>
              <Btn variant="primary" icon={savingFields ? 'loader-circle' : 'save'} disabled={savingFields || Object.keys(fieldDrafts).length === 0} onClick={saveMissingFields}>
                {savingFields ? t('c.saving') : t('c.save')}
              </Btn>
            </>
          )}
        >
          <div className="docgen-missing-sections">
            {selectedRowGroups.map((section) => (
              <section className="docgen-missing-section" key={section.id}>
                <div className="docgen-missing-section-head"><span>{section.title}</span></div>
                <div className="docgen-missing-grid">
                  {section.rows.map((row) => {
                    const key = row.updateKey || row.fieldName || row.key || row.formKey;
                    const kind = applicationFieldKind(row, 'text');
                    const options = applicationFieldOptions(row, null, lang);
                    const label = stripSectionContext(labelFromPlaceholder(row, lang), row.__docgenSectionId || section.id, section.title, lang);
                    return (
                      <Field key={key} label={label}>
                        {window.renderProfileFieldWidget({
                          kind,
                          value: fieldDrafts[key] ?? row.value ?? row.v ?? '',
                          onChange: (value) => setFieldDrafts((previous) => ({ ...previous, [key]: value })),
                          options,
                          label,
                          lang,
                          placeholder: t('form.missing'),
                        })}
                      </Field>
                    );
                  })}
                </div>
              </section>
            ))}
          </div>
        </Modal>
      )}
    </>
  );
}

/* ===== DOCUMENTS ===== */
function Chip({ active, onClick, children }) {
  return <button type="button" onClick={onClick}
    style={{ border: '1px solid ' + (active ? 'var(--brand-300)' : 'var(--line)'), background: active ? 'var(--brand-50)' : 'var(--surface-2)', color: active ? 'var(--brand-700)' : 'var(--ink)', padding: '6px 12px', borderRadius: 999, fontSize: 12.5, fontWeight: 500 }}>{children}</button>;
}

const ARCHIVE_FOLDER_NAMES = {
  f_relocation: 'Relocation',
  f_accommodation_re: 'Accommodation & Real Estate',
  f_translations: 'Translations',
  f_osvc: 'Free Trade Licence (OSVC)',
  f_sro: 'LTD (SRO) Set-up',
  f_tax: 'Tax & Financial',
  f_vehicle: 'Vehicle & Driving Licence',
  f_legal: 'Legal Support',
  f_permanent: 'Permanent & Citizenship',
  f_education: 'Education',
  f_identity: 'Identity and Passaport',
  f_health: 'Health',
};
function folderTkToSubName(tk, folder) {
  if (folder && folder.archiveName) return folder.archiveName;
  return ARCHIVE_FOLDER_NAMES[tk] || String(tk || '').replace(/^f_/, '').replace(/\b\w/g, (s) => s.toUpperCase());
}
function subNameToFolderTk(name) {
  if (name === 'Blue Card' || name === 'Employee Card') return 'f_relocation';
  const found = Object.keys(ARCHIVE_FOLDER_NAMES).find((tk) => ARCHIVE_FOLDER_NAMES[tk] === name);
  return found || '';
}
function driveFileMeta(file) {
  const bits = [];
  if (file.modifiedTime) {
    const d = new Date(file.modifiedTime);
    bits.push(Number.isNaN(d.getTime()) ? String(file.modifiedTime).slice(0, 10) : d.toLocaleDateString(undefined, { day: 'numeric', month: 'short' }));
  }
  if (file.size) bits.push(Math.max(1, Math.round(Number(file.size) / 1024)) + ' KB');
  return bits.join(' · ');
}

function FolderArchiveCard({ folder, allItems, archiveSubfolders, openFolderTk, onToggle }) {
  const { t } = useT();
  const folderItems = allItems.filter((x) => x.folderK === folder.tk);
  const archiveInfo = archiveSubfolders[folderTkToSubName(folder.tk, folder)] || {};
  const directFileCount = Number(archiveInfo.fileCount || 0);
  const totalCount = Math.max(folderItems.length, directFileCount + folderItems.filter((x) => x.source !== 'drive').length);
  const doneCount = folderItems.filter((x) => x.ok).length;
  const pendingCount = Math.max(0, totalCount - doneCount);
  const active = openFolderTk === folder.tk;
  const cardStyle = active
    ? { padding: 0, overflow: 'hidden', borderColor: 'var(--brand-300)', background: 'var(--brand-50)' }
    : { padding: 0, overflow: 'hidden' };
  return (
    <Card style={cardStyle}>
      <div onClick={() => onToggle(folder.tk)} className="pointer flex ac gap-12" style={{ padding: '14px 16px' }}>
        <div className="hd-ic" style={{ width: 40, height: 40, background: active ? 'var(--brand-100)' : 'var(--surface-3)', color: active ? 'var(--brand-700)' : 'var(--ink-500)' }}><Icon name={folder.ic} size={19} /></div>
        <div className="grow">
          <div className="strong" style={{ fontSize: 14 }}>{folder.label || t(folder.tk)}</div>
          {totalCount > 0 && (
            <div className="dim" style={{ fontSize: 12 }}>{doneCount}/{totalCount} {t('col.done')}{pendingCount > 0 ? ' · ' + pendingCount + ' ' + t('flt.pending').toLowerCase() : ''}</div>
          )}
        </div>
        {totalCount > 0 && pendingCount > 0 && <Badge tone="warn" dot>{pendingCount}</Badge>}
        <Icon name={active ? 'chevron-down' : 'chevron-right'} size={16} className="dim" />
      </div>
    </Card>
  );
}

function driveFileId(url) {
  const raw = String(url || '');
  const pathMatch = raw.match(/\/d\/([^/?#]+)/);
  if (pathMatch) return pathMatch[1];
  try { return new URL(raw).searchParams.get('id') || ''; } catch (_) { return ''; }
}

function driveDownloadUrl(file) {
  const id = (file && file.id) || driveFileId(file && (file.webViewLink || file.url));
  const base = String((window.YEYE_CONFIG && window.YEYE_CONFIG.FILL_API_URL) || '').replace(/\/$/, '');
  return id && base ? `${base}/public/download/${encodeURIComponent(id)}` : '';
}

function drivePreviewUrl(url) {
  const raw = String(url || '');
  return /drive\.google\.com\/file\/d\//.test(raw) ? raw.replace(/\/view(?:\?.*)?$/, '/preview') : raw;
}

function DocumentDetailModal({ file, onClose }) {
  const { t } = useT();
  if (!file) return null;
  const webViewLink = file.webViewLink || file.url || '';
  const downloadUrl = driveDownloadUrl(file);
  return (
    <Modal wide icon={file.ic || 'file-text'} title={file.label || file.name || t('doc.file')} sub={file.meta || t('doc.uploaded')} onClose={onClose}
      footer={<>
        <a className="btn btn-primary btn-lg" href={downloadUrl || webViewLink} download target="_blank" rel="noopener noreferrer"><Icon name="download" size={16} />{t('doc.download')}</a>
      </>}>
      {webViewLink ? (
        <iframe
          src={drivePreviewUrl(webViewLink)}
          title={file.label || file.name || t('doc.file')}
          style={{ display: 'block', width: '100%', height: 'min(58vh, 620px)', border: '1px solid var(--line)', borderRadius: 12, background: 'var(--surface-2)' }}
        />
      ) : (
        <div className="flex col ac jc gap-10" style={{ minHeight: 260, textAlign: 'center', color: 'var(--ink-500)' }}>
          <Icon name="file-question" size={32} />
          <div className="strong">{t('doc.noPreview')}</div>
        </div>
      )}
    </Modal>
  );
}

function FolderExpandedBody({ folder, allItems, filter, openModal, openUpload, onOpenDocument }) {
  const { t } = useT();
  if (!folder) return null;
  const folderItems = allItems.filter((x) => x.folderK === folder.tk);
  const filteredItems = filter === 'all' ? folderItems : (filter === 'done' ? folderItems.filter((x) => x.ok) : folderItems.filter((x) => !x.ok));
  const directItems = filteredItems.filter((x) => x.subK === '__archive');
  return (
    <div style={{ padding: '10px 12px' }}>
      {directItems.length > 0 && (
        <div style={{ padding: '10px 6px', borderTop: '1px solid var(--line-2)' }}>
          <div className="strong mb-8" style={{ fontSize: 13 }}>{t('doc.driveFiles')}</div>
          <div className="flex col gap-6">
            {directItems.map((it, i) => (
              <div key={it.source + '-' + (it.id || i)} className="flex ac gap-10 pointer" onClick={() => onOpenDocument(it)} style={{ padding: '8px 10px', border: '1px solid var(--line-2)', borderRadius: 8 }}>
                <div className="l-ic" style={{ width: 28, height: 28, background: 'var(--ok-bg)', color: 'var(--ok)' }}><Icon name={it.ic || 'file-text'} size={14} /></div>
                <div className="grow" style={{ minWidth: 0 }}>
                  <div className="nm" style={{ fontSize: 13 }}>{it.label}</div>
                  <div className="dim" style={{ fontSize: 11.5 }}>{it.meta || t('doc.uploaded')}</div>
                </div>
                {it.url && <Btn variant="ghost" size="sm" icon="eye" onClick={(e) => { e.stopPropagation(); onOpenDocument(it); }}>{t('c.open')}</Btn>}
              </div>
            ))}
          </div>
        </div>
      )}
      {folder.subs.map((sub) => {
        const subItems = filteredItems.filter((x) => x.subK === sub.tk);
        const subDone = subItems.filter((x) => x.ok).length;
        return (
          <div key={sub.tk} style={{ padding: '10px 6px', borderTop: '1px solid var(--line-2)' }}>
            <div className="flex ac jb mb-8">
              <div className="flex ac gap-8">
                <span className="strong" style={{ fontSize: 13 }}>{t(sub.tk)}</span>
                {subItems.length > 0 && <span className="dim tnum" style={{ fontSize: 11 }}>{subDone}/{subItems.length}</span>}
              </div>
              {subItems.length === 0 && (
                <Btn variant="soft" size="sm" icon="upload" onClick={(e) => { e.stopPropagation(); (openUpload || (() => openModal('upload', { folderK: folder.tk })))(folder.tk); }}>{t('c.upload')}</Btn>
              )}
            </div>
            {subItems.length === 0 && <div className="muted" style={{ fontSize: 12.5, padding: '2px 0 0' }}>{t('doc.noDocs')}</div>}
            {subItems.length > 0 && (
              <div className="flex col gap-6">
                {subItems.map((it, i) => (
                  <div key={it.source + '-' + (it.tk || it.label || i)} className={'flex ac gap-10 ' + (it.url ? 'pointer' : '')} onClick={() => it.url && onOpenDocument(it)} style={{ padding: '8px 10px', border: '1px solid var(--line-2)', borderRadius: 8 }}>
                    <div className="l-ic" style={it.ok ? { width: 28, height: 28, background: 'var(--ok-bg)', color: 'var(--ok)' } : { width: 28, height: 28, background: 'var(--surface-3)', color: 'var(--ink-500)' }}>
                      <Icon name={it.ok ? 'check' : (it.ic || 'file-warning')} size={14} />
                    </div>
                    <div className="grow" style={{ minWidth: 0 }}>
                      <div className="nm" style={{ fontSize: 13 }}>{(() => {
                        if (it.tk) {
                          const tr = t('doc.' + it.tk);
                          if (tr && tr !== 'doc.' + it.tk) return tr;
                        }
                        return it.label || '-';
                      })()}</div>
                      <div className="dim" style={{ fontSize: 11.5 }}>
                        {it.origin === 'yeye' ? t('doc.byYeYe') : (it.meta || (it.ok ? t('doc.uploaded') : t('doc.awaiting')))}
                      </div>
                    </div>
                    {it.origin === 'yeye' && <Badge tone="info" dot>{t('doc.badgeYeYe')}</Badge>}
                    {it.url && (
                      <Btn variant="ghost" size="sm" icon="eye" onClick={(e) => { e.stopPropagation(); onOpenDocument(it); }}>{t('c.open')}</Btn>
                    )}
                    <Btn variant="soft" size="sm" icon="upload" onClick={(e) => { e.stopPropagation(); (openUpload || (() => openModal('upload', { folderK: folder.tk })))(folder.tk); }}>{it.ok ? t('c.replace') : t('c.upload')}</Btn>
                  </div>
                ))}
              </div>
            )}
          </div>
        );
      })}
      {folder.subs.length === 0 && directItems.length === 0 && (
        <div style={{ padding: '10px 6px', borderTop: '1px solid var(--line-2)' }}>
          <div className="muted" style={{ fontSize: 12.5 }}>{t('doc.noDocs')}</div>
        </div>
      )}
    </div>
  );
}

const DOCGEN_DIY_KEYS = [
  'blue_card_diy', 'blue_card_ext_diy', 'emp_card_diy', 'eu_temp_residence_diy',
  'eu_perm_residence_diy', 'trade_cz_diy', 'pausalni_tax_registration_diy',
  'sro_establishment_diy', 'eu_vat_registration_diy', 'eori_registration_diy',
  'vehicle_registration_diy', 'vehicle_registration_non_eu_diy', 'vehicle_inspection_diy',
];

function diyCatalogOffer(key) {
  const services = (window.YEYE && window.YEYE.services) || [];
  for (const service of services) {
    const options = service.family && Array.isArray(service.tabs) ? service.tabs : [service];
    for (const option of options) {
      if (option.k === key) return { service, offer: option };
      const variant = (option.variants || []).find((item) => item.k === key);
      if (variant) return { service, offer: variant, option };
    }
  }
  return null;
}

function diyOfferName(found, t, lang) {
  if (!found) return '';
  const optionLabel = found.option && found.option.label;
  if (optionLabel && typeof optionLabel === 'object') return optionLabel[lang] || optionLabel.en || optionLabel.tr || optionLabel.cs;
  return svcName(found.service, t, lang);
}

function diyCartItem(key, t, lang) {
  const found = diyCatalogOffer(key);
  const product = ((window.YEYE && window.YEYE.marketplaceProducts) || []).find((item) => (
    item.key === key || (item.serviceKeys || []).includes(key)
  ));
  const variant = product && (product.variants || []).find((item) => item.serviceKey === key);
  if (!found) return null;
  const name = diyOfferName(found, t, lang);
  const priceMatch = String(found.offer.price || found.offer.priceLabel || '').match(/€\s*([0-9]+(?:[.,][0-9]+)?)/);
  return {
	    productKey: product ? product.key : key,
	    priceId: (variant && variant.priceId) || (product && product.priceId) || found.offer.priceId || null,
	    productId: (variant && variant.productId) || (product && product.productId) || found.offer.productId || null,
	    serviceKey: key,
	    name,
    variantKey: (variant && variant.key) || 'diy',
    variantLabel: (variant && t(variant.labelTk)) || t('svc.variant.diy'),
    uiPrice: variant ? variant.uiPrice : Number((priceMatch && priceMatch[1] || '0').replace(',', '.')),
    uiCurrency: (variant && variant.uiCurrency) || 'EUR',
    qty: 1,
  };
}

function diySuggestionIcon(key) {
  if (/^(blue|emp)/.test(key)) return 'briefcase';
  if (/^(trade|pausalni|sro|eu_vat|eori)/.test(key)) return 'building-2';
  if (/^vehicle/.test(key)) return 'car';
  if (/^(eu_temp|eu_perm)/.test(key)) return 'home';
  if (/^translation/.test(key)) return 'languages';
  if (/^accommodation/.test(key)) return 'home';
  return 'id-card';
}

function DocGenerationSuggestions({ contact, purchasedServices }) {
  const { t, lang, currency } = useT();
  const livePaid = window.YEYE_PURCHASES && window.YEYE_PURCHASES.getPaidServices
    ? window.YEYE_PURCHASES.getPaidServices(contact || {})
    : [];
  const paid = livePaid.concat(purchasedServices || []);
  const ownedRaw = new Set((paid || []).map((item) => String(item && (item.k || item.key || item.serviceKey || item.productKey) || '').toLowerCase()).filter(Boolean));
  const normalize = typeof window.YEYE_NORMALIZE_SERVICE_KEY === 'function' ? window.YEYE_NORMALIZE_SERVICE_KEY : (key) => key;
  const ownedBases = new Set(Array.from(ownedRaw).map(normalize));
  const baseVariants = { blue_card_ext_diy: 'blue_card' };
  const suggestions = DOCGEN_DIY_KEYS.filter((key) => (
    !ownedRaw.has(key) && !ownedBases.has(normalize(key)) && !ownedBases.has(baseVariants[key])
  )).map((key) => ({ key, found: diyCatalogOffer(key), cartItem: diyCartItem(key, t, lang) }))
    .filter((item) => item.found && item.cartItem)
    .slice(0, 4);
  if (!suggestions.length) return null;
  return (
    <div className="docgen-suggestions">
      <div className="docgen-suggestions-title"><span className="eyebrow">{t('docgen.suggestions')}</span></div>
      <div className="docgen-suggestions-grid">
        {suggestions.map(({ key, found, cartItem }) => {
          const price = window.YEYE_CART_MONEY
            ? window.YEYE_CART_MONEY(window.YEYE_CART_CONVERT ? window.YEYE_CART_CONVERT(cartItem.uiPrice, cartItem.uiCurrency, currency) : cartItem.uiPrice, currency)
            : `${cartItem.uiPrice} ${cartItem.uiCurrency}`;
          const cadence = String(found.offer.u || found.service.u || '');
          const cadenceLabel = /month|monthly|aylık|měs/i.test(cadence) ? t('docgen.monthly') : t('docgen.oneTime');
          return (
            <div key={key} className="docgen-suggestion-card">
              <span className="docgen-suggestion-icon"><Icon name={diySuggestionIcon(key)} size={16} /></span>
              <div className="docgen-suggestion-name">{diyOfferName(found, t, lang)}</div>
              <div className="docgen-suggestion-footer">
                <span className="docgen-suggestion-price tnum">{price}<small>{cadenceLabel}</small></span>
                <button className="docgen-suggestion-add" onClick={() => {
                  window.YEYE_CART.addItem(cartItem);
                  if (window.YEYE_TOAST) window.YEYE_TOAST(t('cart.added'));
                  if (window.YEYE_CART_OPEN) window.YEYE_CART_OPEN();
                }}><Icon name="plus" size={13} />{t('c.add')}</button>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

function DocGenerationModal({ option, contact, purchasedServices, onGenerated, onCompleteProfile, onClose, onResult }) {
  const { t } = useT();
  const [phase, setPhase] = React.useState('running');
  const [messageIndex, setMessageIndex] = React.useState(0);
  const [messageVisible, setMessageVisible] = React.useState(true);
  const [longRunning, setLongRunning] = React.useState(false);
  const [result, setResult] = React.useState(null);
  const [error, setError] = React.useState('');
  const attemptRef = React.useRef(0);
  const timersRef = React.useRef([]);

  const generate = React.useCallback(async () => {
    const attempt = attemptRef.current + 1;
    attemptRef.current = attempt;
    timersRef.current.forEach(clearTimeout);
    timersRef.current = [];
    setPhase('running'); setMessageIndex(0); setMessageVisible(true); setLongRunning(false); setError(''); setResult(null);
    [1, 2].forEach((index) => {
      const changeAt = index * 5000;
      timersRef.current.push(setTimeout(() => { if (attemptRef.current === attempt) setMessageVisible(false); }, changeAt - 250));
      timersRef.current.push(setTimeout(() => {
        if (attemptRef.current === attempt) { setMessageIndex(index); setMessageVisible(true); }
      }, changeAt));
    });
    timersRef.current.push(setTimeout(() => { if (attemptRef.current === attempt) setLongRunning(true); }, 15000));
    try {
      const cfg = window.YEYE_CONFIG || {};
      const base = String(cfg.FILL_API_URL || '').replace(/\/$/, '');
      if (!base) throw new Error('backend-not-configured');
      const contactId = contact && (contact.contactId || contact.id);
      if (!contactId) throw new Error('missing-contact');
      const url = new URL(base + '/public/fill');
      url.searchParams.set('form_type', option.formType);
      url.searchParams.set('create_pdf', 'true');
      url.searchParams.set('sync_sheet', 'false');
      url.searchParams.set('target', 'clientview');
      const contactName = [contact.firstName, contact.lastName].filter(Boolean).join(' ') || contact.name || contact.email || '';
      const res = await fetch(url.toString(), {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', ...(cfg.FILL_API_KEY ? { 'X-API-Key': cfg.FILL_API_KEY } : {}) },
        body: JSON.stringify({ contactId, contactName, formType: option.formType, contactFields: {}, target: 'clientview' }),
      });
      if (!res.ok) {
        const text = await res.text().catch(() => '');
        throw new Error('http-' + res.status + (text ? ': ' + text.slice(0, 120) : ''));
      }
      const data = await res.json().catch(() => ({}));
      const documentUrl = data.documentUrl || (data.files && data.files[0] && (data.files[0].url || data.files[0].webViewLink)) || '';
      const documentId = driveFileId(documentUrl) || data.documentId || data.primaryFileId || '';
      const placeholdersReplaced = data.placeholdersReplaced ?? (data.documents && data.documents[0] && data.documents[0].placeholdersReplaced);
      const payload = {
        ...data,
        documentUrl,
        downloadUrl: documentId ? `${base}/public/download/${encodeURIComponent(documentId)}` : documentUrl,
        folderUrl: data.folderUrl || data.folder?.url || '',
        emptyProfile: placeholdersReplaced === 0,
      };
      if (onGenerated) await Promise.resolve(onGenerated(payload));
      if (attemptRef.current !== attempt) return;
      setResult(payload); setPhase('success');
      if (onResult) onResult(payload);
      if (window.YEYE_TOAST) window.YEYE_TOAST(t('docgen.success'));
    } catch (err) {
      if (attemptRef.current !== attempt) return;
      console.warn('DocGen failed', err);
      setError(t('docgen.failed')); setPhase('error');
    }
  }, [contact, option, onGenerated, onResult, t]);

  React.useEffect(() => {
    generate();
    return () => { attemptRef.current += 1; timersRef.current.forEach(clearTimeout); };
  }, []);

  return (
    <Modal wide icon="file-plus-2" title={t('docgen.' + option.formType)} onClose={onClose}>
      {phase === 'running' && (
        <div className={'docgen-loading' + (longRunning ? ' is-long' : '')} role="status" aria-live="polite">
          <span className="docgen-spinner docgen-loading-spinner" />
          <div className="docgen-rotating-message" style={{ opacity: messageVisible ? 1 : 0 }}>
            {t('docgen.rotating.' + (messageIndex + 1))}
          </div>
        </div>
      )}
      {phase === 'success' && result && (
        <div style={{ textAlign: 'center' }}>
          <div style={{ width: 58, height: 58, borderRadius: 99, margin: '0 auto 12px', background: 'var(--ok-bg)', color: 'var(--ok)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon name="check" size={28} stroke={3} /></div>
          <div className="h2">{t('docgen.ready')}</div>
          <div className="flex col gap-8 mt-16">
            <a className="btn btn-primary btn-lg" href={result.downloadUrl} download target="_blank" rel="noopener noreferrer"><Icon name="download" size={16} />{t('docgen.openGenerated')}</a>
          </div>
          {result.emptyProfile && (
            <div style={{ marginTop: 14, padding: 12, borderRadius: 10, background: 'var(--warn-bg)', color: 'var(--warn)', fontSize: 12.5, textAlign: 'left' }}>
              {t('docgen.emptyWarning')}{' '}
              <a href="#" onClick={(e) => { e.preventDefault(); if (onCompleteProfile) onCompleteProfile(); }} style={{ color: 'var(--warn)', fontWeight: 700, textDecoration: 'underline' }}>{t('docgen.completeProfile')}</a>
            </div>
          )}
          <DocGenerationSuggestions contact={contact} purchasedServices={purchasedServices} />
        </div>
      )}
      {phase === 'error' && (
        <div style={{ textAlign: 'center', padding: '12px 0' }}>
          <div style={{ width: 58, height: 58, borderRadius: 99, margin: '0 auto 12px', background: 'var(--bad-bg)', color: 'var(--bad)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}><Icon name="x" size={28} stroke={3} /></div>
          <div className="h3">{error}</div>
          <Btn className="mt-16" variant="primary" icon="refresh-cw" onClick={generate}>{t('docgen.retry')}</Btn>
        </div>
      )}
    </Modal>
  );
}

function DocGenerationCard({ contact, purchasedServices, onGenerated, onCompleteProfile }) {
  const { t } = useT();
  const [results, setResults] = React.useState({});
  const [activeOption, setActiveOption] = React.useState(null);
  const purchasedKeys = new Set((purchasedServices || []).map((p) => String((p && (p.k || p.key || p.serviceKey || p.productKey)) || '').toLowerCase()).filter(Boolean));
  const options = [
    { key: 'blue_card_diy', formType: 'blue_card' },
    { key: 'emp_card_diy', formType: 'emp_card' },
  ].filter((opt) => purchasedKeys.has(opt.key));
  if (!options.length) return null;
  return (
    <>
      <Card className="mb-16">
        <CardHead icon="file-plus-2" title={t('docgen.title')} sub={t('docgen.sub')} />
        <div className="card-bd">
          <div style={{ display: 'grid', gap: 10 }}>
            {options.map((opt) => (
              <div key={opt.key} className="flex ac wrap gap-10" style={{ padding: 12, border: '1px solid var(--line)', borderRadius: 12, background: 'var(--surface)' }}>
                <span style={{ width: 40, height: 40, borderRadius: 10, background: 'var(--brand-50)', color: 'var(--brand-600)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}><Icon name="file-text" size={18} /></span>
                <div className="grow strong" style={{ minWidth: 0, fontSize: 14 }}>{t('docgen.' + opt.formType)}</div>
                <Btn variant="primary" icon={results[opt.key] ? 'refresh-cw' : 'wand-2'} onClick={() => setActiveOption(opt)}>
                  {results[opt.key] ? t('docgen.regenerate') : t('docgen.generate')}
                </Btn>
              </div>
            ))}
          </div>
        </div>
      </Card>
      {activeOption && <DocGenerationModal option={activeOption} contact={contact} purchasedServices={purchasedServices} onGenerated={onGenerated} onCompleteProfile={onCompleteProfile} onClose={() => setActiveOption(null)} onResult={(payload) => setResults((prev) => ({ ...prev, [activeOption.key]: payload }))} />}
    </>
  );
}

function DocumentsPage({ openModal, blankProfile, contact, onRefresh, purchasedServices, onCompleteProfile, fieldMappings }) {
  const { t, lang } = useT();
  const folders = P.folders || [];
  const [filter, setFilter] = useState('all');
  const [openFolderTk, setOpenFolderTk] = useState(null);
  const [archiveSubfolders, setArchiveSubfolders] = useState({});
  const [archiveFilesBySub, setArchiveFilesBySub] = useState({});
  const [newFolderOpen, setNewFolderOpen] = useState(false);
  const [openChecklistKey, setOpenChecklistKey] = useState(null);
  const [detailFile, setDetailFile] = useState(null);
  const [profileFormKey, setProfileFormKey] = useState('');
  const hasRealContact = !!contact && !blankProfile;
  const contactId = contact && contact.id;
  const tracker = window.PROCESS_TRACKER || {};
  const paidServicesFromContact = window.YEYE_PURCHASES && window.YEYE_PURCHASES.getPaidServices
    ? window.YEYE_PURCHASES.getPaidServices(contact || {})
    : [];
  const formType = tracker.detectFormType ? tracker.detectFormType(contact) : null;
  const docStatus = contact && formType && tracker.documentStatusFromContact
    ? tracker.documentStatusFromContact(contact, formType)
    : { items: tracker.DOCUMENT_CHECKLIST || [], total: (tracker.DOCUMENT_CHECKLIST || []).length, doneCount: 0 };
  const serviceFormMap = { blue_card: 'blue_card', emp_card: 'employee_card' };
  const normalizeServiceKey = typeof window.YEYE_NORMALIZE_SERVICE_KEY === 'function' ? window.YEYE_NORMALIZE_SERVICE_KEY : (key) => key;
  const purchasedChecklists = useMemo(() => {
    const rows = (purchasedServices || []).filter((row) => row && row.status !== 'cancelled');
    const seen = new Set();
    const out = [];
    rows.forEach((row) => {
      const serviceKey = normalizeServiceKey(row.k);
      const ftype = serviceFormMap[serviceKey];
      if (!ftype || seen.has(ftype)) return;
      seen.add(ftype);
      const svc = (P.services || []).find((s) => s.k === serviceKey) || { k: serviceKey };
      const raw = contact && tracker.documentStatusFromContact
        ? tracker.documentStatusFromContact(contact, ftype)
        : { items: tracker.DOCUMENT_CHECKLIST || [], total: (tracker.DOCUMENT_CHECKLIST || []).length, doneCount: 0 };
      const items = (raw.items || []).filter((doc) => doc.key !== 'application_fee');
      const status = {
        items,
        total: items.length,
        doneCount: items.filter((d) => d.completed).length,
      };
      out.push({ key: ftype, service: svc, status });
    });
    return out;
  }, [purchasedServices, contact]);
  const chkCopy = ({
    tr: { docsBtn: 'Belgelerim', close: 'Belgeleri kapat', pending: 'Bekleniyor', view: 'Görüntüle' },
    en: { docsBtn: 'My documents', close: 'Hide documents', pending: 'Pending', view: 'View' },
    cs: { docsBtn: 'Moje dokumenty', close: 'Skrýt dokumenty', pending: 'Čeká', view: 'Zobrazit' },
  })[lang] || { docsBtn: 'My documents', close: 'Hide documents', pending: 'Pending', view: 'View' };
  const checklistMap = {
    hlasenka: { folderK: 'f_relocation', subK: 'sf_mvcr_corr' },
    accommodation_paper: { folderK: 'f_accommodation_re', subK: 'sf_lease' },
    employment_contract: { folderK: 'f_relocation', subK: 'sf_employment_contract' },
    salary_document: { folderK: 'f_relocation', subK: 'sf_payslip' },
    power_of_attorney: { folderK: 'f_relocation', subK: 'sf_mvcr_corr' },
    application_form: { folderK: 'f_relocation', subK: 'sf_blue_employee' },
    criminal_record_apostilled: { folderK: 'f_identity', subK: 'sf_criminal_record' },
    diploma_apostilled: { folderK: 'f_education', subK: 'sf_diploma' },
    certificates: { folderK: 'f_education', subK: 'sf_diploma' },
    passport_visa_copy: { folderK: 'f_identity', subK: 'sf_passport' },
    biometric_photo: { folderK: 'f_identity', subK: 'sf_passport' },
    application_fee: { folderK: 'f_relocation', subK: 'sf_blue_employee' },
  };
  const displayFolders = useMemo(() => {
    const standardNames = new Set(folders.map((folder) => folderTkToSubName(folder.tk)));
    const extras = Object.keys(archiveSubfolders)
      .filter((name) => !standardNames.has(name) && !subNameToFolderTk(name))
      .sort((a, b) => a.localeCompare(b))
      .map((name) => ({
        tk: 'archive_' + name.toLowerCase().replace(/[^a-z0-9]+/g, '_'),
        label: name,
        archiveName: name,
        ic: 'folder',
        subs: [],
      }));
    return folders.concat(extras);
  }, [folders, archiveSubfolders]);
  async function refreshArchiveSubfolders() {
    if (!hasRealContact || !contactId || !window.YEYE_BACKEND) return;
    try {
      await window.YEYE_BACKEND.ensureArchiveSubfolders(contactId);
      const res = await window.YEYE_BACKEND.listArchiveSubfolders(contactId);
      const byName = {};
      ((res && res.subfolders) || []).forEach((sub) => { byName[sub.name] = sub; });
      setArchiveSubfolders(byName);
    } catch (e) {
      console.warn('Archive subfolder sync failed.', e);
    }
  }
  async function loadArchiveFiles(folderTk, { force = false } = {}) {
    if (!hasRealContact || !contactId || !window.YEYE_BACKEND) return;
    const folder = displayFolders.find((item) => item.tk === folderTk);
    const primarySubName = folderTkToSubName(folderTk, folder);
    if (!primarySubName) return;
    const subNames = [primarySubName].concat(
      Object.keys(archiveSubfolders).filter((name) => subNameToFolderTk(name) === folderTk && name !== primarySubName)
    );
    await Promise.all(subNames.map(async (subName) => {
      if (!force && archiveFilesBySub[subName]) return;
      try {
        const res = await window.YEYE_BACKEND.listArchiveFiles(contactId, subName);
        setArchiveFilesBySub((prev) => ({ ...prev, [subName]: (res && res.files) || [] }));
      } catch (e) {
        console.warn('Archive file list failed.', e);
        setArchiveFilesBySub((prev) => ({ ...prev, [subName]: [] }));
      }
    }));
  }
  const allItems = useMemo(() => {
    const checklistItems = (docStatus.items || [])
      .filter((doc) => doc.key !== 'application_fee')
      .map((doc) => {
        const mapped = checklistMap[doc.key] || {};
        return {
          source: 'checklist',
          tk: doc.key,
          label: doc.label,
          ok: !!(doc.completed || doc.url),
          url: doc.url,
          webViewLink: doc.url,
          meta: doc.url ? t('doc.uploaded') : '',
          origin: doc.url ? 'yeye' : undefined,
          folderK: mapped.folderK,
          subK: mapped.subK,
        };
      })
      .filter((doc) => doc.folderK && doc.subK);
    const driveItems = Object.keys(archiveFilesBySub).flatMap((subName) => {
      const customFolder = displayFolders.find((folder) => folder.archiveName === subName);
      const folderK = subNameToFolderTk(subName) || (customFolder && customFolder.tk);
      if (!folderK) return [];
      return (archiveFilesBySub[subName] || []).map((file) => ({
        source: 'drive',
        id: file.id,
        label: file.name,
        ok: true,
        url: file.webViewLink,
        webViewLink: file.webViewLink,
        meta: driveFileMeta(file),
        folderK,
        subK: '__archive',
        ic: String(file.mimeType || '').indexOf('image/') === 0 ? 'image' : 'file-text',
      }));
    });
    return checklistItems.concat(driveItems)
      .sort((a, b) => (
        (a.folderK || '').localeCompare(b.folderK || '') ||
        (a.subK || '').localeCompare(b.subK || '')
      ));
  }, [docStatus.items, archiveFilesBySub, displayFolders, t]);
  const profilePrompts = useMemo(() => paidApplicationFormKeys(paidServicesFromContact, contact).map((key) => {
    const rows = window.YEYE_FIELD_MAPPING ? window.YEYE_FIELD_MAPPING.forForm(fieldMappings || [], key, contact || {}) : [];
    return { key, rows, missing: rows.filter((row) => !row.value).length };
  }).filter((item) => item.rows.length && item.missing > 0), [contact, fieldMappings]);
  React.useEffect(() => {
    if (!onRefresh) return undefined;
    const doRefresh = () => Promise.resolve(onRefresh()).catch(() => {});
    doRefresh();
    const interval = setInterval(doRefresh, 60000);
    const onVisible = () => { if (!document.hidden) doRefresh(); };
    document.addEventListener('visibilitychange', onVisible);
    window.addEventListener('focus', doRefresh);
    return () => {
      clearInterval(interval);
      document.removeEventListener('visibilitychange', onVisible);
      window.removeEventListener('focus', doRefresh);
    };
  }, [onRefresh]);
  React.useEffect(() => {
    if (!hasRealContact || !contactId) return undefined;
    refreshArchiveSubfolders();
    return undefined;
  }, [hasRealContact, contactId]);
  React.useEffect(() => {
    if (openFolderTk) loadArchiveFiles(openFolderTk);
  }, [openFolderTk, contactId, archiveSubfolders]);
  const openUpload = (folderK) => {
    const folder = displayFolders.find((item) => item.tk === folderK);
    const subName = folder ? folderTkToSubName(folderK, folder) : '';
    openModal('upload', {
      contactId,
      folderK,
      subName,
      onUploaded: async () => {
        await Promise.resolve(refreshArchiveSubfolders());
        if (folderK) await Promise.resolve(loadArchiveFiles(folderK, { force: true }));
        if (onRefresh) await Promise.resolve(onRefresh());
        if (window.YEYE_TOAST) window.YEYE_TOAST(t('doc.uploaded'));
      },
    });
  };
  return (
    <>
      <PageHead title={t('nav.documents')} sub={t('sub.documents')}
        actions={<><Btn variant="ghost" icon="folder-plus" onClick={() => setNewFolderOpen(true)}>{t('c.newFolder')}</Btn><Btn variant="primary" icon="upload" onClick={() => openUpload(openFolderTk)}>{t('c.upload')}</Btn></>} />
      {profilePrompts.map((prompt) => (
        <Card className="mb-16" key={prompt.key} style={{ borderColor: 'var(--brand-200)', background: 'var(--brand-50)' }}>
          <div className="card-bd flex ac jb wrap gap-12">
            <div>
              <div className="strong" style={{ fontSize: 14 }}>{t('profile.context.title').replace('{service}', applicationFormLabel(prompt.key, lang)).replace('{count}', prompt.missing)}</div>
              <div className="muted" style={{ fontSize: 12.5, marginTop: 4 }}>{t('profile.context.body')}</div>
            </div>
            <Btn variant="primary" icon="clipboard-list" onClick={() => setProfileFormKey(prompt.key)}>{t('profile.context.cta')}</Btn>
          </div>
        </Card>
      ))}
      <DocGenerationCard contact={contact} purchasedServices={purchasedServices} onCompleteProfile={onCompleteProfile} onGenerated={async () => {
        setArchiveFilesBySub({});
        await Promise.resolve(refreshArchiveSubfolders());
        if (onRefresh) await Promise.resolve(onRefresh());
      }} />
      {allItems.length === 0 && <div className="muted mb-12" style={{ fontSize: 13 }}>{t('doc.noDocs')}</div>}
      <div className="grid g-12" style={{ gap: 14, gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))' }}>
        {displayFolders.map((folder) => (
          <FolderArchiveCard
            folder={folder}
            allItems={allItems}
            archiveSubfolders={archiveSubfolders}
            openFolderTk={openFolderTk}
            onToggle={setOpenFolderTk}
            key={folder.tk}
          />
        ))}
      </div>
      {openFolderTk && (
        <Modal wide icon="folder-open" title={(displayFolders.find((f) => f.tk === openFolderTk) || {}).label || t(openFolderTk)} onClose={() => setOpenFolderTk(null)}>
          <FolderExpandedBody folder={displayFolders.find((f) => f.tk === openFolderTk)} allItems={allItems} filter={filter} openModal={(kind, data) => openUpload(data && data.folderK)} openUpload={openUpload} onOpenDocument={(file) => { setOpenFolderTk(null); setDetailFile(file); }} />
        </Modal>
      )}
      {openChecklistKey && (() => {
        const checklist = purchasedChecklists.find((item) => item.key === openChecklistKey);
        if (!checklist) return null;
        return (
          <Modal wide icon="list-checks" title={svcName(checklist.service, t, lang)} sub={`${checklist.status.doneCount || 0}/${checklist.status.total || 0} ${t('sec.complete')}`} onClose={() => setOpenChecklistKey(null)}>
            <div className="rowlist">
              {(checklist.status.items || []).map((doc) => (
                <div className={'lrow ' + (doc.url ? 'pointer' : '')} key={doc.key} onClick={() => {
                  if (!doc.url) return;
                  setOpenChecklistKey(null);
                  setDetailFile({ label: doc.label, url: doc.url, webViewLink: doc.url, meta: t('doc.uploaded'), ic: 'file-text' });
                }}>
                  <div className="l-ic" style={doc.completed ? { background: 'var(--ok-bg)', color: 'var(--ok)' } : { background: 'var(--surface-3)', color: 'var(--ink-300)' }}>
                    <Icon name={doc.completed ? 'file-check-2' : 'file'} size={17} />
                  </div>
                  <div className="l-bd"><div className="l-t">{doc.label}</div></div>
                  {doc.url ? <Btn variant="quiet" size="sm" icon="eye">{chkCopy.view}</Btn> : doc.completed ? <Badge tone="ok" dot>{t('c.done')}</Badge> : <Badge tone="neut">{chkCopy.pending}</Badge>}
                </div>
              ))}
            </div>
          </Modal>
        );
      })()}
      {newFolderOpen && <NewFolderModal contactId={contactId} onClose={() => setNewFolderOpen(false)} onCreated={() => { setNewFolderOpen(false); refreshArchiveSubfolders(); }} />}
      {detailFile && <DocumentDetailModal file={detailFile} onClose={() => setDetailFile(null)} />}
      {profileFormKey && (
        <ApplicationFormModal
          formKey={profileFormKey}
          contact={contact}
          rows={window.YEYE_FIELD_MAPPING ? window.YEYE_FIELD_MAPPING.forForm(fieldMappings || [], profileFormKey, contact || {}) : []}
          lang={lang}
          t={t}
          onClose={() => setProfileFormKey('')}
          onSaved={() => { setProfileFormKey(''); if (onRefresh) onRefresh(); }}
          applyOptimisticUpdate={() => {}}
        />
      )}
    </>
  );
}

function NewFolderModal({ contactId, onClose, onCreated }) {
  const { t } = useT();
  const [name, setName] = useState('');
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState('');
  async function submit() {
    const clean = name.trim();
    if (!clean || !contactId || saving) return;
    setSaving(true); setError('');
    try {
      await window.YEYE_BACKEND.createArchiveSubfolder({ contactId, name: clean });
      onCreated();
    } catch (e) {
      console.warn('Create archive subfolder failed.', e);
      setError(e.message || 'create-failed');
      setSaving(false);
    }
  }
  return (
    <Modal icon="folder-plus" title={t('doc.newFolderTitle')} sub={t('doc.archiveSubfolder')} onClose={onClose}
      footer={<><Btn variant="ghost" onClick={onClose}>{t('c.cancel')}</Btn><Btn variant="primary" icon="folder-plus" onClick={submit}>{saving ? t('c.saving') : t('c.create')}</Btn></>}>
      <Field label={t('doc.folderName')}>
        <input className="input" value={name} onChange={(e) => setName(e.target.value)} autoFocus />
      </Field>
      {error && <div className="alert bad mt-12"><div className="a-ic"><Icon name="alert-triangle" size={16} /></div><div className="grow"><div className="a-t">{error}</div></div></div>}
    </Modal>
  );
}

/* ===== MESSAGES ===== */
function MessagesPage() {
  const { t } = useT();
  const threads = [
    { whoK: 'immigration', av: 'IM', c: 'brand', lastK: 'm.appt', tm: '2h', n: 2 },
    { whoK: 'support', av: 'SP', c: 'accent', lastK: 'm.doc', tm: '1d', n: 0 },
    { whoK: 'relocation', av: 'RL', c: 'neut', lastK: 'm.reloc', tm: '3d', n: 0 },
  ];
  const [active, setActive] = useState(0);
  const conv = [
    { me: false, k: 'msg.c1', t: '09:12' }, { me: true, k: 'msg.c2', t: '09:20' },
    { me: false, k: 'msg.c3', t: '09:24' }, { me: false, k: 'msg.c4', t: '2h' },
  ];
  const tone = (c) => c === 'brand' ? { bg: 'var(--brand-100)', fg: 'var(--brand-700)' } : c === 'accent' ? { bg: 'var(--accent-100)', fg: 'var(--accent-700)' } : { bg: 'var(--neut-bg)', fg: 'var(--neut)' };
  return (
    <div style={{ height: '100%' }}>
      <div className="card" style={{ display: 'flex', height: 'calc(100vh - 66px - 60px)', minHeight: 460, overflow: 'hidden' }}>
        <div style={{ width: 300, borderRight: '1px solid var(--line)', display: 'flex', flexDirection: 'column' }} className="desktop-only">
          <div style={{ padding: '16px 18px', borderBottom: '1px solid var(--line-2)' }} className="flex jb ac"><div className="h3">{t('msg.inbox')}</div><IconBtn name="square-pen" /></div>
          <div style={{ overflowY: 'auto', flex: 1 }}>
            {threads.map((th, i) => (
              <div key={i} onClick={() => setActive(i)} className="pointer" style={{ display: 'flex', gap: 11, padding: '13px 16px', borderBottom: '1px solid var(--line-2)', background: active === i ? 'var(--brand-50)' : 'transparent' }}>
                <Avatar size="md" tone={tone(th.c)}>{th.av}</Avatar>
                <div className="grow" style={{ minWidth: 0 }}><div className="flex jb"><span className="nm" style={{ fontSize: 13.5 }}>{t('who.' + th.whoK)}</span><span className="dim" style={{ fontSize: 11 }}>{th.tm}</span></div><div className="dim" style={{ fontSize: 12, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{t(th.lastK)}</div></div>
                {th.n > 0 && <span className="nav-badge">{th.n}</span>}
              </div>
            ))}
          </div>
        </div>
        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', minWidth: 0 }}>
          <div style={{ padding: '13px 20px', borderBottom: '1px solid var(--line-2)' }} className="flex ac gap-12">
            <Avatar size="md" tone={tone(threads[active].c)}>{threads[active].av}</Avatar>
            <div className="grow"><div className="strong">{t('who.' + threads[active].whoK)}</div><div className="dim flex ac gap-6" style={{ fontSize: 12 }}><i style={{ background: 'var(--ok)', width: 7, height: 7, borderRadius: 99, display: 'inline-block' }} />{t('m.reply')}</div></div>
            <IconBtn name="phone" /><IconBtn name="info" />
          </div>
          <div style={{ flex: 1, overflowY: 'auto', padding: '20px 22px', display: 'flex', flexDirection: 'column', gap: 12, background: 'var(--surface-2)' }}>
            {conv.map((m, i) => (
              <div key={i} style={{ alignSelf: m.me ? 'flex-end' : 'flex-start', maxWidth: '74%' }}>
                <div style={{ padding: '10px 14px', borderRadius: 14, fontSize: 13.5, lineHeight: 1.5, background: m.me ? 'var(--brand-500)' : '#fff', color: m.me ? '#fff' : 'var(--ink-800)', border: m.me ? 'none' : '1px solid var(--line)', borderBottomRightRadius: m.me ? 4 : 14, borderBottomLeftRadius: m.me ? 14 : 4 }}>{t(m.k)}</div>
                <div className="dim" style={{ fontSize: 10.5, marginTop: 4, textAlign: m.me ? 'right' : 'left' }}>{m.t}</div>
              </div>
            ))}
          </div>
          <div style={{ padding: '13px 16px', borderTop: '1px solid var(--line-2)' }} className="flex ac gap-10">
            <IconBtn name="paperclip" />
            <input className="input" placeholder={t('m.write')} style={{ flex: 1 }} />
            <Btn variant="primary" icon="send">{t('c.send')}</Btn>
          </div>
        </div>
      </div>
    </div>
  );
}

/* ===== INVOICES ===== */
function invoiceAmountValue(amount) {
  const eur = String(amount || '').match(/€\s*([0-9]+(?:[.,][0-9]+)?)/);
  const n = Number((eur ? eur[1] : String(amount || '')).replace(',', '.').replace(/[^0-9.-]/g, ''));
  return Number.isFinite(n) ? n : 0;
}
function paidTotalLabel(total, currency) {
  return moneyLabel(total * (CURRENCY_RATES[currency] || 1), currency);
}
function invoiceDisplayAmount(inv, currency) {
  const eur = Number.isFinite(inv.eurAmount) ? inv.eurAmount : invoiceAmountValue(inv.amt);
  return moneyLabel(eur * (CURRENCY_RATES[currency] || 1), currency);
}
function downloadInvoice(inv, t) {
  const service = inv.serviceName || t('iv.' + inv.svcK);
  const paidAt = inv.paidAt || inv.due || '';
  const html = `<!doctype html>
<html><head><meta charset="utf-8"><title>${inv.id}</title>
<style>body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;margin:40px;color:#17202a}h1{margin:0 0 8px}.muted{color:#667085}.box{border:1px solid #d9dee7;border-radius:10px;padding:18px;margin-top:24px}table{width:100%;border-collapse:collapse;margin-top:18px}th,td{text-align:left;border-bottom:1px solid #e8ebf0;padding:12px}th{font-size:12px;text-transform:uppercase;color:#667085}.total{font-size:22px;font-weight:700;text-align:right}.paid{display:inline-block;background:#e8f7ef;color:#147a3f;border-radius:999px;padding:6px 10px;font-weight:700}</style>
</head><body>
<h1>Invoice ${inv.id}</h1>
<div class="muted">YeYe Expats Centre</div>
<div class="box"><span class="paid">${t('iv.invoicePaid')}</span><p>${t('iv.autoInvoice')}</p><p><strong>${t('col.paidOn')}:</strong> ${paidAt}</p></div>
<table><thead><tr><th>${t('nav.services')}</th><th>${t('col.amount')}</th></tr></thead><tbody><tr><td>${service}</td><td>${inv.amt}</td></tr></tbody></table>
<p class="total">${inv.amt}</p>
</body></html>`;
  const blob = new Blob([html], { type: 'text/html;charset=utf-8' });
  const a = document.createElement('a');
  a.href = URL.createObjectURL(blob);
  a.download = inv.id + '.html';
  document.body.appendChild(a);
  a.click();
  setTimeout(() => { URL.revokeObjectURL(a.href); a.remove(); }, 0);
}
function InvoicesPage({ contact, go, openModal, onCheckout }) {
  const { t, currency } = useT();
  const invoiceUtils = window.YEYE_INVOICES;
  const cart = useCartState();
  const [invoices, setInvoices] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState('');
  const [refreshing, setRefreshing] = useState(false);
  const [sendingId, setSendingId] = useState('');
  const [cancellingId, setCancellingId] = useState('');
  const contactId = contact && contact.contactId;
  const loadInvoices = async (silent) => {
    if (!contactId) {
      setInvoices([]);
      setLoading(false);
      return;
    }
    if (silent) setRefreshing(true);
    else setLoading(true);
    try {
      const result = await window.YEYE_BACKEND.listInvoices(contactId);
      setInvoices(invoiceUtils.normalizeList(result));
      setError('');
    } catch (err) {
      setError((err && err.message) || t('checkout.error'));
    } finally {
      setLoading(false);
      setRefreshing(false);
    }
  };
  useEffect(() => { loadInvoices(false); }, [contactId]);
  useEffect(() => {
    const poll = () => { if (document.visibilityState === 'visible') loadInvoices(true); };
    const timer = window.setInterval(poll, 30000);
    const onVisibility = () => { if (document.visibilityState === 'visible') loadInvoices(true); };
    document.addEventListener('visibilitychange', onVisibility);
    return () => {
      window.clearInterval(timer);
      document.removeEventListener('visibilitychange', onVisibility);
    };
  }, [contactId]);
  const [cancelledIds, setCancelledIds] = useState(() => {
    return invoiceUtils.cancelledIds();
  });
  const cancelInvoice = async (invoice) => {
    const id = String(invoiceUtils.idFor(invoice) || '');
    if (!id || cancellingId) return;
    if (!window.confirm(t('invoices.cancelConfirm'))) return;
    setCancellingId(id);
    try {
      await window.YEYE_BACKEND.voidInvoice(id);
      setCancelledIds((prev) => {
        const next = new Set(prev);
        next.add(id);
        try { localStorage.setItem(invoiceUtils.CANCELLED_KEY, JSON.stringify([...next])); } catch (_) {}
        return next;
      });
      setInvoices((rows) => rows.map((row) => (
        String(invoiceUtils.idFor(row) || '') === id
          ? Object.assign({}, row, { status: 'void' })
          : row
      )));
      if (window.YEYE_TOAST) window.YEYE_TOAST(t('invoices.cancelled'));
    } catch (_) {
      if (window.YEYE_TOAST) window.YEYE_TOAST(t('invoices.cancelError'));
    } finally {
      setCancellingId('');
    }
  };
  const visibleInvoices = useMemo(
    () => invoiceUtils.visibleInvoices(invoices, contact, cancelledIds),
    [invoices, contact, cancelledIds]
  );
  const resend = async (invoice) => {
    const id = invoiceUtils.idFor(invoice);
    if (!id || sendingId) return;
    setSendingId(id);
    try {
      const result = await window.YEYE_BACKEND.sendInvoice(id);
      if (result && result.invoiceUrl) {
        invoiceUtils.rememberUrl(id, result.invoiceUrl);
        setInvoices((rows) => rows.map((row) => (
          String(invoiceUtils.idFor(row) || '') === String(id)
            ? Object.assign({}, row, { invoiceUrl: result.invoiceUrl })
            : row
        )));
      }
      if (window.YEYE_TOAST) window.YEYE_TOAST(t('invoices.resent'));
      await loadInvoices(true);
    } catch (_) {
      if (window.YEYE_TOAST) window.YEYE_TOAST(t('invoices.resendError'));
    } finally {
      setSendingId('');
    }
  };
  const paidInvoices = visibleInvoices.filter((invoice) => invoiceUtils.statusFor(invoice) === 'paid');
  const readyInvoices = visibleInvoices.filter((invoice) => invoiceUtils.statusFor(invoice) !== 'draft');
  const paidTotal = paidInvoices.reduce((sum, invoice) => sum + invoiceUtils.amountInCurrency(invoice, currency), 0);
  const cartTotals = window.YEYE_CART_TOTALS(cart.items, currency);
  const downloadAll = () => {
    visibleInvoices.filter((invoice) => invoice.pdfUrl || invoice.downloadUrl).forEach((invoice, index) => {
      window.setTimeout(() => {
        const anchor = document.createElement('a');
        anchor.href = invoice.pdfUrl || invoice.downloadUrl;
        anchor.download = '';
        anchor.target = '_blank';
        anchor.rel = 'noopener noreferrer';
        document.body.appendChild(anchor);
        anchor.click();
        anchor.remove();
      }, index * 120);
    });
  };
  return (
    <>
      <PageHead title={t('invoices.title')} sub={t('sub.invoices')}
        actions={<>
          <Btn variant="ghost" icon="life-buoy" onClick={() => openModal && openModal('ticket', { catK: 'billing', subject: t('ticket.itInvoiceSubject') })}>{t('c.openItTicket')}</Btn>
          <Btn variant="ghost" icon="download" onClick={downloadAll} disabled={!visibleInvoices.some((invoice) => invoice.pdfUrl || invoice.downloadUrl)}>{t('c.downloadInvoices')}</Btn>
        </>} />
      {error && <Alert tone="bad" title={t('checkout.error')}>{error}</Alert>}
      {cart.items.length > 0 && (
        <Card className="card-pad mb-20" style={{ border: '1px solid var(--brand-200)', background: 'var(--brand-50)' }}>
          <div className="flex jb ac gap-12 wrap mb-12">
            <div className="flex ac gap-10">
              <div className="hd-ic" style={{ background: 'var(--brand-100)', color: 'var(--brand-700)' }}><Icon name="shopping-cart" size={18} /></div>
              <div className="h3">{t('cart.pending')}</div>
              <Badge tone="info">{t('cart.pendingItems').replace('{n}', cart.items.length)}</Badge>
            </div>
          </div>
          <div className="flex col gap-8">
            {cart.items.map((item) => (
              <div className="flex jb ac gap-12 wrap" key={item.id} style={{ padding: '8px 0', borderBottom: '1px solid var(--brand-100)' }}>
                <div><span className="strong">{item.name}</span>{item.variantLabel && <span className="muted"> · {item.variantLabel}</span>}</div>
                <div className="strong tnum">{window.YEYE_CART_MONEY(window.YEYE_CART_CONVERT ? window.YEYE_CART_CONVERT(item.uiPrice, item.uiCurrency, currency) : (Number(item.uiPrice) || 0), currency)} × {item.qty}</div>
              </div>
            ))}
          </div>
          <div className="flex jb ac gap-12 wrap mt-16">
            <div>
              <div className="eyebrow">{t('cart.subtotal')}</div>
              <div className="flex gap-12 wrap">{Object.keys(cartTotals).map((code) => <strong className="tnum" key={code}>{window.YEYE_CART_MONEY(cartTotals[code], code)}</strong>)}</div>
            </div>
            <div className="flex gap-8 wrap">
              <Btn variant="ghost" onClick={() => go('services')}>{t('cart.continueShopping')}</Btn>
              <Btn variant="primary" iconR="arrow-right" onClick={onCheckout}>{t('cart.payNow')}</Btn>
            </div>
          </div>
        </Card>
      )}
      <div className="grid g-12 mb-20" style={{ gap: 16 }}>
        <div className="col-4"><Stat icon="check-check" value={moneyLabel(paidTotal, currency)} label={t('iv.totalPaid')} /></div>
        <div className="col-4"><Stat icon="package-check" tone="blue" value={String(paidInvoices.length)} label={t('iv.paidServices')} /></div>
        <div className="col-4"><Stat icon="receipt-text" tone="amber" value={String(readyInvoices.length)} label={t('iv.invoiceReady')} /></div>
      </div>
      <div className="tbl-wrap mt-16">
        <table className="tbl">
          <thead><tr><th>{t('col.invoice')}</th><th>{t('nav.services')}</th><th>{t('col.amount')}</th><th>{t('col.paidOn')}</th><th>{t('col.status')}</th><th></th></tr></thead>
          <tbody>
            {loading ? (
              <tr><td colSpan="6"><div className="muted" style={{ padding: 18, textAlign: 'center' }}>{t('invoices.loading')}</div></td></tr>
            ) : visibleInvoices.length === 0 ? (
              <tr><td colSpan="6"><div className="muted" style={{ padding: 18, textAlign: 'center' }}>—</div></td></tr>
            ) : visibleInvoices.map((invoice) => {
              const id = invoiceUtils.idFor(invoice);
              const status = invoiceUtils.statusFor(invoice);
              const number = invoice.invoiceNumber || invoice.number || (id ? String(id).slice(-8) : '—');
              const invoiceUrl = invoice.invoiceUrl || invoice.url || invoice.paymentUrl;
              const invoicePdfUrl = invoice.pdfUrl || invoice.downloadUrl || (status === 'paid' && id && window.YEYE_BACKEND ? window.YEYE_BACKEND.getInvoicePdfUrl(id) : '');
              const lineItems = invoiceUtils.itemsOf(invoice);
              const currencyCode = invoice.currency || 'CZK';
              const fmtLine = (n) => Number(n || 0).toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: 2 }) + ' ' + currencyCode;
              return (
                <tr key={id || number}>
                  <td className="mono nm" style={{ fontSize: 12.5 }}>#{number}</td>
                  <td className="muted">
                    {lineItems.length > 0 ? (
                      <div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
                        {lineItems.map((it, idx) => (
                          <div key={idx} style={{ fontSize: 12.5, display: 'flex', justifyContent: 'space-between', gap: 12 }}>
                            <span>{it.name || it.description || '—'}{(it.qty || it.quantity) > 1 ? ' × ' + (it.qty || it.quantity) : ''}</span>
                            <span className="tnum">{fmtLine(invoiceUtils.itemNumericAmount(it))}</span>
                          </div>
                        ))}
                      </div>
                    ) : (
                      invoiceUtils.nameFor(invoice, t('invoices.title'))
                    )}
                  </td>
                  <td className="nm tnum">{invoiceUtils.amountFor(invoice)}</td>
                  <td className="muted mono" style={{ fontSize: 12.5 }}>{invoiceUtils.dateFor(invoice)}</td>
                  <td><Badge tone={invoiceUtils.toneFor(status)} dot>{t('invoices.status.' + status)}</Badge></td>
                  <td className="txt-r">
                    <div className="flex gap-6" style={{ justifyContent: 'flex-end', flexWrap: 'nowrap' }}>
                      {status !== 'paid' && invoiceUrl && <a className="btn btn-primary btn-sm" href={invoiceUrl} target="_blank" rel="noopener noreferrer"><Icon name="credit-card" size={14} />{t('invoices.pay')}</a>}
                      <a className="btn btn-ghost btn-sm"
                        href={status === 'paid' && invoicePdfUrl ? invoicePdfUrl : '#'}
                        target="_blank" rel="noopener noreferrer"
                        download={status === 'paid' && invoicePdfUrl ? '' : undefined}
                        onClick={(e) => { if (status !== 'paid' || !invoicePdfUrl) { e.preventDefault(); if (window.YEYE_TOAST) window.YEYE_TOAST(t('invoices.notPaidYet')); } }}
                        title={status === 'paid' ? t('invoices.downloadPaid') : t('invoices.notPaidYet')}>
                        <Icon name="download" size={14} />{t('invoices.pdf')}
                      </a>
                      {status === 'paid' && invoiceUrl && <a className="btn btn-ghost btn-sm" href={invoiceUrl} target="_blank" rel="noopener noreferrer" title={t('invoices.openInvoice')}><Icon name="external-link" size={14} /></a>}
                      {status !== 'paid' && <Btn variant="ghost" size="sm" icon="send" onClick={() => resend(invoice)} disabled={!id || sendingId === id} title={t('invoices.resendInvoice')} />}
                      {status !== 'paid' && status !== 'void' && <Btn variant="ghost" size="sm" icon="x" onClick={() => cancelInvoice(invoice)} disabled={!id || cancellingId === id} title={t('invoices.cancel')} />}
                    </div>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    </>
  );
}

/* ===== SUPPORT ===== */
function SupportPage({ openModal, tickets, tasks, go }) {
  const { t } = useT();
  const cards = [{ ic: 'messages-square', k: 'chat' }, { ic: 'phone', k: 'call' }, { ic: 'calendar-plus', k: 'book' }];
  const CATEGORY_RE = /^\[([^\]]+)\]\s*/;
  const taskTickets = (tasks || [])
    .map((task) => {
      const title = String(task.title || '');
      const match = title.match(CATEGORY_RE);
      if (!match) return null;
      const catK = match[1].toLowerCase();
      const subject = title.replace(CATEGORY_RE, '').trim() || title;
      const done = !!task.done;
      return {
        id: task.ghlTaskId || task.id,
        subject,
        catK,
        details: task.body || task.description || task.details || '',
        st: done ? 'resolved' : 'open',
        stc: done ? 'ok' : 'info',
        upd: task.due || task.dateLabel || '—',
        source: 'ghl',
      };
    })
    .filter(Boolean);
  const localOnly = (tickets || []).filter((tk) => !tk.ghlTaskId);
  const merged = [...localOnly, ...taskTickets];
  const supportCardAction = (key) => {
    if (key === 'chat' || key === 'call') {
      if (window.YEYE_TOAST) window.YEYE_TOAST(t('sup.paidWhatsAppToast'));
      if (go) go('services');
      return;
    }
    if (key === 'book' && go) go('services');
  };
  return (
    <>
      <PageHead title={t('nav.support')} sub={t('sub.support')}
        actions={<Btn variant="primary" icon="plus" onClick={() => openModal('ticket')}>{t('c.newTicket')}</Btn>} />
      <div className="grid g-12 mb-24" style={{ gap: 14 }}>
        {cards.map((c, i) => (
          <div className="col-3" key={i}><Card className="card-pad pointer" onClick={() => supportCardAction(c.k)} style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <div className="hd-ic" style={{ width: 40, height: 40 }}><Icon name={c.ic} size={19} /></div>
            <div><div className="strong" style={{ fontSize: 14 }}>{t('sup.' + c.k)}</div><div className="dim" style={{ fontSize: 12 }}>{t('sup.' + c.k + 'S')}</div></div>
          </Card></div>
        ))}
      </div>
      <Card>
        <CardHead icon="life-buoy" title={t('sup.yourTickets')} sub={t('sup.yourTicketsSub')} />
        <div className="tbl-wrap" style={{ border: 'none', borderRadius: 0 }}>
          <table className="tbl">
            <thead><tr><th>{t('col.ticket')}</th><th>{t('col.subject')}</th><th>{t('col.category')}</th><th>{t('col.status')}</th><th>{t('col.updated')}</th></tr></thead>
            <tbody>
              {merged.length === 0 ? (
                <tr><td colSpan="5"><div className="muted" style={{ padding: 18, textAlign: 'center' }}>—</div></td></tr>
              ) : merged.map((tk, i) => (
                <tr key={tk.id || i} className="pointer">
                  <td className="mono nm" style={{ fontSize: 12.5 }}>{tk.id}</td>
                  <td className="nm">
                    <div>{tk.subject || t('t.' + tk.tk)}</div>
                    {tk.details && <div className="muted" style={{ fontSize: 11.5, marginTop: 3, whiteSpace: 'normal', maxWidth: 420, lineHeight: 1.4 }}>{tk.details}</div>}
                  </td>
                  <td className="muted">{t('cat.' + tk.catK)}</td>
                  <td><Badge tone={tk.stc} dot>{t('st.' + tk.st)}</Badge></td>
                  <td className="muted">{tk.upd}{tk.upd && tk.upd !== '—' ? ' ' + t('col.ago') : ''}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </Card>
    </>
  );
}

/* ===== FORM SUBMISSION ===== */
function formatFieldValue(value) {
  const text = String(value || '').trim();
  if (!text) return '';
  if (/^\d{4}-\d{2}-\d{2}T/.test(text)) return text.slice(0, 10);
  return text;
}

function contactFieldValue(contact, keys, fallback) {
  const wanted = (Array.isArray(keys) ? keys : [keys]).filter(Boolean);
  const values = contact || {};
  const raw = contact?.raw || {};
  const custom = contact?.customFields || contact?.fields || raw.customFields || [];
  const norm = (value) => String(value || '').toLowerCase().replace(/[\s._-]+/g, '');
  for (const key of wanted) {
    const direct = values[key] ?? raw[key];
    if (direct != null && String(direct).trim() !== '') return direct;
    const stripped = String(key).replace(/^contact\./, '').replace(/^business\./, '');
    const strippedValue = values[stripped] ?? raw[stripped];
    if (strippedValue != null && String(strippedValue).trim() !== '') return strippedValue;
  }
  if (Array.isArray(custom)) {
    const found = custom.find((field) => wanted.some((key) => [
      field?.key, field?.fieldKey, field?.name, field?.id, field?.fieldId, field?.customFieldId
    ].some((candidate) => norm(candidate) === norm(key))));
    const value = found?.value ?? found?.field_value ?? found?.fieldValue;
    if (value != null && String(value).trim() !== '') return value;
  } else if (custom && typeof custom === 'object') {
    for (const key of wanted) {
      const direct = custom[key];
      if (direct != null && String(direct).trim() !== '') return direct;
      const foundKey = Object.keys(custom).find((item) => norm(item) === norm(key));
      if (foundKey && custom[foundKey] != null && String(custom[foundKey]).trim() !== '') return custom[foundKey];
    }
  }
  return fallback || '';
}

function isFilledContactValue(value) {
  const text = String(value ?? '').trim();
  return !!text && text !== '—' && text.toLowerCase() !== 'eksik';
}

function submittedFormChips(contact, formKey) {
  const tags = (contact?.tags || contact?.raw?.tags || []).map((tag) => String(tag).toLowerCase());
  const chips = [];
  const hasBlueSubmission = tags.some((tag) => /^blue[_ -]?card[_ -](form_created|submitted|payment|purchased|created)/.test(tag));
  const hasEmpSubmission = tags.some((tag) => /^employee[_ -]?card[_ -](form_created|submitted|payment|purchased|created)/.test(tag));
  if (hasBlueSubmission) chips.push({ key: 'blue_card', label: 'Blue Card', tone: 'info' });
  if (hasEmpSubmission) chips.push({ key: 'employee_card', label: 'Employee Card', tone: 'warn' });
  return chips;
}

function contactDisplayName(contact) {
  const prettyName = (value) => String(value || '').trim().split(/\s+/).filter(Boolean)
    .map((part) => part ? part.charAt(0).toLocaleUpperCase() + part.slice(1) : part)
    .join(' ');
  const name = [contactFieldValue(contact, ['firstName', 'first_name', 'contact.first_name']), contactFieldValue(contact, ['lastName', 'last_name', 'contact.last_name'])]
    .filter(Boolean).join(' ').trim() || contact?.name || contact?.email || '—';
  if (!name || name === '—' || String(name).includes('@')) return name;
  return prettyName(name);
}

function contactInitials(contact) {
  const name = contactDisplayName(contact);
  const parts = name.split(/\s+/).filter(Boolean);
  return (parts.length > 1 ? parts[0][0] + parts[1][0] : name.slice(0, 2)).toUpperCase();
}

function expandFieldLabelAbbreviations(label, lang = 'en') {
  const replacements = {
    en: { dob: 'Date of Birth', no: 'Number', nat: 'Nationality', occ: 'Occupation', pob: 'Place of Birth', poi: 'Place of Issue', doi: 'Date of Issue', exp: 'Expiry' },
    tr: { dob: 'Doğum Tarihi', no: 'Numara', nat: 'Uyruk', occ: 'Meslek', pob: 'Doğum Yeri', poi: 'Verildiği Yer', doi: 'Verildiği Tarih', exp: 'Geçerlilik' },
    cs: { dob: 'Datum narození', no: 'Číslo', nat: 'Národnost', occ: 'Povolání', pob: 'Místo narození', poi: 'Místo vydání', doi: 'Datum vydání', exp: 'Platnost' },
  };
  const dict = replacements[lang] || replacements.en;
  const text = String(label || '').trim();
  return dict[text.toLowerCase()] || text;
}

function labelFromPlaceholder(row, lang = 'en') {
  const raw = String(row?.placeholder || row?.label || '').replace(/[{}]/g, '').trim();
  const schemaLabelTr = String(row?.schemaLabelTr || '').replace(/[{}]/g, '').trim();
  const labels = {
    en: { ApplicationType: 'Application Type', 'Application Type': 'Application Type', appType: 'Application Type', firstName: 'First Name', FirstName: 'First Name', 'Ad (First Name)': 'First Name', lastName: 'Last Name', LastName: 'Last Name', 'Soyad (Last Name)': 'Last Name', email: 'Email', Email: 'Email', 'E-posta (Email)': 'Email', phone: 'Phone', Phone: 'Phone', 'Telefon (Phone)': 'Phone', BirthCountry: 'Birth Country', countryOfBirth: 'Birth Country', BirthCountryCode: 'Birth Country Code', dateOfBirth: 'Birth Date', BirthDate: 'Birth Date', birthName: 'Birth Name', BirthName: 'Birth Name', placeOfBirth: 'Birth Place', BirthPlace: 'Birth Place', citizenship: 'Citizenship', Citizenship: 'Citizenship', gender: 'Gender', Gender: 'Gender', maritalStatus: 'Marital Status', MaritalStatus: 'Marital Status', nationality: 'Nationality', Nationality: 'Nationality', passportNumber: 'Passport No', PassportNumber: 'Passport No', dateOfIssue: 'Date of Issue', DateOfIssue: 'Date of Issue', expirationDate: 'Expiration Date', ExpirationDate: 'Expiration Date', nationalId: 'National ID', NationalId: 'National ID', employerName: 'Employer Name', EmployerName: 'Employer Name', companyName: 'Company', CompanyName: 'Company', cpcomanyname: 'Company Name', contactemployee_job_position: 'Job Position', position: 'Position', Position: 'Position', occupation: 'Occupation', Occupation: 'Occupation', address: 'Address', Address: 'Address', city: 'City', City: 'City', country: 'Country', Country: 'Country', postalCode: 'Postal Code', PostalCode: 'Postal Code', 'Başvuru Tipi': 'Application Type', 'Ad': 'First Name', 'Soyad': 'Last Name', 'E-posta': 'Email', 'Telefon': 'Phone', 'Cinsiyet': 'Gender', 'Doğum Yeri': 'Birth Place', 'Doğum Ülkesi': 'Birth Country', 'Doğum Tarihi': 'Birth Date', 'Medeni Durum': 'Marital Status', 'Şirket Adı': 'Company Name', 'İş Pozisyonu': 'Job Position' },
    tr: { ApplicationType: 'Başvuru Tipi', 'Application Type': 'Başvuru Tipi', appType: 'Başvuru Tipi', firstName: 'Ad', FirstName: 'Ad', 'Ad (First Name)': 'Ad', lastName: 'Soyad', LastName: 'Soyad', 'Soyad (Last Name)': 'Soyad', email: 'E-posta', Email: 'E-posta', 'E-posta (Email)': 'E-posta', phone: 'Telefon', Phone: 'Telefon', 'Telefon (Phone)': 'Telefon', BirthCountry: 'Doğum Ülkesi', countryOfBirth: 'Doğum Ülkesi', BirthCountryCode: 'Doğum Ülkesi Kodu', dateOfBirth: 'Doğum Tarihi', BirthDate: 'Doğum Tarihi', birthName: 'Doğum Adı', BirthName: 'Doğum Adı', placeOfBirth: 'Doğum Yeri', BirthPlace: 'Doğum Yeri', citizenship: 'Vatandaşlık', Citizenship: 'Vatandaşlık', gender: 'Cinsiyet', Gender: 'Cinsiyet', maritalStatus: 'Medeni Durum', MaritalStatus: 'Medeni Durum', nationality: 'Uyruk', Nationality: 'Uyruk', passportNumber: 'Pasaport No', PassportNumber: 'Pasaport No', dateOfIssue: 'Veriliş Tarihi', DateOfIssue: 'Veriliş Tarihi', expirationDate: 'Geçerlilik Tarihi', ExpirationDate: 'Geçerlilik Tarihi', nationalId: 'Ulusal Kimlik No', NationalId: 'Ulusal Kimlik No', employerName: 'İşveren Adı', EmployerName: 'İşveren Adı', companyName: 'Şirket', CompanyName: 'Şirket', cpcomanyname: 'Şirket Adı', contactemployee_job_position: 'İş Pozisyonu', position: 'Pozisyon', Position: 'Pozisyon', occupation: 'Meslek', Occupation: 'Meslek', address: 'Adres', Address: 'Adres', city: 'Şehir', City: 'Şehir', country: 'Ülke', Country: 'Ülke', postalCode: 'Posta Kodu', PostalCode: 'Posta Kodu', 'Passport Upload': 'Pasaport Yükleme', 'Highest Education Level': 'En Yüksek Eğitim Seviyesi' },
    cs: { ApplicationType: 'Typ žádosti', appType: 'Typ žádosti', firstName: 'Jméno', FirstName: 'Jméno', lastName: 'Příjmení', LastName: 'Příjmení', email: 'E-mail', Email: 'E-mail', phone: 'Telefon', Phone: 'Telefon', BirthCountry: 'Země narození', countryOfBirth: 'Země narození', BirthCountryCode: 'Kód země narození', dateOfBirth: 'Datum narození', BirthDate: 'Datum narození', birthName: 'Rodné jméno', BirthName: 'Rodné jméno', placeOfBirth: 'Místo narození', BirthPlace: 'Místo narození', citizenship: 'Občanství', Citizenship: 'Občanství', gender: 'Pohlaví', Gender: 'Pohlaví', maritalStatus: 'Rodinný stav', MaritalStatus: 'Rodinný stav', nationality: 'Národnost', Nationality: 'Národnost', passportNumber: 'Číslo pasu', PassportNumber: 'Číslo pasu', dateOfIssue: 'Datum vydání', DateOfIssue: 'Datum vydání', expirationDate: 'Datum platnosti', ExpirationDate: 'Datum platnosti', nationalId: 'Národní ID', NationalId: 'Národní ID', employerName: 'Zaměstnavatel', EmployerName: 'Zaměstnavatel', companyName: 'Společnost', CompanyName: 'Společnost', cpcomanyname: 'Název společnosti', contactemployee_job_position: 'Pracovní pozice', position: 'Pozice', Position: 'Pozice', occupation: 'Povolání', Occupation: 'Povolání', address: 'Adresa', Address: 'Adresa', city: 'Město', City: 'Město', country: 'Země', Country: 'Země', postalCode: 'PSČ', PostalCode: 'PSČ', 'Başvuru Tipi': 'Typ žádosti', 'Ad': 'Jméno', 'Soyad': 'Příjmení', 'E-posta': 'E-mail', 'Telefon': 'Telefon', 'Cinsiyet': 'Pohlaví', 'Doğum Yeri': 'Místo narození', 'Doğum Ülkesi': 'Země narození', 'Doğum Tarihi': 'Datum narození', 'Medeni Durum': 'Rodinný stav', 'Şirket Adı': 'Název společnosti', 'İş Pozisyonu': 'Pracovní pozice' },
  };
  const dict = labels[lang] || labels.en;
  const keys = [row?.formKey, raw, row?.fieldName, row?.key, row?.updateKey].filter(Boolean);
  for (const key of keys) if (dict[key]) return expandFieldLabelAbbreviations(dict[key], lang);
  const normalizeLabelKey = (value) => String(value || '')
    .replace(/^contact\./, '')
    .replace(/^business\./, '')
    .replace(/[{}]/g, '')
    .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
    .toLowerCase()
    .replace(/[^a-z0-9ğüşöçıİĞÜŞÖÇ]+/g, '_')
    .replace(/^_+|_+$/g, '');
  const fieldLabels = {
    en: {
      dob: 'Date of Birth', no: 'Number', nat: 'Nationality', occ: 'Occupation', pob: 'Place of Birth', poi: 'Place of Issue', doi: 'Date of Issue', exp: 'Expiry',
      arrival_date: 'Anticipated Arrival Date', arrivaldate: 'Anticipated Arrival Date',
      app_type: 'Application Type', apptype: 'Application Type', application_type: 'Application Type',
      num_children: 'Number of Children', numchildren: 'Number of Children', how_many_children_do_you_have: 'Number of Children',
      num_siblings: 'Number of Siblings', numsiblings: 'Number of Siblings', how_many_siblings_do_you_have: 'Number of Siblings',
      company_address_country: 'Company Address Country', company_address_country_country_list: 'Company Address Country',
      company_address_municipality: 'Company Address Municipality', company_address_district: 'Company Address District',
      company_address_street: 'Company Address Street', company_address_building_number: 'Company Address Building Number',
      company_address_postal_zip_code: 'Company Address Postal Zip Code', contactemployee_work_address: 'Work Address',
      contract_start_date: 'Contract Start Date', contractstart_date: 'Contract Start Date', contractstartdate: 'Contract Start Date',
      employee_contract_start_date: 'Contract Start Date', contract_end_date: 'Contract End Date', contractend_date: 'Contract End Date',
      contractenddate: 'Contract End Date', employee_contract_end_date: 'Contract End Date', place_of_work: 'Place of Work',
      emp_employer: 'Previous Employer', empemployer: 'Previous Employer', emp_position: 'Previous Position', empposition: 'Previous Position',
      emp_country: 'Previous Employment Country', empcountry: 'Previous Employment Country',
      emp_municipality: 'Previous Employment Municipality', empmunicipality: 'Previous Employment Municipality',
      emp_municipal_district: 'Previous Employment District', empmunicipaldistrict: 'Previous Employment District',
      emp_street: 'Previous Employment Street', empstreet: 'Previous Employment Street',
      emp_number: 'Previous Employment Number', empnumber: 'Previous Employment Number',
      emp_post_code: 'Previous Employment Postal Code', emppostcode: 'Previous Employment Postal Code',
    },
    tr: {
      dob: 'Doğum Tarihi', no: 'Numara', nat: 'Uyruk', occ: 'Meslek', pob: 'Doğum Yeri', poi: 'Verildiği Yer', doi: 'Verildiği Tarih', exp: 'Geçerlilik',
      arrival_date: 'Beklenen Varış Tarihi', arrivaldate: 'Beklenen Varış Tarihi',
      app_type: 'Başvuru Tipi', apptype: 'Başvuru Tipi', application_type: 'Başvuru Tipi',
      num_children: 'Çocuk Sayısı', numchildren: 'Çocuk Sayısı', how_many_children_do_you_have: 'Çocuk Sayısı',
      num_siblings: 'Kardeş Sayısı', numsiblings: 'Kardeş Sayısı', how_many_siblings_do_you_have: 'Kardeş Sayısı',
      company_address_country: 'Şirket Adresi - Ülke', company_address_country_country_list: 'Şirket Adresi - Ülke',
      company_address_municipality: 'Şirket Adresi - Belediye', company_address_district: 'Şirket Adresi - İlçe',
      company_address_street: 'Şirket Adresi - Sokak', company_address_building_number: 'Şirket Adresi - Bina No',
      company_address_postal_zip_code: 'Şirket Adresi - Posta Kodu', contactemployee_work_address: 'Çalışma Adresi',
      contract_start_date: 'Sözleşme Başlangıç Tarihi', contractstart_date: 'Sözleşme Başlangıç Tarihi', contractstartdate: 'Sözleşme Başlangıç Tarihi',
      employee_contract_start_date: 'Sözleşme Başlangıç Tarihi', contract_end_date: 'Sözleşme Bitiş Tarihi', contractend_date: 'Sözleşme Bitiş Tarihi',
      contractenddate: 'Sözleşme Bitiş Tarihi', employee_contract_end_date: 'Sözleşme Bitiş Tarihi', place_of_work: 'Çalışma Yeri',
      emp_employer: 'Son İşveren', empemployer: 'Son İşveren', emp_position: 'Son Pozisyon', empposition: 'Son Pozisyon',
      emp_country: 'Son İstihdam Ülkesi', empcountry: 'Son İstihdam Ülkesi',
      emp_municipality: 'Son İstihdam Belediyesi', empmunicipality: 'Son İstihdam Belediyesi',
      emp_municipal_district: 'Son İstihdam İlçesi', empmunicipaldistrict: 'Son İstihdam İlçesi',
      emp_street: 'Son İstihdam Sokağı', empstreet: 'Son İstihdam Sokağı',
      emp_number: 'Son İstihdam Kapı/Bina No', empnumber: 'Son İstihdam Kapı/Bina No',
      emp_post_code: 'Son İstihdam Posta Kodu', emppostcode: 'Son İstihdam Posta Kodu',
    },
    cs: {
      dob: 'Datum narození', no: 'Číslo', nat: 'Národnost', occ: 'Povolání', pob: 'Místo narození', poi: 'Místo vydání', doi: 'Datum vydání', exp: 'Platnost',
      arrival_date: 'Očekávané datum příjezdu', arrivaldate: 'Očekávané datum příjezdu',
      app_type: 'Typ žádosti', apptype: 'Typ žádosti', application_type: 'Typ žádosti',
      num_children: 'Počet dětí', numchildren: 'Počet dětí', how_many_children_do_you_have: 'Počet dětí',
      num_siblings: 'Počet sourozenců', numsiblings: 'Počet sourozenců', how_many_siblings_do_you_have: 'Počet sourozenců',
      company_address_country: 'Adresa společnosti - země', company_address_country_country_list: 'Adresa společnosti - země',
      company_address_municipality: 'Adresa společnosti - obec', company_address_district: 'Adresa společnosti - okres',
      company_address_street: 'Adresa společnosti - ulice', company_address_building_number: 'Adresa společnosti - číslo budovy',
      company_address_postal_zip_code: 'Adresa společnosti - PSČ', contactemployee_work_address: 'Adresa pracoviště',
      contract_start_date: 'Datum začátku smlouvy', contractstart_date: 'Datum začátku smlouvy', contractstartdate: 'Datum začátku smlouvy',
      employee_contract_start_date: 'Datum začátku smlouvy', contract_end_date: 'Datum konce smlouvy', contractend_date: 'Datum konce smlouvy',
      contractenddate: 'Datum konce smlouvy', employee_contract_end_date: 'Datum konce smlouvy', place_of_work: 'Místo výkonu práce',
      emp_employer: 'Poslední zaměstnavatel', empemployer: 'Poslední zaměstnavatel', emp_position: 'Poslední pozice', empposition: 'Poslední pozice',
      emp_country: 'Země posledního zaměstnání', empcountry: 'Země posledního zaměstnání',
      emp_municipality: 'Obec posledního zaměstnání', empmunicipality: 'Obec posledního zaměstnání',
      emp_municipal_district: 'Okres posledního zaměstnání', empmunicipaldistrict: 'Okres posledního zaměstnání',
      emp_street: 'Ulice posledního zaměstnání', empstreet: 'Ulice posledního zaměstnání',
      emp_number: 'Číslo posledního zaměstnání', empnumber: 'Číslo posledního zaměstnání',
      emp_post_code: 'PSČ posledního zaměstnání', emppostcode: 'PSČ posledního zaměstnání',
    },
  };
  const fieldDict = fieldLabels[lang] || fieldLabels.en;
  const normalizedKeys = keys.map(normalizeLabelKey);
  for (const key of normalizedKeys) if (fieldDict[key]) return expandFieldLabelAbbreviations(fieldDict[key], lang);
  const abbreviatedKey = normalizedKeys
    .map((key) => key.match(/(?:^|_)(dob|nat|occ|pob|poi|doi|exp)$/)?.[1])
    .find(Boolean);
  if (abbreviatedKey && fieldDict[abbreviatedKey]) return fieldDict[abbreviatedKey];
  if (lang === 'tr' && schemaLabelTr) return expandFieldLabelAbbreviations(schemaLabelTr, lang);
  if (lang === 'tr' && raw) return expandFieldLabelAbbreviations(raw, lang);
  if (!raw) return row?.fieldName || (lang === 'tr' ? 'Alan' : lang === 'cs' ? 'Pole' : 'Field');
  const base = String(row?.formKey || raw);
  return expandFieldLabelAbbreviations(base.replace(/^contact\./, '').replace(/^business\./, '').replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/[_-]+/g, ' ').trim().replace(/\b\w/g, (s) => s.toUpperCase()), lang);
}

function upperUiLabel(value, lang = 'en') {
  const text = String(value || '');
  if (lang === 'tr') return text.toLocaleUpperCase('tr-TR');
  if (lang === 'cs') return text.toLocaleUpperCase('cs-CZ');
  return text.toUpperCase();
}

const APPLICATION_TYPE_OPTIONS = [
  { value: 'for_a_permit', labels: { en: 'For a Permit', tr: 'İzin Başvurusu', cs: 'Nová žádost' } },
  { value: 'for_a_renewal', labels: { en: 'For a Renewal', tr: 'Yenileme Başvurusu', cs: 'Prodloužení' } },
  { value: 'change_of_employer_or_placement', labels: { en: 'Change of Employer or Placement', tr: 'İşveren veya İş Yeri Değişikliği', cs: 'Změna zaměstnavatele nebo pracovní pozice' } },
];

function isApplicationTypeField(row) {
  const key = `${row?.key || ''} ${row?.fieldName || ''} ${row?.formKey || ''}`.toLowerCase();
  return /apptype|applicationtype|application_type/.test(key);
}

function localizedFieldOptions(options, lang = 'en') {
  return (options || []).map((option) => {
    if (!option || typeof option !== 'object') return option;
    return {
      value: option.value,
      label: option.labels?.[lang] || option.labels?.en || option.label || option.value,
    };
  });
}

function stripSectionContext(label, sectionId, sectionTitle, lang = 'en') {
  const rawLabel = String(label || '').trim();
  if (!rawLabel) return rawLabel;
  const context = `${sectionId || ''} ${sectionTitle || ''}`.toLocaleLowerCase(lang === 'tr' ? 'tr-TR' : undefined);
  let prefixes = [];
  if (/czechia_address|çekya adresi|address in czechia|adresa v česku/.test(context)) {
    prefixes = ['Çekya', 'Cz', 'Czechia', 'Česko', 'Česká', 'Český'];
  } else if (/residence_abroad|ikamet adresi|residence address|adresa bydliště/.test(context)) {
    prefixes = ['İkamet', 'Residence', 'Bydliště', 'Res'];
  } else if (/shipping_address|kargo adresi|shipping address|delivery|doručovací/.test(context)) {
    prefixes = ['Kargo', 'Delivery', 'Shipping', 'Doručovací', 'Res'];
  } else if (/^company\b|şirket bilgileri|employer information|údaje zaměstnavatele/.test(context)) {
    prefixes = ['Şirket Adresi', 'Company Address', 'Employer Address', 'Adresa společnosti'];
  } else if (/previous_stay_in_czech_republic|önceki|previous|předchozí/.test(context)) {
    prefixes = ['Prev Stay', 'Previous Stay', 'Önceki Kalış', 'Předchozí pobyt'];
  } else if (/last_employment|son istihdam|last employment|poslední zaměstnání/.test(context)) {
    prefixes = ['Son İstihdam', 'Last Employment', 'Previous Employment', 'Poslední zaměstnání'];
  } else if (/spouse_|eş bilgileri|spouse|manžel/.test(context)) {
    prefixes = ['Eş', 'Spouse', 'Manžel', 'Manželka'];
  } else if (/family_information.*(?:child|children|sibling|father|mother|parent)|children|çocuk|cocuk|siblings|kardeş|kardes|parents|anne|baba|father|mother|otec|matka/.test(context)) {
    prefixes = [
      'Child 1', 'Child 2', 'Child 3', 'Child 4', 'Child1', 'Child2', 'Child3', 'Child4',
      'Sibling 1', 'Sibling 2', 'Sibling 3', 'Sibling 4', 'Sibling1', 'Sibling2', 'Sibling3', 'Sibling4',
      'Çocuk 1', 'Çocuk 2', 'Çocuk 3', 'Çocuk 4', 'Kardeş 1', 'Kardeş 2', 'Kardeş 3', 'Kardeş 4',
      'Anne', 'Baba', 'Mother', 'Father', 'Parent', 'Matka', 'Otec',
      'Residence', 'İkamet', 'Bydliště', 'Res',
    ];
  } else if (/passport_travel_document|pasaport|passport|cestovní pas/.test(context)) {
    prefixes = ['Pasaport', 'Passport', 'Cestovní pas', 'Pass'];
  }
  if (!prefixes.length) return expandFieldLabelAbbreviations(rawLabel, lang);
  const escaped = prefixes.map((prefix) => prefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|');
  const prefixPattern = new RegExp(`^(?:${escaped})(?:\\s+(?:Adresi|Address))?\\s*(?:[-–—:/]\\s*)?`, 'i');
  const prefixOnlyPattern = new RegExp(`^(?:${escaped})\\s*(?:[-–—:/]\\s*)?`, 'i');
  let cleaned = rawLabel;
  let previous = '';
  while (cleaned && cleaned !== previous) {
    previous = cleaned;
    const contextual = cleaned.replace(prefixPattern, '').replace(/^[\s\-–—:/]+/, '').trim();
    cleaned = (contextual || cleaned.replace(prefixOnlyPattern, '')).replace(/^[\s\-–—:/]+/, '').trim();
  }
  cleaned = cleaned.replace(/[\s\-–—:/]+$/, '').trim();
  if (!cleaned) return rawLabel;
  const turkishContextNouns = { Adresi: 'Adres', Ülkesi: 'Ülke', Belediyesi: 'Belediye', İlçesi: 'İlçe', Sokağı: 'Sokak', Numarası: 'Numara' };
  return expandFieldLabelAbbreviations(turkishContextNouns[cleaned] || cleaned, lang);
}

function schemaSectionFallbackTitle(id, lang = 'en') {
  const titles = {
    contact_kisisel_iletisim: { en: 'Personal Contact', tr: 'Kişisel İletişim', cs: 'Osobní kontakt' },
    personal_information: { en: 'Personal Information', tr: 'Kişisel Bilgiler', cs: 'Osobní údaje' },
    company: { en: 'Employer Information', tr: 'Şirket Bilgileri', cs: 'Údaje zaměstnavatele' },
    last_employment: { en: 'Last Employment', tr: 'Son İstihdam', cs: 'Poslední zaměstnání' },
    residence_abroad: { en: 'Residence Address', tr: 'İkamet Adresi', cs: 'Adresa bydliště' },
    czechia_address: { en: 'Czechia Address', tr: 'Çekya Adresi', cs: 'Adresa v Česku' },
    shipping_address_shippingsameasczechia_no_ise_gosterilir: { en: 'Shipping Address', tr: 'Kargo Adresi', cs: 'Adresa pro zásilky' },
    passport_travel_document: { en: 'Passport / Travel Document', tr: 'Pasaport / Seyahat Belgesi', cs: 'Cestovní pas / Doklad' },
    previous_stay_in_czech_republic: { en: 'Previous Stay in Czechia', tr: 'Önceki Çekya Konaklaması', cs: 'Předchozí pobyt v Česku' },
    spouse_maritalstatus_married_ise: { en: 'Spouse Information', tr: 'Eş Bilgileri', cs: 'Údaje o manželovi/manželce' },
    children_1_4_dinamik: { en: 'Children', tr: 'Çocuk Bilgileri', cs: 'Děti' },
    parents: { en: 'Parents', tr: 'Anne / Baba Bilgileri', cs: 'Rodiče' },
    siblings_1_4_dinamik: { en: 'Siblings', tr: 'Kardeş Bilgileri', cs: 'Sourozenci' },
    consent: { en: 'Consents', tr: 'Onaylar', cs: 'Souhlasy' },
  };
  const entry = titles[id];
  return entry ? (entry[lang] || entry.en) : '';
}

function buildContactCardSections(contact, rows, formKey, lang = 'en', t = (key) => key, getCurrentAnswer) {
  const sectionLabels = {
    en: { contact: 'Personal Contact', personal: 'Personal Information', company: 'Employer Information', passport: 'Passport / Travel Document', family: 'Family Information', approvals: 'Approvals', fallback: 'Form Section' },
    tr: { contact: 'Kişisel İletişim', personal: 'Kişisel Bilgiler', company: 'İşveren Bilgileri', passport: 'Pasaport / Seyahat Belgesi', family: 'Aile Bilgileri', approvals: 'Onaylar', fallback: 'Form Bölümü' },
    cs: { contact: 'Osobní kontakt', personal: 'Osobní údaje', company: 'Údaje zaměstnavatele', passport: 'Pas / cestovní doklad', family: 'Rodinné údaje', approvals: 'Souhlasy', fallback: 'Sekce formuláře' },
  };
  const st = sectionLabels[lang] || sectionLabels.en;
  const mkRow = (label, value, key, sourceRow) => Object.assign({}, sourceRow || {}, { l: label, v: formatFieldValue(value), key: key || sourceRow?.key || sourceRow?.fieldName || label });
  const requiredLabel = (row, fallback) => {
    const candidates = [row?.updateKey, row?.fieldName, row?.key, row?.formKey]
      .filter(Boolean)
      .map((key) => String(key).replace(/^contact\./, '').toLowerCase());
    const entry = (window.YEYE_REQUIRED_FIELDS || []).find((item) => (
      candidates.includes(String(item.key).replace(/^contact\./, '').toLowerCase())
    ));
    return entry ? t('wizard.field.' + entry.key) : fallback;
  };
  const familyTitles = {
    en: { father: 'Father', mother: 'Mother', child: 'Child', sibling: 'Sibling' },
    tr: { father: 'Baba', mother: 'Anne', child: 'Çocuk', sibling: 'Kardeş' },
    cs: { father: 'Otec', mother: 'Matka', child: 'Dítě', sibling: 'Sourozenec' },
  }[lang] || {};
  const schemaRows = rows.filter((row) => row.schemaSource === 'v3');
  if (schemaRows.length) {
    const bucketFor = (row) => {
      const id = String(row.sectionId || '');
      const title = String(schemaSectionFallbackTitle(id, lang) || row.sectionTitle || row.section || st.fallback);
      const filters = {
        contact_kisisel_iletisim: 'contact_kisisel_iletisim',
        personal_information: 'personal_information',
        company: 'company',
        last_employment: 'last_employment',
        residence_abroad: 'addresses',
        czechia_address: 'addresses',
        shipping_address_shippingsameasczechia_no_ise_gosterilir: 'addresses',
        passport_travel_document: 'passport_travel_document',
        previous_stay_in_czech_republic: 'last_employment',
        spouse_maritalstatus_married_ise: 'family_information',
        children_1_4_dinamik: 'family_information',
        parents: 'family_information',
        siblings_1_4_dinamik: 'family_information',
        consent: 'approvals',
      };
      return { id, title, filterId: filters[id] || id };
    };
    const familyMemberIndex = (row, type) => {
      const raw = `${row?.label || row?.placeholder || ''} ${row?.fieldName || ''} ${row?.formKey || ''}`.toLowerCase();
      const pattern = type === 'child'
        ? /(?:çocuk|child)\s*([1-4])|child([1-4])/
        : /(?:kardeş|kardes|sibling)\s*([1-4])|sibling([1-4])/;
      const match = raw.match(pattern);
      const index = Number(match?.[1] || match?.[2] || 0);
      return index >= 1 && index <= 4 ? index : 0;
    };
    const familyCount = (type) => {
      const wanted = type === 'child' ? 'numChildren' : 'numSiblings';
      const row = schemaRows.find((item) => item.formKey === wanted);
      const currentValue = typeof getCurrentAnswer === 'function' ? getCurrentAnswer(wanted) : '';
      const value = currentValue !== '' && currentValue != null ? currentValue : (row ? row.value : '');
      if (/^(0|no|none|yok|hayır|hayir)$/i.test(String(value || '').trim())) return 0;
      const numeric = Number.parseInt(String(value || '').match(/\d+/)?.[0] || '', 10);
      return Number.isFinite(numeric) ? Math.max(0, Math.min(4, numeric)) : 4;
    };
    const sections = new Map();
    const addSectionRow = (section, row) => {
      if (!sections.has(section.id)) sections.set(section.id, Object.assign({}, section, { rows: [], seen: new Set() }));
      const target = sections.get(section.id);
      const key = row.updateKey || row.fieldName || row.key || row.label;
      if (target.seen.has(key)) return;
      target.seen.add(key);
      const label = stripSectionContext(labelFromPlaceholder(row, lang), section.id, section.title, lang);
      target.rows.push(mkRow(label, row.value, key, row));
    };
    schemaRows.forEach((row) => {
      const bucket = bucketFor(row);
      const sectionId = String(row.sectionId || '');
      const raw = `${sectionId} ${row.sectionTitle || row.section || ''}`.toLowerCase();
      if (/parents|anne|baba/.test(raw)) {
        const label = `${row.schemaLabelTr || ''} ${row.label || row.placeholder || ''} ${row.formKey || ''}`;
        const parent = /(?:^|\s)(?:Baba|Father|Otec|father)/i.test(label) ? 'father' : (/(?:^|\s)(?:Anne|Mother|Matka|mother)/i.test(label) ? 'mother' : '');
        if (parent) {
          addSectionRow({ id: `${bucket.filterId}:${sectionId}:${parent}`, title: familyTitles[parent], filterId: bucket.filterId }, row);
          return;
        }
      }
      if (/children|çocuk|cocuk/.test(raw)) {
        const index = familyMemberIndex(row, 'child');
        const count = familyCount('child');
        if (index && index <= count) {
          addSectionRow({ id: `${bucket.filterId}:${sectionId}:child${index}`, title: `${familyTitles.child} ${index}`, filterId: bucket.filterId }, row);
        }
        return;
      }
      if (/siblings|kardeş|kardes/.test(raw)) {
        const index = familyMemberIndex(row, 'sibling');
        const count = familyCount('sibling');
        if (index && index <= count) {
          addSectionRow({ id: `${bucket.filterId}:${sectionId}:sibling${index}`, title: `${familyTitles.sibling} ${index}`, filterId: bucket.filterId }, row);
        }
        return;
      }
      addSectionRow(bucket, row);
    });
    return Array.from(sections.values()).map((section) => ({
      id: section.id,
      title: section.title,
      filterId: section.filterId,
      rows: section.rows,
    })).filter((section) => section.rows.length);
  }
  const byPlaceholder = {};
  rows.forEach((row) => {
    const clean = String(row.placeholder || '').replace(/[{}]/g, '').trim();
    if (clean && !byPlaceholder[clean]) byPlaceholder[clean] = row;
  });
  const pickRow = (names, label, fallbackKeys) => {
    const row = (Array.isArray(names) ? names : [names]).map((name) => byPlaceholder[name]).find(Boolean);
    return mkRow(label, row?.value || contactFieldValue(contact, fallbackKeys || []), row?.fieldName || label);
  };
  const used = new Set();
  const use = (row) => {
    [row?.fieldName, row?.placeholder, String(row?.placeholder || '').replace(/[{}]/g, '').trim()].filter(Boolean).forEach((key) => used.add(key));
    return row;
  };

  const contactRows = [
    use(pickRow(['ApplicationType', 'Application Type', 'Başvuru Tipi'], labelFromPlaceholder({ formKey: 'appType' }, lang), ['empcapplicationtype', 'contact.empcapplicationtype'])),
    use(pickRow('FirstName', t('wizard.field.firstName'), ['firstName', 'first_name', 'contact.first_name'])),
    use(pickRow('LastName', t('wizard.field.lastName'), ['lastName', 'last_name', 'contact.last_name'])),
    use(pickRow('Email', t('wizard.field.email'), ['email', 'contact.email'])),
    use(pickRow('Phone', t('wizard.field.phone'), ['phone', 'contact.phone'])),
  ];

  const sectionMap = [
    { id: 'personal_information', title: st.personal, filterId: 'personal_information', test: (row) => row.section === 'A - Personal data' },
    { id: 'company', title: st.company, filterId: 'company', test: (row) => row.section === 'F - Employment / Company' },
    { id: 'addresses', title: lang === 'tr' ? 'Adres Bilgileri' : lang === 'cs' ? 'Adresní údaje' : 'Address Information', filterId: 'addresses', test: (row) => /^B |^C1 |^C2 /.test(row.section) },
    { id: 'passport_travel_document', title: st.passport, filterId: 'passport_travel_document', test: (row) => row.section === 'D - Passport / Permit' },
    { id: 'last_employment', title: lang === 'tr' ? 'Son İstihdam' : lang === 'cs' ? 'Poslední zaměstnání' : 'Last Employment', filterId: 'last_employment', test: (row) => row.section === 'E - Previous stay / Previous work' },
    { id: 'family_information', title: st.family, filterId: 'family_information', test: (row) => ['G - Spouse', 'H - Children', 'I - Parents', 'J - Siblings'].includes(row.section) },
    { id: 'approvals', title: st.approvals, filterId: 'approvals', test: (row) => row.section === 'K - Education / Occupation' },
  ];

  const sections = [{ id: 'contact_kisisel_iletisim', title: st.contact, filterId: 'contact_kisisel_iletisim', rows: contactRows }];
  sectionMap.forEach((def) => {
    const sectionRows = rows
      .filter((row) => ![row.fieldName, row.placeholder, String(row.placeholder || '').replace(/[{}]/g, '').trim()].some((key) => used.has(key)) && def.test(row))
      .map((row) => mkRow(requiredLabel(row, labelFromPlaceholder(row, lang)), row.value, row.fieldName));
    const dedupedRows = def.id === 'personal_information'
      ? sectionRows.filter((row) => !['Ad', 'Soyad', 'E-posta', 'Telefon', 'First Name', 'Last Name', 'Email', 'Phone', 'Jméno', 'Příjmení', 'E-mail'].includes(row.l))
      : sectionRows;
    if (dedupedRows.length) sections.push({ ...def, rows: dedupedRows });
  });
  return sections;
}

function applicationFieldKind(row, fallbackKind) {
  if (row?.kind) return row.kind;
  const key = `${row?.key || ''} ${row?.fieldName || ''} ${row?.formKey || ''} ${row?.fieldType || ''}`.toLowerCase();
  const label = `${row?.label || ''} ${row?.placeholder || ''} ${row?.l || ''}`.toLowerCase();
  const fieldType = String(row?.fieldType || '').toLowerCase();
  if (/passport_place_of_issue|passplaceofissue|place_of_birth|placeofbirth|place_of_work|placeofwork/.test(key)) return 'text';
  if (/email/.test(key)) return 'email';
  if (/phone|telefon/.test(key)) return 'phone';
  if (/country_list|countryofbirth|country_of_birth|nationality|citizenship|residencecountry|previouscountry|deliverycountry|shippingcountry|company_address_country|employercountry|\bcountry\b|country$|country\s/.test(key)) return 'country';
  if (/apptype|applicationtype|application_type/.test(key)) return 'select';
  if (/gender/.test(key)) return 'select';
  if (/marital/.test(key)) return 'select';
  if (/how_many_children|how_many_siblings|numchildren|numsiblings/.test(key)) return 'select';
  if (/yesno|yes_no|has_|same/.test(key) || /var mı|mı\?|mi\?/.test(label)) return 'select';
  if (/date/.test(fieldType) && !/placeofbirth|place_of_birth|countryofbirth|country_of_birth/.test(key)) return 'date';
  if (/dateofbirth|date_of_birth|birthdate|passport_date_of_issue|passport_expiry_date|passdateofissue|passexpirydate|contractstartdate|contractenddate|start_date|end_date|expiry|expiration|arrival_date|arrivaldate|previousstayfrom|previousstayuntil|prevstayfrom|prevstayuntil|prev_stay_from|prev_stay_until|stayfrom|stayuntil/.test(key)) return 'date';
  return fallbackKind || 'text';
}

function applicationFieldOptions(row, fallbackOptions, lang) {
  const key = `${row?.key || ''} ${row?.fieldName || ''} ${row?.formKey || ''}`.toLowerCase();
  const label = `${row?.label || ''} ${row?.placeholder || ''} ${row?.l || ''}`.toLowerCase();
  if (isApplicationTypeField(row)) return localizedFieldOptions(APPLICATION_TYPE_OPTIONS, lang);
  if (Array.isArray(row?.options) && row.options.length) return localizedFieldOptions(row.options, lang);
  if (/how_many_children|how_many_siblings|numchildren|numsiblings/.test(key)) return ['0', '1', '2', '3', '4'];
  if (/gender/.test(key)) {
    if (lang === 'tr') return ['Kadın', 'Erkek', 'Diğer'];
    if (lang === 'cs') return ['Žena', 'Muž', 'Jiné'];
    return ['Female', 'Male', 'Other'];
  }
  if (/marital/.test(key)) {
    if (lang === 'tr') return ['Bekar', 'Evli', 'Boşanmış', 'Dul'];
    if (lang === 'cs') return ['Svobodný/á', 'Ženatý/Vdaná', 'Rozvedený/á', 'Vdovec/Vdova'];
    return ['Single', 'Married', 'Divorced', 'Widowed'];
  }
  if (/yesno|yes_no|has_|same/.test(key) || /var mı|mı\?|mi\?/.test(label)) return lang === 'tr' ? ['Evet', 'Hayır'] : ['Yes', 'No'];
  return fallbackOptions;
}

function ContactRow({ row, editing, editValue, onEditChange }) {
  const { t, lang } = useT();
  const filled = isFilledContactValue(row.v);
  if (editing) {
    const kind = applicationFieldKind(row, (window.YEYE_PROFILE && window.YEYE_PROFILE.kindFor(row.key)) || 'text');
    const options = applicationFieldOptions(row, (window.YEYE_PROFILE && window.YEYE_PROFILE.optionsFor(row.key)) || null, lang);
    const currentValue = editValue != null ? editValue : (row.v || '');
    if (isApplicationTypeField(row) && filled) {
      const selected = (options || []).find((option) => String(option?.value ?? option) === String(currentValue));
      const displayValue = selected && typeof selected === 'object' ? selected.label : currentValue;
      return (
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, padding: '9px 10px', borderBottom: '1px solid var(--line-2)' }}>
          <span style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--ink-500)', flex: '0 0 40%' }}>{row.l}</span>
          <span className="flex ac gap-7" style={{ fontSize: 13.5, color: 'var(--ink-900)', fontWeight: 650, textAlign: 'right' }}>
            <Icon name="lock-keyhole" size={13} />{displayValue}
          </span>
        </div>
      );
    }
    const commonStyle = { flex: '1 1 auto', maxWidth: '55%', textAlign: 'right' };
    const widget = window.renderProfileFieldWidget({
      kind,
      value: currentValue,
      onChange: (value) => onEditChange && onEditChange(row.key, value),
      options,
      label: row.l,
      lang,
      placeholder: filled ? '' : t('form.missing'),
      style: commonStyle,
    });
    return (
      <div style={{
        display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12,
        padding: '9px 10px',
        borderBottom: '1px solid var(--line-2)'
      }}>
        <span style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--ink-500)', flex: '0 0 40%' }}>{row.l}</span>
        {widget}
      </div>
    );
  }
  return (
    <div style={{
      display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16,
      margin: filled ? 0 : '6px 0', padding: filled ? '10px 0' : '9px 10px',
      borderBottom: filled ? '1px solid var(--line-2)' : 'none',
      border: filled ? 'none' : '1px solid var(--bad-line)',
      borderRadius: filled ? 0 : 10, background: filled ? 'transparent' : 'var(--bad-bg)'
    }}>
      <span style={{ fontSize: 12.5, fontWeight: filled ? 500 : 700, color: filled ? 'var(--ink-500)' : 'var(--bad)' }}>{row.l}</span>
      <span style={{ fontSize: 13.5, color: filled ? 'var(--ink-900)' : 'var(--bad)', fontWeight: 650, textAlign: 'right', wordBreak: 'break-word' }}>
        {filled ? row.v : t('form.missing')}
      </span>
    </div>
  );
}

function ApplicationFieldsCard({ ct, contact, fieldMappings }) {
  const { t } = useT();
  const [showAll, setShowAll] = useState(false);
  const formKey = ct && (ct.key === 'blue_card' || ct.key === 'employee_card') ? ct.key : '';
  if (!formKey || !window.YEYE_FIELD_MAPPING) return null;
  const rows = window.YEYE_FIELD_MAPPING.forForm(fieldMappings || [], formKey, contact || {});
  const filled = rows.filter((row) => row.value);
  const visibleRows = showAll ? rows : (filled.length ? filled : rows).slice(0, 24);
  const sections = visibleRows.reduce((acc, row) => {
    (acc[row.section] = acc[row.section] || []).push(row);
    return acc;
  }, {});
  const copy = {
    empty: contact ? t('form.empty') : t('form.notConnected'),
    mapped: t('form.mapped'),
    submitted: t('form.submitted'),
    showAll: t('form.showAll'),
    showFilled: t('form.showFilled'),
    missing: t('form.waiting'),
  };

  return (
    <Card>
      <CardHead icon="clipboard-list" title={t('form.applicationData')} sub={`${rows.length} ${copy.mapped} · ${filled.length} ${copy.submitted}`} />
      <div className="card-bd" style={{ paddingTop: 0 }}>
        {!rows.length ? (
          <div className="muted" style={{ padding: '4px 0 14px' }}>{copy.empty}</div>
        ) : (
          <>
            <div className="flex jb ac wrap gap-10 mb-14">
              <div className="muted" style={{ fontSize: 12.5 }}>Blue Card / Employee Card fields are read from the GHL mapping library.</div>
              <Btn variant="ghost" size="sm" icon={showAll ? 'eye' : 'list'} onClick={() => setShowAll((v) => !v)}>
                {showAll ? copy.showFilled : copy.showAll}
              </Btn>
            </div>
            <div className="flex col gap-16">
              {Object.keys(sections).map((section) => (
                <div key={section}>
                  <div className="eyebrow mb-8">{section}</div>
                  <div className="grid g-12" style={{ gap: 10 }}>
                    {sections[section].map((row) => (
                      <div className="col-4" key={`${row.fieldName}-${row.placeholder}`}>
                        <div style={{ border: '1px solid var(--line-2)', borderRadius: 'var(--r-sm)', padding: 12, minHeight: 76, background: row.value ? 'var(--surface)' : 'var(--surface-2)' }}>
                          <div className="dim" style={{ fontSize: 11.5, marginBottom: 6, lineHeight: 1.35 }}>{row.label}</div>
                          <div className={row.value ? 'strong' : 'muted'} style={{ fontSize: 13, lineHeight: 1.35, wordBreak: 'break-word' }}>
                            {formatFieldValue(row.value) || copy.missing}
                          </div>
                        </div>
                      </div>
                    ))}
                  </div>
                </div>
              ))}
            </div>
          </>
        )}
      </div>
    </Card>
  );
}

const INTERNAL_APPLICATION_FORMS = [
  { key: 'blue_card', icon: 'badge-check', label: { en: 'Blue Card Application Form', tr: 'Blue Card Application Form', cs: 'Blue Card Application Form' } },
  { key: 'employee_card', icon: 'id-card', label: { en: 'Employee Card Application Form', tr: 'Employee Card Application Form', cs: 'Employee Card Application Form' } },
  { key: 'employee_onboarding', icon: 'clipboard-check', label: { en: 'Employee Onboarding', tr: 'Employee Onboarding', cs: 'Employee Onboarding' } },
];

function applicationFormLabel(key, lang) {
  const form = INTERNAL_APPLICATION_FORMS.find((item) => item.key === key);
  return form ? (form.label[lang] || form.label.en) : key;
}

function realGhlFieldId(row, activeFormKey) {
  const candidates = [
    activeFormKey === 'blue_card' ? row?.blueId : '',
    activeFormKey === 'employee_card' ? row?.employeeId : '',
    activeFormKey === 'employee_onboarding' ? row?.onboardingId : '',
    row?.sourceCrmId, row?.fieldId, row?.id, row?.updateKey,
  ];
  return candidates.find((id) => {
    const v = String(id || '').trim();
    return v && v !== 'native' && v !== 'existing' && !/^contact\./.test(v) && !/^business\./.test(v);
  }) || '';
}

function applicationBasicKey(row) {
  const raw = String(row?.fieldName || row?.updateKey || row?.key || '').replace(/^contact\./, '').replace(/^business\./, '');
  const map = {
    first_name: 'firstName',
    last_name: 'lastName',
    date_of_birth: 'dateOfBirth',
    email: 'email',
    phone: 'phone',
    country: 'country',
    address1: 'address1',
    city: 'city',
    state: 'state',
    postal_code: 'postalCode',
    postalCode: 'postalCode',
    company_name: 'companyName',
  };
  return map[raw] || (['firstName', 'lastName', 'email', 'phone', 'address1', 'city', 'state', 'country', 'postalCode', 'companyName', 'website', 'dateOfBirth'].includes(raw) ? raw : '');
}

function normalizedAnswer(value) {
  return String(value || '').trim().toLowerCase()
    .normalize('NFD').replace(/[\u0300-\u036f]/g, '');
}

function visibleApplicationSection(section, getAnswer) {
  const id = String(section?.id || '').toLowerCase();
  if (id.includes('spouse')) {
    const marital = normalizedAnswer(getAnswer('maritalStatus') || getAnswer('contact.marital_status'));
    return /married|evli|zenaty|vdana|ženat|vdan/.test(marital);
  }
  if (id.includes('children')) {
    const count = Number.parseInt(getAnswer('numChildren') || getAnswer('contact.how_many_children_do_you_have') || '0', 10);
    return count > 0 || section.rows.some((row) => /how_many_children|numchildren|has_children|child_tax|dependents/i.test(`${row.key} ${row.formKey}`));
  }
  if (id.includes('siblings')) {
    const count = Number.parseInt(getAnswer('numSiblings') || getAnswer('contact.how_many_siblings_do_you_have') || '0', 10);
    return count > 0;
  }
  return true;
}

function visibleApplicationRows(section, getAnswer) {
  const childCount = Number.parseInt(getAnswer('numChildren') || getAnswer('contact.how_many_children_do_you_have') || '0', 10);
  const siblingCount = Number.parseInt(getAnswer('numSiblings') || getAnswer('contact.how_many_siblings_do_you_have') || '0', 10);
  return section.rows.filter((row) => {
    const text = `${row.key || ''} ${row.fieldName || ''} ${row.formKey || ''}`.toLowerCase();
    const childMatch = text.match(/child(?:ren)?[_\s-]*(\d)|empcchild(\d)/);
    if (childMatch) return Number(childMatch[1] || childMatch[2]) <= Math.max(0, childCount);
    const siblingMatch = text.match(/sibling[_\s-]*(\d)|empcsibling(\d)/);
    if (siblingMatch) return Number(siblingMatch[1] || siblingMatch[2]) <= Math.max(0, siblingCount);
    return true;
  });
}

function rowLookupValue(rows, edits, keys) {
  const wanted = keys.map((key) => String(key || '').toLowerCase());
  const row = rows.find((item) => wanted.some((key) => [item.formKey, item.key, item.fieldName, item.updateKey]
    .map((v) => String(v || '').toLowerCase()).includes(key)));
  if (!row) return '';
  const editKey = [row.key, row.updateKey, row.fieldName, row.formKey].find((key) => Object.prototype.hasOwnProperty.call(edits, key));
  return editKey ? edits[editKey] : (row.value || row.v || '');
}

function familyMemberForSection(section) {
  const id = String(section?.id || '').toLowerCase();
  if (id.includes('spouse_maritalstatus_married_ise')) return { key: 'spouse', type: 'spouse' };
  if (/:father$/.test(id)) return { key: 'father', type: 'father' };
  if (/:mother$/.test(id)) return { key: 'mother', type: 'mother' };
  const child = id.match(/:child([1-4])$/);
  if (child) return { key: `child${child[1]}`, type: 'child', index: Number(child[1]) };
  const sibling = id.match(/:sibling([1-4])$/);
  if (sibling) return { key: `sibling${sibling[1]}`, type: 'sibling', index: Number(sibling[1]) };
  return null;
}

function isFamilyAddressRow(row) {
  const key = [row?.formKey, row?.fieldName]
    .filter(Boolean)
    .join(' ')
    .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
    .toLowerCase();
  if (/nationality|citizenship|birth_country|country_of_birth/.test(key)) return false;
  return /res|address|country|municipality|district|street|building|postal|zip/.test(key);
}

function partitionFamilyRows(rows) {
  return rows.reduce((groups, row) => {
    groups[isFamilyAddressRow(row) ? 1 : 0].push(row);
    return groups;
  }, [[], []]);
}

function familyResidenceFormKeys(member) {
  if (!member) return [];
  if (member.type === 'child' || member.type === 'sibling') return [`${member.key}ResAddress`];
  const prefix = member.type === 'spouse' ? 'spouse' : member.type;
  return [
    `${prefix}ResCountry`, `${prefix}ResMunicipality`, `${prefix}ResDistrict`,
    `${prefix}ResStreet`, `${prefix}ResNumber`, `${prefix}ResPostCode`,
  ];
}

function applicationRowAnswerKey(row) {
  return row?.updateKey || row?.fieldName || row?.key || row?.formKey || '';
}

function currentResidenceParts(rows, edits) {
  return {
    country: rowLookupValue(rows, edits, ['resCountry', 'contact.country_residence_country_list']),
    municipality: rowLookupValue(rows, edits, ['resMunicipality', 'contact.municipality_in_residence']),
    district: rowLookupValue(rows, edits, ['resDistrict', 'contact.district']),
    street: rowLookupValue(rows, edits, ['resStreetNumber', 'contact.street_number']),
    number: rowLookupValue(rows, edits, ['resBuildingNumber', 'contact.building_no']),
    postCode: rowLookupValue(rows, edits, ['resPostalCode', 'contact.zip_code']),
  };
}

function combinedResidenceAddress(parts) {
  return [parts.street, parts.number, parts.district, parts.municipality, parts.postCode, parts.country]
    .map((value) => String(value || '').trim()).filter(Boolean).join(', ');
}

function parentResidenceParts(rows, edits, parent) {
  const prefix = parent === 'mother' ? 'mother' : 'father';
  return {
    country: rowLookupValue(rows, edits, [`${prefix}ResCountry`]),
    municipality: rowLookupValue(rows, edits, [`${prefix}ResMunicipality`]),
    district: rowLookupValue(rows, edits, [`${prefix}ResDistrict`]),
    street: rowLookupValue(rows, edits, [`${prefix}ResStreet`]),
    number: rowLookupValue(rows, edits, [`${prefix}ResNumber`]),
    postCode: rowLookupValue(rows, edits, [`${prefix}ResPostCode`]),
  };
}

function residencePartsHaveValue(parts) {
  return Object.values(parts).some((value) => String(value || '').trim());
}

function residencePatchFromParts(rows, member, parts) {
  const targetValues = member?.type === 'child' || member?.type === 'sibling'
    ? [combinedResidenceAddress(parts)]
    : [parts.country, parts.municipality, parts.district, parts.street, parts.number, parts.postCode];
  const patch = {};
  familyResidenceFormKeys(member).forEach((formKey, index) => {
    const row = rows.find((item) => item.formKey === formKey);
    const answerKey = applicationRowAnswerKey(row);
    if (answerKey) patch[answerKey] = targetValues[index] || '';
  });
  return patch;
}

function familyResidencePatch(rows, edits, member) {
  return residencePatchFromParts(rows, member, currentResidenceParts(rows, edits));
}

function parentResidencePatch(rows, edits, member) {
  const fatherParts = parentResidenceParts(rows, edits, 'father');
  const parts = residencePartsHaveValue(fatherParts)
    ? fatherParts
    : parentResidenceParts(rows, edits, 'mother');
  return residencePatchFromParts(rows, member, parts);
}

function residencePatchMatches(rows, edits, patch) {
  const entries = Object.entries(patch);
  if (!entries.length || !entries.some(([, value]) => String(value || '').trim())) return false;
  return entries.every(([answerKey, sourceValue]) => {
    const row = rows.find((item) => applicationRowAnswerKey(item) === answerKey);
    if (!row) return false;
    const targetValue = rowLookupValue(rows, edits, [row.formKey, row.key, row.fieldName, row.updateKey].filter(Boolean));
    return String(targetValue || '').trim() === String(sourceValue || '').trim();
  });
}

function familyResidenceMatches(rows, edits, member) {
  return residencePatchMatches(rows, edits, familyResidencePatch(rows, edits, member));
}

function siblingResidenceChoice(rows, edits, member) {
  if (familyResidenceMatches(rows, edits, member)) return 'mine';
  const matchesParent = ['father', 'mother'].some((parent) => residencePatchMatches(
    rows,
    edits,
    residencePatchFromParts(rows, member, parentResidenceParts(rows, edits, parent)),
  ));
  return matchesParent ? 'parents' : 'different';
}

function yesNoState(value) {
  const answer = normalizedAnswer(value);
  if (/^(yes|evet|ano|true|1)$/.test(answer)) return 'yes';
  if (/^(no|hayir|hayır|ne|false|0)$/.test(answer)) return 'no';
  return '';
}

function deliveryAddressPatch(rows, edits, source) {
  const sources = source === 'czechia'
    ? {
      country: ['czCountry', 'contact.country_in_czechia_country_list'],
      municipality: ['czMunicipality', 'contact.municipality_in_czechia'],
      district: ['czDistrict', 'contact.district_in_czechia'],
      street: ['czStreetNumber', 'contact.street_number_in_czechia'],
      building: ['czBuildingNumber', 'contact.building_number_in_czechia'],
      postCode: ['czPostalCode', 'contact.postalzip_code_in_czechia'],
    }
    : {
      country: ['resCountry', 'contact.country_residence_country_list'],
      municipality: ['resMunicipality', 'contact.municipality_in_residence'],
      district: ['resDistrict', 'contact.district'],
      street: ['resStreetNumber', 'contact.street_number'],
      building: ['resBuildingNumber', 'contact.building_no'],
      postCode: ['resPostalCode', 'contact.zip_code'],
    };
  const targets = {
    country: ['delCountry', 'contact.delivery_country_country_list'],
    municipality: ['delMunicipality', 'contact.delivery_municipality'],
    district: ['delDistrict', 'contact.delivery_municipal_district'],
    street: ['delStreet', 'contact.delivery_street'],
    building: ['delBuildingNumber', 'contact.delivery_building_number'],
    postCode: ['delPostCode', 'contact.delivery_post_code'],
  };
  const patch = {};
  Object.keys(targets).forEach((part) => {
    const target = rows.find((row) => targets[part].some((key) => [row.formKey, row.key, row.fieldName, row.updateKey]
      .map((candidate) => String(candidate || '').toLowerCase()).includes(String(key).toLowerCase())));
    const value = rowLookupValue(rows, edits, sources[part]);
    if (target && value) patch[target.key] = value;
  });
  return patch;
}

function addressDecisionRow(source, lang, currentValue) {
  const isResidence = source === 'residence';
  const labels = {
    tr: isResidence
      ? 'Kargo için bu ikamet adresini mi kullanıyorsunuz?'
      : 'Kargo için bu Çekya adresini mi kullanıyorsunuz?',
    en: isResidence
      ? 'Use this residence address for shipping?'
      : 'Use this Czechia address for shipping?',
    cs: isResidence
      ? 'Použít tuto adresu bydliště pro doručení?'
      : 'Použít tuto českou adresu pro doručení?',
  };
  return {
    virtual: true,
    noSave: true,
    kind: 'select',
    options: lang === 'tr' ? ['Evet', 'Hayır'] : lang === 'cs' ? ['Ano', 'Ne'] : ['Yes', 'No'],
    key: source === 'residence' ? '__deliverySameResidence' : '__deliverySameCzechia',
    l: labels[lang] || labels.en,
    v: currentValue || '',
  };
}

function serviceKeyToApplicationForm(key) {
  const v = String(key || '').toLowerCase();
  if (!v) return '';
  if (v.includes('blue_card') || v.includes('bluecard')) return 'blue_card';
  if (v.includes('employee_onboarding') || v.includes('onboarding') || v === 'eob') return 'employee_onboarding';
  if (v.includes('emp_card') || v.includes('employee_card')) return 'employee_card';
  return '';
}

function paidApplicationFormKeys(purchasedServices, contact) {
  const keys = new Set();
  (purchasedServices || []).forEach((item) => {
    const status = String(item?.status || 'active').toLowerCase();
    if (['cancelled', 'canceled', 'inactive', 'refunded'].includes(status)) return;
    const form = serviceKeyToApplicationForm(item?.k || item?.key || item?.serviceKey || item?.productKey);
    if (form) keys.add(form);
  });
  const tags = [
    ...((contact && contact.tags) || []),
    ...((contact && contact.raw && contact.raw.tags) || []),
  ].map((tag) => String(tag || '').toLowerCase());
  tags.forEach((tag) => {
    if (!/(payment|paid|purchased|received|svc:)/.test(tag)) return;
    const form = serviceKeyToApplicationForm(tag);
    if (form) keys.add(form);
  });
  return INTERNAL_APPLICATION_FORMS.map((form) => form.key).filter((key) => keys.has(key));
}

async function saveApplicationFormAnswers(contact, answers, rows, activeFormKey) {
  const contactId = contact && (contact.contactId || contact.id);
  if (!contactId) throw new Error('missing-contact');
  const basic = {};
  const customs = [];
  Object.entries(answers || {}).forEach(([key, rawValue]) => {
    if (String(key).startsWith('__')) return;
    const row = (rows || []).find((item) => [item.updateKey, item.fieldName, item.key, item.formKey].some((candidate) => String(candidate || '') === String(key)));
    if (!row) return;
    const value = rawValue == null ? '' : String(rawValue);
    const gid = realGhlFieldId(row, activeFormKey);
    const basicKey = applicationBasicKey(row);
    if (basicKey && !gid) basic[basicKey] = value;
    else if (gid) customs.push({ id: gid, ghlFieldId: gid, key: row.fieldName || row.key || key, value });
  });
  if (!window.YEYE_BACKEND || !window.YEYE_BACKEND.updateContactProfile) throw new Error('write-backend-not-configured');
  await window.YEYE_BACKEND.updateContactProfile({ contactId, basic, customFields: customs });
  return {
    updates: basic,
    customFieldUpdates: customs.map((field) => ({ id: field.id, key: field.key, value: field.value })),
  };
}

function auditFormSave(contact, formKey, answers, rows, sections, sourceScreen) {
  if (!window.YEYE_AUDIT) return;
  const contactId = contact && (contact.contactId || contact.id);
  const changes = Object.entries(answers || {}).flatMap(([key, newRaw]) => {
    if (String(key).startsWith('__')) return [];
    const row = (rows || []).find((item) => [item.updateKey, item.fieldName, item.key, item.formKey]
      .some((candidate) => String(candidate || '') === String(key)));
    if (!row) return [];
    const oldValue = row.v == null ? '' : String(row.v);
    const newValue = newRaw == null ? '' : String(newRaw);
    if (oldValue === newValue) return [];
    const section = (sections || []).find((item) => (item.rows || []).some((sectionRow) => (
      sectionRow === row || (row.key != null && sectionRow.key === row.key)
    )));
    return [{
      event: 'field.changed',
      contactId,
      payload: {
        fieldKey: row.fieldName || row.updateKey || row.key || key,
        oldValue: oldValue.slice(0, 60),
        newValue: newValue.slice(0, 60),
        section: (section && (section.id || section.title)) || null,
      },
    }];
  });
  if (!changes.length) return;
  const events = [{
    event: 'form.filled',
    contactId,
    payload: { formKey: formKey || null, fieldsChanged: changes.length, sourceScreen },
  }].concat(changes);
  if (window.YEYE_AUDIT.logBatch) window.YEYE_AUDIT.logBatch(events);
  else events.forEach((item) => window.YEYE_AUDIT.log(item.event, item.contactId, item.payload));
}

function ApplicationAutofillPanel({ section, rows, edits, onApply }) {
  const { lang } = useT();
  if (!section || !/address|residence|company|calisma|çalışma|izin/i.test(`${section.id} ${section.title}`)) return null;
  const copyAddress = (from, to) => {
    const pairs = [
      [['resCountry', 'contact.country_residence_country_list'], ['delCountry', 'contact.delivery_country_country_list']],
      [['resMunicipality', 'contact.municipality_in_residence'], ['delMunicipality', 'contact.delivery_municipality']],
      [['resDistrict', 'contact.district'], ['delDistrict', 'contact.delivery_municipal_district']],
      [['resStreetNumber', 'contact.street_number'], ['delStreet', 'contact.delivery_street']],
      [['resBuildingNumber', 'contact.building_no'], ['delBuildingNumber', 'contact.delivery_building_number']],
      [['resPostalCode', 'contact.zip_code'], ['delPostCode', 'contact.delivery_post_code']],
      [['czCountry', 'contact.country_in_czechia_country_list'], ['delCountry', 'contact.delivery_country_country_list']],
      [['czMunicipality', 'contact.municipality_in_czechia'], ['delMunicipality', 'contact.delivery_municipality']],
      [['czDistrict', 'contact.district_in_czechia'], ['delDistrict', 'contact.delivery_municipal_district']],
      [['czStreetNumber', 'contact.street_number_in_czechia'], ['delStreet', 'contact.delivery_street']],
      [['czBuildingNumber', 'contact.building_number_in_czechia'], ['delBuildingNumber', 'contact.delivery_building_number']],
      [['czPostalCode', 'contact.postalzip_code_in_czechia'], ['delPostCode', 'contact.delivery_post_code']],
    ].filter((pair) => pair[0][0].startsWith(from) && pair[1][0].startsWith(to));
    const patch = {};
    pairs.forEach(([sourceKeys, targetKeys]) => {
      const target = rows.find((row) => targetKeys.includes(row.formKey) || targetKeys.includes(row.key) || targetKeys.includes(row.fieldName));
      if (target) patch[target.key] = rowLookupValue(rows, edits, sourceKeys);
    });
    onApply(patch);
  };
  const copyWorkAddress = () => {
    const parts = [
      rowLookupValue(rows, edits, ['company_address_street', 'contact.company_address_street']),
      rowLookupValue(rows, edits, ['company_address_building_number', 'contact.company_address_building_number']),
      rowLookupValue(rows, edits, ['company_address_municipality', 'contact.company_address_municipality']),
      rowLookupValue(rows, edits, ['company_address_district', 'contact.company_address_district']),
      rowLookupValue(rows, edits, ['company_address_postal_zip_code', 'contact.company_address_postal_zip_code']),
      rowLookupValue(rows, edits, ['company_address_country', 'contact.company_address_country_country_list']),
    ].filter(Boolean).join(', ');
    const target = rows.find((row) => ['contactemployee_work_address', 'contact.contactemployee_work_address'].includes(row.formKey) || ['contactemployee_work_address', 'contact.contactemployee_work_address'].includes(row.key));
    if (target && parts) onApply({ [target.key]: parts });
  };
  const btnLabel = lang === 'tr' ? 'Aynıysa doldur' : 'Autofill if same';
  return (
    <div className="flex ac gap-8 wrap" style={{ padding: '12px 20px', borderBottom: '1px solid var(--line-2)', background: 'var(--surface-2)' }}>
      <Btn size="sm" variant="ghost" icon="copy" onClick={() => copyAddress('res', 'del')}>{lang === 'tr' ? 'Posta = İkamet' : 'Delivery = Residence'}</Btn>
      <Btn size="sm" variant="ghost" icon="copy" onClick={() => copyAddress('cz', 'del')}>{lang === 'tr' ? 'Posta = Çekya adresi' : 'Delivery = Czech address'}</Btn>
      <Btn size="sm" variant="ghost" icon="copy" onClick={copyWorkAddress}>{lang === 'tr' ? 'Çalışma = İşyeri' : 'Work = Company'}</Btn>
      <span className="muted" style={{ fontSize: 12 }}>{btnLabel}</span>
    </div>
  );
}

function ApplicationFormModal({ formKey, contact, rows, lang, t, onClose, onSaved, applyOptimisticUpdate }) {
  const [activeStep, setActiveStep] = React.useState(0);
  const [answers, setAnswers] = React.useState({});
  const [sameAddressChoices, setSameAddressChoices] = React.useState({});
  const [siblingAddressChoices, setSiblingAddressChoices] = React.useState({});
  const [saving, setSaving] = React.useState(false);
  const [error, setError] = React.useState('');
  const getValue = (row) => Object.prototype.hasOwnProperty.call(answers, row.key) ? answers[row.key] : row.v;
  const rawRows = rows || [];
  const getAnswer = (key) => rowLookupValue(rawRows, answers, [key]) || answers[key] || '';
  const sections = buildContactCardSections(contact || {}, rawRows, formKey, lang, t, getAnswer)
    .filter((section) => visibleApplicationSection(section, getAnswer))
    .map((section) => {
      const id = String(section.id || '').toLowerCase();
      const title = String(section.title || '').toLowerCase();
      let nextRows = visibleApplicationRows(section, getAnswer);
      if (/residence|ikamet|bydli/.test(`${id} ${title}`)) {
        nextRows = nextRows.concat(addressDecisionRow('residence', lang, answers.__deliverySameResidence));
      }
      if (/czechia|çekya|cekya|česku|cesku/.test(`${id} ${title}`) && yesNoState(answers.__deliverySameResidence) === 'no') {
        nextRows = nextRows.concat(addressDecisionRow('czechia', lang, answers.__deliverySameCzechia));
      }
      return { ...section, rows: nextRows };
    })
    .filter((section) => {
      const text = `${section.id || ''} ${section.title || ''}`.toLowerCase();
      if (!/delivery|shipping|kargo|doru/.test(text)) return true;
      return yesNoState(answers.__deliverySameResidence) === 'no' && yesNoState(answers.__deliverySameCzechia) === 'no';
    })
    .filter((section) => section.rows.length);
  const activeIndex = Math.min(activeStep, Math.max(sections.length - 1, 0));
  const activeSection = sections[activeIndex];
  const activeFamilyMember = familyMemberForSection(activeSection);
  const activeSiblingAddressChoice = activeFamilyMember?.type === 'sibling'
    ? (Object.prototype.hasOwnProperty.call(siblingAddressChoices, activeFamilyMember.key)
      ? siblingAddressChoices[activeFamilyMember.key]
      : siblingResidenceChoice(rawRows, answers, activeFamilyMember))
    : null;
  const activeSameAddress = activeFamilyMember && activeFamilyMember.type !== 'sibling'
    ? (Object.prototype.hasOwnProperty.call(sameAddressChoices, activeFamilyMember.key)
      ? sameAddressChoices[activeFamilyMember.key]
      : familyResidenceMatches(rawRows, answers, activeFamilyMember))
    : false;
  const hideActiveResidence = activeFamilyMember?.type === 'sibling'
    ? activeSiblingAddressChoice !== 'different'
    : activeSameAddress;
  const hiddenResidenceKeys = new Set(hideActiveResidence ? familyResidenceFormKeys(activeFamilyMember) : []);
  const activeRows = activeSection
    ? activeSection.rows.filter((row) => !hiddenResidenceKeys.has(row.formKey))
    : [];
  const filledCount = rawRows.filter((row) => isFilledContactValue(getValue(row))).length;
  const progress = sections.length ? Math.round(((activeIndex + 1) / sections.length) * 100) : 0;
  const copy = {
    save: t('form.save') || 'Save',
    saving: t('c.saving') || 'Saving',
    cancel: t('c.cancel') || 'Cancel',
    back: lang === 'tr' ? 'Geri' : 'Back',
    next: lang === 'tr' ? 'İleri' : 'Next',
    step: lang === 'tr' ? 'Bölüm' : 'Section',
  };
  React.useEffect(() => {
    if (activeStep >= sections.length) setActiveStep(Math.max(sections.length - 1, 0));
  }, [activeStep, sections.length]);
  React.useEffect(() => {
    if (activeFamilyMember?.type !== 'sibling') return;
    setSiblingAddressChoices((prev) => Object.prototype.hasOwnProperty.call(prev, activeFamilyMember.key)
      ? prev
      : { ...prev, [activeFamilyMember.key]: siblingResidenceChoice(rawRows, answers, activeFamilyMember) });
  }, [activeFamilyMember?.key]);
  const doSave = async () => {
    setSaving(true);
    setError('');
    try {
      const patch = await saveApplicationFormAnswers(contact, answers, rawRows, formKey);
      if (applyOptimisticUpdate) applyOptimisticUpdate(patch);
      auditFormSave(contact, formKey, answers, rawRows, sections, 'application_form_modal');
      window.YEYE_TOAST && window.YEYE_TOAST(t('form.savedNext') || t('form.savedGhl') || 'Saved');
      if (onSaved) onSaved();
      onClose();
    } catch (err) {
      console.warn('Application form save failed', err);
      setError((err && err.message) || 'Save failed');
    } finally {
      setSaving(false);
    }
  };
  const updateAnswer = (row, value) => {
    setAnswers((prev) => {
      const base = { ...prev, [row.key]: value };
      if (row.key === '__deliverySameResidence' && yesNoState(value) === 'yes') {
        return { ...base, ...deliveryAddressPatch(rawRows, base, 'residence') };
      }
      if (row.key === '__deliverySameCzechia' && yesNoState(value) === 'yes') {
        return { ...base, ...deliveryAddressPatch(rawRows, base, 'czechia') };
      }
      return base;
    });
  };
  const updateSameAddress = (checked) => {
    if (!activeFamilyMember) return;
    setSameAddressChoices((prev) => ({ ...prev, [activeFamilyMember.key]: checked }));
    if (checked) {
      setAnswers((prev) => ({ ...prev, ...familyResidencePatch(rawRows, prev, activeFamilyMember) }));
    }
  };
  const updateSiblingAddress = (choice) => {
    if (activeFamilyMember?.type !== 'sibling') return;
    setSiblingAddressChoices((prev) => ({ ...prev, [activeFamilyMember.key]: choice }));
    if (choice === 'mine') {
      setAnswers((prev) => ({ ...prev, ...familyResidencePatch(rawRows, prev, activeFamilyMember) }));
    } else if (choice === 'parents') {
      setAnswers((prev) => ({ ...prev, ...parentResidencePatch(rawRows, prev, activeFamilyMember) }));
    }
  };
  const sameAddressLabel = activeFamilyMember?.type === 'spouse' && lang === 'tr'
    ? 'İkamet adresim eşimle aynı'
    : t('wizard.sameAddr.title');
  return (
    <Modal
      wide
      icon="clipboard-list"
      title={applicationFormLabel(formKey, lang)}
      sub={`${filledCount}/${rawRows.length} ${lang === 'tr' ? 'alan dolu' : 'fields filled'}`}
      onClose={onClose}
      footer={(
        <>
          <Btn variant="ghost" icon="x" disabled={saving} onClick={onClose}>{copy.cancel}</Btn>
          <Btn variant="ghost" icon="arrow-left" disabled={saving || activeIndex === 0} onClick={() => setActiveStep((v) => Math.max(0, v - 1))}>{copy.back}</Btn>
          {activeIndex < sections.length - 1 ? (
            <Btn variant="primary" iconR="arrow-right" disabled={saving || sections.length === 0} onClick={() => setActiveStep((v) => Math.min(sections.length - 1, v + 1))}>{copy.next}</Btn>
          ) : (
            <Btn variant="primary" icon={saving ? 'loader-circle' : 'check'} disabled={saving || Object.keys(answers).length === 0} onClick={doSave}>
              {saving ? copy.saving : copy.save}
            </Btn>
          )}
        </>
      )}
    >
      {error && <Alert tone="bad" icon="circle-alert" title={error} />}
      {formKey === 'blue_card' && activeIndex === 0 && (
        <Alert tone="info" icon="info" title={t('form.blueCardIntroTitle')}>
          {t('form.blueCardIntroBody')}
        </Alert>
      )}
      <div className="wizard-progress-block mb-14">
        <div className="wizard-progress-copy">
          <span>{copy.step} <strong>{activeIndex + 1}/{Math.max(sections.length, 1)}</strong></span>
          <span>{progress}%</span>
        </div>
        <div className="wizard-progress-track"><span style={{ width: `${progress}%` }} /></div>
      </div>
      <div className="application-step-strip mb-14" style={{ display: 'flex', gap: 8, overflowX: 'auto', paddingBottom: 4 }}>
        {sections.map((section, index) => {
          const state = index < activeIndex ? 'done' : index === activeIndex ? 'current' : 'todo';
          return (
            <button
              key={section.id}
              type="button"
              onClick={() => setActiveStep(index)}
              aria-current={index === activeIndex ? 'step' : undefined}
              style={{
                minWidth: 150,
                maxWidth: 210,
                flex: '0 0 auto',
                border: '1px solid ' + (state === 'current' ? 'var(--brand-400)' : 'var(--line-2)'),
                background: state === 'current' ? 'var(--brand-50)' : state === 'done' ? 'var(--surface-2)' : 'var(--surface)',
                color: state === 'current' ? 'var(--brand-700)' : 'var(--ink-700)',
                borderRadius: 'var(--r-sm)',
                padding: '10px 11px',
                textAlign: 'left',
                cursor: 'pointer',
              }}
            >
              <div className="flex ac gap-8">
                <span className="mono" style={{ fontSize: 11, fontWeight: 850 }}>{String(index + 1).padStart(2, '0')}</span>
                {state === 'done' && <Icon name="check" size={13} />}
              </div>
              <div style={{ marginTop: 5, fontSize: 12, fontWeight: 750, lineHeight: 1.25, whiteSpace: 'normal' }}>{section.title}</div>
            </button>
          );
        })}
      </div>
      <div className="flex col gap-14">
        {!activeSection ? (
          <Card><div className="card-bd"><div className="muted" style={{ padding: 18, textAlign: 'center' }}>—</div></div></Card>
        ) : (() => {
          const sectionFilled = activeRows.filter((row) => isFilledContactValue(getValue(row))).length;
          const [personalRows, addressRows] = activeFamilyMember ? partitionFamilyRows(activeRows) : [activeRows, []];
          const addressChoice = activeFamilyMember && (
            <div style={{ display: 'flex', flexDirection: 'column', gap: 9, padding: '11px 10px', borderBottom: '1px solid var(--line-2)' }}>
              {activeFamilyMember.type === 'sibling' ? (
                <fieldset style={{ display: 'flex', flexDirection: 'column', gap: 8, margin: 0, padding: 0, border: 0 }}>
                  <legend className="muted" style={{ marginBottom: 2, padding: 0, fontSize: 11.5, fontWeight: 700 }}>
                    {t('wizard.sibling.addr.label')}
                  </legend>
                  {[
                    ['mine', 'wizard.sibling.addr.mine'],
                    ['parents', 'wizard.sibling.addr.parents'],
                    ['different', 'wizard.sibling.addr.diff'],
                  ].map(([value, labelKey]) => (
                    <label key={value} className="flex ac gap-8" style={{ fontSize: 13, fontWeight: 650, cursor: 'pointer' }}>
                      <input
                        type="radio"
                        name={`sibling-address-${activeFamilyMember.key}`}
                        value={value}
                        checked={activeSiblingAddressChoice === value}
                        onChange={() => updateSiblingAddress(value)}
                      />
                      <span>{t(labelKey)}</span>
                    </label>
                  ))}
                </fieldset>
              ) : (
                <label className="flex ac gap-8" style={{ fontSize: 13, fontWeight: 650, cursor: 'pointer' }}>
                  <input type="checkbox" checked={activeSameAddress} onChange={(event) => updateSameAddress(event.target.checked)} />
                  <span>{sameAddressLabel}</span>
                </label>
              )}
            </div>
          );
          return (
            <Card key={activeSection.id} style={{ overflow: 'hidden' }}>
              <div style={{ padding: '14px 20px', borderBottom: '1px solid var(--line-2)', fontWeight: 750, fontSize: 13, color: 'var(--ink-900)', letterSpacing: '.04em' }}>
                {upperUiLabel(activeSection.title, lang)}
                <span className="muted mono" style={{ fontSize: 11.5, fontWeight: 600, marginLeft: 8 }}>{sectionFilled}/{activeRows.length}</span>
              </div>
              <div style={{ padding: '6px 20px 12px' }}>
                {personalRows.map((row) => (
                  <ContactRow
                    key={`${activeSection.id}-${row.key}-${row.l}`}
                    row={row}
                    editing
                    editValue={answers[row.key]}
                    onEditChange={(key, value) => updateAnswer(row, value)}
                  />
                ))}
                {addressChoice}
                {addressRows.map((row) => (
                  <ContactRow
                    key={`${activeSection.id}-${row.key}-${row.l}`}
                    row={row}
                    editing
                    editValue={answers[row.key]}
                    onEditChange={(key, value) => updateAnswer(row, value)}
                  />
                ))}
              </div>
            </Card>
          );
        })()}
      </div>
    </Modal>
  );
}

function DataAccordionCard({ title, sub, count, children }) {
  const [open, setOpen] = useState(false);
  return (
    <Card className="data-accordion">
      <button type="button" className="data-acc-toggle" onClick={() => setOpen((v) => !v)} aria-expanded={open}>
        <Icon name={open ? 'chevron-down' : 'chevron-right'} size={18} className="dim" />
        <div className="data-acc-title">
          <strong>{title}</strong>
          {sub && <span>{sub}</span>}
        </div>
        {count && <span className="data-acc-count">{count}</span>}
      </button>
      {open && <div className="data-acc-body">{children}</div>}
    </Card>
  );
}

function FormSubmissionPage({ ct, contact, fieldMappings, onRefresh, onOptimisticUpdate, syncState, purchasedServices, openModal, onCompleteProfile }) {
  const { t, lang } = useT();
  const authEmail = (window.YEYE_AUTH && window.YEYE_AUTH.getState && (window.YEYE_AUTH.getState().user || {}).email) || '';
  const isAdmin = /@yeyeagency\.com$/i.test(authEmail);
  const [activeSection, setActiveSection] = useState('all');
  const [activeForm, setActiveForm] = useState('');
  const [onlyMissing, setOnlyMissing] = useState(false);
  const [isEditing, setIsEditing] = useState(false);
  const [edits, setEdits] = useState({});
  const [saving, setSaving] = useState(false);
  const [profileWizardOpen, setProfileWizardOpen] = useState(false);
  const [profileWizardSection, setProfileWizardSection] = useState(null);
  const [formModalKey, setFormModalKey] = useState('');
  const serviceKeys = new Set([
    ct && ct.key,
    ...((purchasedServices || []).map((item) => item && (item.k || item.key || item.serviceKey || item.productKey)).filter(Boolean)),
    ...((contact && contact.tags) || []),
  ].map((key) => String(key || '').toLowerCase()));
  const paidFormKeys = paidApplicationFormKeys(purchasedServices, contact);
  const hasPaidServiceAccess = paidFormKeys.length > 0 || (purchasedServices || []).some((item) => {
    const status = String(item?.status || 'active').toLowerCase();
    return !['cancelled', 'canceled', 'inactive', 'refunded'].includes(status);
  });
  const formKey = paidFormKeys[0] || '';
  const activeFormKey = activeForm || formKey;
  const rows = activeFormKey && window.YEYE_FIELD_MAPPING
    ? window.YEYE_FIELD_MAPPING.forForm(fieldMappings || [], activeFormKey, contact || {})
    : [];
  const filled = rows.filter((row) => row.value);
  const missing = rows.filter((row) => !row.value);
  const profileMissing = window.YEYE_PROFILE && window.YEYE_PROFILE.missing
    ? window.YEYE_PROFILE.missing(contact || {}, isEditing ? edits : {})
    : [];
  const displayedValue = (row) => (
    Object.prototype.hasOwnProperty.call(edits, row.key) ? edits[row.key] : row.v
  );
  const getAnswer = (key) => rowLookupValue(rows, edits, [key]) || edits[key] || '';
  const allSections = buildContactCardSections(contact || {}, rows, activeFormKey, lang, t, getAnswer);
  const visibleSections = allSections
    .filter((section) => visibleApplicationSection(section, getAnswer))
    .map((section) => ({ ...section, rows: visibleApplicationRows(section, getAnswer) }))
    .filter((section) => activeSection === 'all' || section.filterId === activeSection || section.id === activeSection)
    .map((section) => ({ ...section, rows: onlyMissing ? section.rows.filter((row) => !isFilledContactValue(displayedValue(row))) : section.rows }))
    .filter((section) => section.rows.length);
  const availableFormKeys = paidFormKeys.length ? paidFormKeys : [];
  const formChips = availableFormKeys.map((key) => ({ key, label: applicationFormLabel(key, lang) }));
  const contactName = contactDisplayName(contact || {});
  const contactEmail = contact?.email || contactFieldValue(contact, ['email', 'contact.email']);
  const contactPhone = contactFieldValue(contact, ['phone', 'contact.phone']);
  const fc = {
    en: { customers: 'Customers', active: 'Active', missingFields: 'Missing Fields', edit: 'Edit', linkedCompany: 'Linked Company · GHL business', companyDetail: 'Company Detail', syncWarning: 'GHL sync warning', all: 'All', contact: 'Contact', personal: 'Personal Information', company: 'Employer Information', addresses: 'Address Information', passport: 'Passport / Travel Document', lastEmployment: 'Last Employment', family: 'Family Information', approvals: 'Approvals', others: 'Others', syncing: 'Syncing', lastSync: 'Last sync', onlyMissing: 'Only Missing', submittedForms: 'Submitted Forms' },
    tr: { customers: 'Müşteriler', active: 'Aktif', missingFields: 'Eksik Alanlar', edit: 'Düzenle', linkedCompany: 'Bağlı Firma · GHL business', companyDetail: 'Firma Detayı', syncWarning: 'GHL sync uyarısı', all: 'Tümü', contact: 'İletişim', personal: 'Kişisel Bilgiler', company: 'İşveren Bilgileri', addresses: 'Adres Bilgileri', passport: 'Pasaport / Seyahat Belgesi', lastEmployment: 'Son İstihdam', family: 'Aile Bilgileri', approvals: 'Onaylar', others: 'Diğerleri', syncing: 'Senkronize', lastSync: 'Son sync', onlyMissing: 'Sadece Eksikler', submittedForms: 'Submit Edilen Formlar' },
    cs: { customers: 'Zákazníci', active: 'Aktivní', missingFields: 'Chybějící pole', edit: 'Upravit', linkedCompany: 'Propojená firma · GHL business', companyDetail: 'Detail firmy', syncWarning: 'Upozornění synchronizace GHL', all: 'Vše', contact: 'Kontakt', personal: 'Osobní údaje', company: 'Údaje zaměstnavatele', addresses: 'Adresní údaje', passport: 'Pas / cestovní doklad', lastEmployment: 'Poslední zaměstnání', family: 'Rodinné údaje', approvals: 'Souhlasy', others: 'Ostatní', syncing: 'Synchronizuje se', lastSync: 'Poslední sync', onlyMissing: 'Pouze chybějící', submittedForms: 'Odeslané formuláře' },
  }[lang] || {};
  const companyName = contactFieldValue(contact, [
    'business.name', 'business.companyName', 'companyName', 'company_name', 'contact.company_name', 'contact.employer_name'
  ]);
  const companyMeta = [
    contactFieldValue(contact, ['business.city', 'company_city', 'contact.company_city']),
    contactFieldValue(contact, ['business.country', 'company_country', 'contact.company_country']),
    contactFieldValue(contact, ['business.status', 'company_status'])
  ].filter(Boolean).join(' · ');
  const primaryFilters = [
    { id: 'all', label: fc.all },
    { id: 'contact_kisisel_iletisim', label: fc.contact },
    { id: 'personal_information', label: fc.personal },
    { id: 'company', label: fc.company },
    { id: 'addresses', label: fc.addresses },
    { id: 'passport_travel_document', label: fc.passport },
  ].filter((filter) => filter.id === 'all' || allSections.some((section) => section.filterId === filter.id || section.id === filter.id));
  const otherFilters = [
    { id: 'last_employment', label: fc.lastEmployment },
    { id: 'family_information', label: fc.family },
    { id: 'approvals', label: fc.approvals },
  ].filter((filter) => allSections.some((section) => section.filterId === filter.id || section.id === filter.id));
  const otherActive = otherFilters.some((filter) => filter.id === activeSection);
  const applyOptimisticUpdate = (patch) => {
    const contactId = contact && (contact.contactId || contact.id);
    if (!contactId || !patch) return;
    if (onOptimisticUpdate) {
      onOptimisticUpdate(contactId, patch);
      return;
    }
    if (window.YEYE_CONTACT_STATE && window.YEYE_CONTACT_STATE.applyOptimisticUpdate) {
      window.YEYE_CONTACT_STATE.applyOptimisticUpdate(contactId, patch);
    }
  };

  useEffect(() => {
    if (!onRefresh) return undefined;
    let cancelled = false;
    onRefresh();
    const timer = setInterval(() => { if (!cancelled) onRefresh(); }, 15000);
    return () => { cancelled = true; clearInterval(timer); };
  }, [formKey]);

  useEffect(() => {
    if (formKey) setActiveForm(formKey);
  }, [formKey]);

  return (
    <>
      <Card className="mb-18" style={{ overflow: 'hidden' }}>
        <div className="card-bd">
          <div className="flex ac wrap gap-16">
            <Avatar size="lg" tone={{ bg: 'var(--brand-400)', fg: '#fff' }}>{contactInitials(contact || {})}</Avatar>
            <div className="grow" style={{ minWidth: 260 }}>
              <div className="flex ac gap-8 wrap">
                <div className="h2">{contactName}</div>
              </div>
              <div className="muted mono" style={{ fontSize: 12.5, marginTop: 5 }}>{[contactEmail, contactPhone].filter(Boolean).join(' · ') || '—'}</div>
            </div>
            <div className="flex ac gap-8 wrap" style={{ justifyContent: 'flex-end' }}>
              {hasPaidServiceAccess && <Btn variant={onlyMissing ? 'primary' : 'ghost'} icon="circle-alert" onClick={() => setOnlyMissing((v) => !v)}>{fc.missingFields}</Btn>}
              {hasPaidServiceAccess && <Btn variant="ghost" icon="upload" onClick={() => openModal && openModal('upload', {
                contactId: contact && (contact.contactId || contact.id),
                folderK: 'f_identity',
                subName: folderTkToSubName('f_identity'),
                onUploaded: async () => {
                  if (onRefresh) await Promise.resolve(onRefresh());
                  if (window.YEYE_TOAST) window.YEYE_TOAST(t('doc.uploaded'));
                },
              })}>{t('auth.passportUpload')}</Btn>}
              {hasPaidServiceAccess && !isEditing && <Btn variant="ghost" icon="clipboard-list" onClick={() => {
                if (activeFormKey) {
                  setFormModalKey(activeFormKey);
                  return;
                }
                setProfileWizardSection(null);
                setProfileWizardOpen(true);
              }}>{t('wizard.openFullForm')}</Btn>}
              {isEditing ? (
                <>
                  <Btn variant="ghost" icon="x" disabled={saving} onClick={() => { setEdits({}); setIsEditing(false); }}>{t('c.cancel')}</Btn>
                  <Btn variant="primary" icon={saving ? 'loader-circle' : 'check'} disabled={saving || Object.keys(edits).length === 0} onClick={async () => {
                    const contactId = contact && (contact.contactId || contact.id);
                    const emailAddr = (contact && contact.email) || '';
                    if (!contactId || !emailAddr) { showToast && showToast('Contact not connected'); return; }
                    const missingAfterSave = window.YEYE_PROFILE && window.YEYE_PROFILE.missing
                      ? window.YEYE_PROFILE.missing(contact || {}, edits)
                      : [];
                    setSaving(true);
                    const allowed = new Set(['firstName', 'lastName', 'email', 'phone', 'address1', 'city', 'state', 'country', 'postalCode', 'companyName', 'website', 'dateOfBirth']);
                    const basic = {};
                    const customs = [];
                    Object.entries(edits).forEach(([k, v]) => {
                      const meta = rows.find((r) => (r.updateKey === k || r.fieldName === k || r.key === k));
                      const requiredMeta = (window.YEYE_REQUIRED_FIELDS || []).find((entry) => (
                        entry.key === k ||
                        String(entry.key).replace(/^contact\./, '') === String(k).replace(/^contact\./, '')
                      ));
                      const gid = (meta && realGhlFieldId(meta, activeFormKey)) ||
                        (requiredMeta && requiredMeta.ghlFieldId);
                      const shortKey = String(k).replace(/^contact\./, '').replace(/^business\./, '');
                      const basicKey = meta ? applicationBasicKey(meta) : (allowed.has(shortKey) ? shortKey : '');
                      if (basicKey && !gid) basic[basicKey] = v;
                      else if (gid) customs.push({ id: gid, ghlFieldId: gid, key: k, value: v });
                    });
                    try {
                      if (!window.YEYE_BACKEND || !window.YEYE_BACKEND.updateContactProfile) throw new Error('write-backend-not-configured');
                      await window.YEYE_BACKEND.updateContactProfile({ contactId, basic, customFields: customs });
                      applyOptimisticUpdate({
                        updates: basic,
                        customFieldUpdates: customs.map((field) => ({
                          id: field.id,
                          key: field.key,
                          value: field.value,
                        })),
                      });
                      auditFormSave(contact, activeFormKey, edits, rows, allSections, 'form_submission');
                      setEdits({});
                      setIsEditing(false);
                      if (onRefresh) onRefresh();
                      window.YEYE_TOAST && window.YEYE_TOAST(t('form.savedGhl') || 'Saved');
                      if (hasPaidServiceAccess && missingAfterSave.length) {
                        window.YEYE_TOAST && window.YEYE_TOAST(
                          t('profileFields.missingBanner').replace('{count}', missingAfterSave.length)
                        );
                      }
                    } catch (err) {
                      console.warn('Save failed', err);
                      window.YEYE_TOAST && window.YEYE_TOAST((err && err.message) || 'Save failed');
                    } finally {
                      setSaving(false);
                    }
                  }}>{saving ? t('c.saving') : (t('form.save') || 'Save')}</Btn>
                </>
              ) : (
                <Btn variant="ghost" icon="pencil" onClick={() => setIsEditing(true)}>{fc.edit}</Btn>
              )}
            </div>
          </div>
        </div>
      </Card>
      {!hasPaidServiceAccess && (
        <div className="flex col gap-16">
          <DataAccordionCard
            title={lang === 'tr' ? 'Kayıt Bilgileri' : (lang === 'cs' ? 'Registrační údaje' : 'Registration Details')}
            sub={lang === 'tr' ? 'Servis satın alınana kadar sadece temel iletişim bilgileri tutulur.' : 'Only basic contact details are kept until a service is purchased.'}
            count="4"
          >
            {[
              { key: 'firstName', l: t('wizard.field.firstName'), v: contactFieldValue(contact, ['firstName', 'contact.firstName']) },
              { key: 'lastName', l: t('wizard.field.lastName'), v: contactFieldValue(contact, ['lastName', 'contact.lastName']) },
              { key: 'email', l: t('wizard.field.email'), v: contactEmail },
              { key: 'phone', l: t('wizard.field.phone'), v: contactPhone },
            ].map((row) => (
              <ContactRow
                key={row.key}
                row={row}
                editing={isEditing}
                editValue={edits[row.key]}
                onEditChange={(k, v) => setEdits((prev) => ({ ...prev, [k]: v }))}
              />
            ))}
          </DataAccordionCard>
        </div>
      )}
      {hasPaidServiceAccess && profileMissing.length > 0 && (
        <div className="mb-18">
          <ProfileMissingFieldsBanner contact={contact} edits={isEditing ? edits : {}} />
        </div>
      )}
      {hasPaidServiceAccess && <DocGenerationCard contact={contact} purchasedServices={purchasedServices} onGenerated={onRefresh || (() => {})} onCompleteProfile={onCompleteProfile} />}
      {hasPaidServiceAccess && companyName && (
        <Card className="mb-18" style={{ borderColor: 'var(--accent-300)' }}>
          <div className="card-bd">
            <div className="flex ac gap-14">
              <Avatar tone={{ bg: 'var(--accent-100)', fg: 'var(--accent-700)' }}>{String(companyName).slice(0, 2).toUpperCase()}</Avatar>
              <div className="grow">
                <div className="eyebrow">{fc.linkedCompany}</div>
                <div className="strong" style={{ fontSize: 15 }}>{companyName}</div>
                {companyMeta && <div className="muted mono" style={{ fontSize: 11.5 }}>{companyMeta}</div>}
              </div>
            </div>
          </div>
        </Card>
      )}
      {hasPaidServiceAccess && isAdmin && syncState && syncState.error && (
        <Alert tone="warn" icon="triangle-alert" title={fc.syncWarning}>{syncState.error}</Alert>
      )}
      {hasPaidServiceAccess && <Card className="mb-18">
        <div className="card-bd">
          <div className="flex jb ac wrap gap-12">
            <div>
              <div className="eyebrow mb-6">{lang === 'tr' ? 'INTERNAL FORM' : 'INTERNAL FORM'}</div>
              <div className="strong" style={{ fontSize: 15 }}>
                {availableFormKeys.length
                  ? (lang === 'tr' ? 'Satın alınan ürün formu' : 'Paid product form')
                  : (lang === 'tr' ? 'Aktif form yok' : 'No active form')}
              </div>
              <div className="muted" style={{ fontSize: 12.5, marginTop: 4 }}>
                {availableFormKeys.length
                  ? (lang === 'tr' ? 'Sadece ödemesi alınan ürünün formu görünür.' : 'Only paid product forms are shown.')
                  : (lang === 'tr' ? 'Formun görünmesi için GHL ödeme tag’i veya satın alma kaydı gerekiyor.' : 'A payment tag or purchase record is required to show a form.')}
              </div>
            </div>
            <div className="flex ac gap-8 wrap" style={{ justifyContent: 'flex-end' }}>
              {formChips.map((chip) => (
                <Btn
                  key={chip.key}
                  variant={activeFormKey === chip.key ? 'primary' : 'ghost'}
                  icon="clipboard-list"
                  onClick={() => { setActiveForm(chip.key); setActiveSection('all'); setFormModalKey(chip.key); }}
                >
                  {chip.label}
                </Btn>
              ))}
            </div>
          </div>
        </div>
      </Card>}
      {hasPaidServiceAccess && (rows.length === 0 ? (
        <div className="flex col gap-16">
          {(() => {
            const reqSections = window.YEYE_REQUIRED_SECTIONS || {};
            const reqFields = window.YEYE_REQUIRED_FIELDS || [];
            const visibleReqFields = onlyMissing && window.YEYE_PROFILE && window.YEYE_PROFILE.missing
              ? window.YEYE_PROFILE.missing(contact || {}, isEditing ? edits : {})
              : reqFields;
            const grouped = {};
            visibleReqFields.forEach((entry) => {
              (grouped[entry.section] = grouped[entry.section] || []).push(entry);
            });
            return Object.keys(grouped).map((sectionKey) => {
              const secMeta = reqSections[sectionKey] || {};
              const secTitle = secMeta[lang] || secMeta.en || sectionKey;
              const secRows = grouped[sectionKey].map((entry) => {
                const raw = window.YEYE_PROFILE && window.YEYE_PROFILE.getValue
                  ? window.YEYE_PROFILE.getValue(contact || {}, entry)
                  : null;
                const labelKey = 'wizard.field.' + entry.key;
                return {
                  l: t(labelKey),
                  v: formatFieldValue(raw),
                  key: entry.key,
                };
              });
              const filledCount = secRows.filter((row) => isFilledContactValue(row.v)).length;
              return (
                <DataAccordionCard
                  key={sectionKey}
                  title={upperUiLabel(secTitle, lang)}
                  count={`${filledCount}/${secRows.length}`}
                >
                    {secRows.map((row) => (
                      <ContactRow
                        key={`${sectionKey}-${row.key}-${row.l}`}
                        row={row}
                        editing={isEditing}
                        editValue={edits[row.key]}
                        onEditChange={(k, v) => setEdits((prev) => ({ ...prev, [k]: v }))}
                      />
                    ))}
                </DataAccordionCard>
              );
            });
          })()}
        </div>
      ) : (
        <>
          <div className="flex ac gap-7 wrap mb-18">
            {primaryFilters.map((filter) => (
              <button key={filter.id} className={'btn btn-sm ' + (activeSection === filter.id ? 'btn-primary' : 'btn-ghost')} onClick={() => setActiveSection(filter.id)}>{filter.label}</button>
            ))}
            {otherFilters.length > 0 && (
              <select value={otherActive ? activeSection : ''} onChange={(e) => setActiveSection(e.target.value || 'all')} className={'btn btn-sm data-filter-select ' + (otherActive ? 'btn-primary' : 'btn-ghost')} style={{ height: 34 }}>
                <option value="">{fc.others}</option>
                {otherFilters.map((filter) => <option key={filter.id} value={filter.id}>{filter.label}</option>)}
              </select>
            )}
            <div className="grow" />
          </div>

          <div className="flex col gap-16">
            {visibleSections.length === 0 ? (
              <Card><div className="card-bd"><div className="muted" style={{ padding: 18, textAlign: 'center' }}>—</div></div></Card>
            ) : visibleSections.map((section) => {
              const sectionFilled = section.rows.filter((row) => isFilledContactValue(row.v)).length;
              return (
                <DataAccordionCard
                  key={section.id}
                  title={upperUiLabel(section.title, lang)}
                  count={`${sectionFilled}/${section.rows.length}`}
                >
                    {section.rows.map((row) => (
                      <ContactRow
                        key={`${section.id}-${row.key}-${row.l}`}
                        row={row}
                        editing={isEditing}
                        editValue={edits[row.key]}
                        onEditChange={(k, v) => setEdits((prev) => ({ ...prev, [k]: v }))}
                      />
                    ))}
                </DataAccordionCard>
              );
            })}
          </div>
        </>
      ))}
      {hasPaidServiceAccess && <div className="mb-18" style={{ marginTop: 18 }}>
        <DataAccordionCard title={t('myData.docs.title')} sub={t('myData.docs.sub')} count="8">
          <div className="grid" style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill,minmax(230px,1fr))', gap: 10 }}>
            {[
              { key: 'passport',        folderK: 'f_identity',        subK: 'sf_passport',            icon: 'book-user' },
              { key: 'criminal',        folderK: 'f_identity',        subK: 'sf_criminal_record',     icon: 'shield-alert' },
              { key: 'biometric',       folderK: 'f_identity',        subK: 'sf_passport',            icon: 'camera' },
              { key: 'diploma',         folderK: 'f_education',       subK: 'sf_diploma',             icon: 'graduation-cap' },
              { key: 'employment',      folderK: 'f_relocation',      subK: 'sf_employment_contract', icon: 'file-signature' },
              { key: 'accommodation',   folderK: 'f_accommodation_re',subK: 'sf_lease',               icon: 'home' },
              { key: 'payslip',         folderK: 'f_relocation',      subK: 'sf_payslip',             icon: 'receipt' },
              { key: 'applicationFee',  folderK: 'f_relocation',      subK: 'sf_blue_employee',       icon: 'wallet' },
            ].map((d) => (
              <button
                key={d.key}
                type="button"
                onClick={() => openModal && openModal('upload', {
                  contactId: contact && (contact.contactId || contact.id),
                  folderK: d.folderK,
                  subName: folderTkToSubName(d.folderK),
                  onUploaded: async () => {
                    if (onRefresh) await Promise.resolve(onRefresh());
                    if (window.YEYE_TOAST) window.YEYE_TOAST(t('doc.uploaded'));
                  },
                })}
                style={{
                  display: 'flex', alignItems: 'center', gap: 10, textAlign: 'left',
                  padding: '11px 12px', borderRadius: 12, border: '1px solid var(--line)',
                  background: 'var(--surface)', color: 'var(--ink-800)', cursor: 'pointer',
                  fontFamily: 'inherit', fontSize: 13, fontWeight: 700, minWidth: 0,
                }}
              >
                <span style={{ width: 34, height: 34, borderRadius: 10, background: 'var(--brand-50)', color: 'var(--brand-600)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
                  <Icon name={d.icon} size={16} />
                </span>
                <span style={{ flex: 1, minWidth: 0, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                  {t('myData.doc.' + d.key)}
                </span>
                <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, color: 'var(--accent-600)', fontSize: 12, fontWeight: 800 }}>
                  <Icon name="upload" size={13} />{t('myData.doc.upload')}
                </span>
              </button>
            ))}
          </div>
        </DataAccordionCard>
      </div>}
      {hasPaidServiceAccess && profileWizardOpen && (
        <ProfileWizard
          contact={contact}
          onClose={() => setProfileWizardOpen(false)}
          initialSection={profileWizardSection}
          onSaved={() => {
            setProfileWizardOpen(false);
            if (onRefresh) onRefresh();
          }}
        />
      )}
      {hasPaidServiceAccess && formModalKey && (
        <ApplicationFormModal
          formKey={formModalKey}
          contact={contact}
          rows={window.YEYE_FIELD_MAPPING ? window.YEYE_FIELD_MAPPING.forForm(fieldMappings || [], formModalKey, contact || {}) : []}
          lang={lang}
          t={t}
          onClose={() => setFormModalKey('')}
          onSaved={() => { if (onRefresh) onRefresh(); }}
          applyOptimisticUpdate={applyOptimisticUpdate}
        />
      )}
    </>
  );
}

/* ===== APPOINTMENTS — Calendar (June 2026) ===== */
const CAL_EVENTS = [
  { d: 9, key: 'police', time: '09:30', tone: 'ok', ic: 'shield' },
  { d: 14, key: 'deadline', time: '23:59', tone: 'bad', ic: 'file-warning' },
  { d: 19, key: 'biometrics', time: '11:00', tone: 'info', ic: 'fingerprint' },
  { d: 27, key: 'consult', time: '10:00', tone: 'brand', ic: 'video' },
];
const TODAY = 7, MONTH_IDX = 5, FIRST_DOW = 0, DAYS_IN = 30;
function evTone(tone) {
  const m = { ok: ['var(--ok-bg)', 'var(--ok)'], info: ['var(--info-bg)', 'var(--info)'], bad: ['var(--bad-bg)', 'var(--bad)'], brand: ['var(--brand-500)', '#fff'] };
  const [bg, fg] = m[tone] || m.ok; return { background: bg, color: fg };
}
function ApptDetail({ e, title, loc, dim }) {
  return (
    <div style={{ border: '1px solid var(--line)', borderRadius: 'var(--r-md)', padding: 14 }}>
      <div className="flex ac gap-10 mb-12">
        <div className="l-ic" style={{ ...evTone(e.tone), width: 36, height: 36 }}><Icon name={e.ic} size={18} /></div>
        <div className="grow"><div className="strong" style={{ fontSize: 14 }}>{title}</div></div>
      </div>
      <div className="flex col gap-8">
        <div className="flex ac gap-8 muted" style={{ fontSize: 12.5 }}><Icon name="clock" size={14} /> {e.time}</div>
        <div className="flex ac gap-8 muted" style={{ fontSize: 12.5 }}><Icon name="map-pin" size={14} /> {loc}</div>
      </div>
      <Btn variant="ghost" size="sm" className="btn-block mt-12" iconR="arrow-right">{dim}</Btn>
    </div>
  );
}
const APPT_CATEGORIES = [
  { key: 'immigration', icon: 'shield', match: (e) => ['police', 'biometrics', 'ministry', 'immigration'].includes(e.key) },
  { key: 'medical', icon: 'stethoscope', match: (e) => ['medical', 'health', 'checkup'].includes(e.key) },
  { key: 'document', icon: 'file-text', match: (e) => ['document', 'signing', 'notary'].includes(e.key) },
  { key: 'personal', icon: 'user-round', match: (e) => ['custom', 'google', 'personal'].includes(e.key) },
  { key: 'other', icon: 'circle-dashed', match: () => true },
];

function apptCategoryOf(e) {
  if (e.category) return e.category;
  for (const c of APPT_CATEGORIES) if (c.match(e)) return c.key;
  return 'other';
}

function AppointmentsPage({ events, openModal }) {
  const { t, dict } = useT();
  const [view, setView] = useState('month');
  const [sel, setSel] = useState(9);
  const [filter, setFilter] = useState('all');
  const allRows = (events || CAL_EVENTS).map((e) => ({ ...e, category: apptCategoryOf(e) }));
  const rows = filter === 'all' ? allRows : allRows.filter((e) => e.category === filter);
  const evByDay = {};
  rows.forEach((e) => { (evByDay[e.d] = evByDay[e.d] || []).push(e); });
  const selEvents = evByDay[sel] || [];
  const chipStyle = (active) => ({
    display: 'inline-flex', alignItems: 'center', gap: 6, padding: '6px 11px', borderRadius: 999,
    border: '1px solid ' + (active ? 'var(--brand-500)' : 'var(--line)'),
    background: active ? 'var(--brand-50)' : 'var(--surface)', color: active ? 'var(--brand-700)' : 'var(--ink-700)',
    fontSize: 12.5, fontWeight: 600, cursor: 'pointer', whiteSpace: 'nowrap',
  });
  const cells = [];
  for (let i = 0; i < FIRST_DOW; i++) cells.push(null);
  for (let d = 1; d <= DAYS_IN; d++) cells.push(d);
  while (cells.length % 7 !== 0) cells.push(null);
  const dow = (d) => dict.weekdays[(FIRST_DOW + d - 1) % 7];
  const titleOf = (e) => e.title || t('ev.' + e.key);
  const locOf = (e) => e.loc || t('ev.' + e.key + 'Loc');

  return (
    <>
      <PageHead title={t('nav.appointments')} sub={t('sub.appointments')}
        actions={<><Seg items={[{ value: 'month', label: t('c.month') }, { value: 'list', label: t('c.list') }]} value={view} onChange={setView} /><Btn variant="primary" icon="calendar-plus" onClick={() => openModal('calendarEvent')}>{t('c.schedule')}</Btn></>} />
      <div className="flex wrap gap-8" style={{ marginBottom: 16 }}>
        <button style={chipStyle(filter === 'all')} onClick={() => setFilter('all')}>{t('task.cat.all')}</button>
        {APPT_CATEGORIES.map((c) => (
          <button key={c.key} style={chipStyle(filter === c.key)} onClick={() => setFilter(c.key)}>
            <Icon name={c.icon} size={13} />{t('appt.cat.' + c.key)}
          </button>
        ))}
      </div>
      {view === 'month' ? (
        <div className="dash-grid">
          <div className="col-8">
            <Card>
              <div className="cal-head">
                <div className="flex ac gap-10"><IconBtn name="chevron-left" /><div className="h3" style={{ minWidth: 150 }}>{dict.months[MONTH_IDX]} 2026</div><IconBtn name="chevron-right" /></div>
                <div className="grow" />
                <Btn variant="ghost" size="sm" icon="dot" onClick={() => setSel(TODAY)}>{t('c.today')}</Btn>
              </div>
              <div className="cal-grid">{dict.weekdays.map((w, i) => <div className="cal-dow" key={i}>{w}</div>)}</div>
              <div className="cal-grid">
                {cells.map((d, i) => {
                  if (d === null) return <div className="cal-cell empty" key={i} />;
                  const evs = evByDay[d] || [];
                  return (
                    <div key={i} className={'cal-cell ' + (d === TODAY ? 'today ' : '') + (d === sel ? 'sel' : '')} onClick={() => setSel(d)}>
                      <div className="cal-num">{d}</div>
                      {evs.map((e, j) => <div key={j} className={'cal-ev ' + e.tone}><span className="ev-dot" /><span className="ev-time mono">{e.time}</span> {titleOf(e).split(' — ')[0]}</div>)}
                    </div>
                  );
                })}
              </div>
            </Card>
          </div>
          <div className="col-4">
            <Card style={{ height: '100%' }}>
              <CardHead icon="calendar-clock" title={dow(sel) + ' · ' + sel + ' ' + dict.months[MONTH_IDX]} sub={selEvents.length + ' ' + (selEvents.length === 1 ? t('appt.event') : t('appt.events'))} />
              <div className="card-bd">
                {selEvents.length === 0
                  ? <div className="flex col ac jc" style={{ padding: '34px 10px', textAlign: 'center', gap: 10 }}><div className="hd-ic" style={{ width: 44, height: 44, background: 'var(--surface-3)', color: 'var(--ink-400)' }}><Icon name="calendar-x" size={20} /></div><div className="muted" style={{ fontSize: 13 }}>{t('appt.noEvents')}</div></div>
                  : <div className="flex col gap-12">{selEvents.map((e, i) => <ApptDetail key={i} e={e} title={titleOf(e)} loc={locOf(e)} dim={t('c.details')} />)}</div>}
              </div>
            </Card>
          </div>
          <div className="col-12">
            <Card>
              <CardHead icon="list" title={t('appt.upcoming')} sub={t('appt.thisMonth')} />
              <div className="card-bd" style={{ paddingTop: 4, paddingBottom: 4 }}>
                <div className="rowlist">
                  {rows.map((e, i) => (
                    <div className="lrow pointer" key={i} onClick={() => setSel(e.d)}>
                      <div className="l-ic" style={evTone(e.tone)}><Icon name={e.ic} size={18} /></div>
                      <div className="l-bd"><div className="l-t">{titleOf(e)}</div><div className="l-s">{dow(e.d)} {e.d} {dict.months[MONTH_IDX]} · {e.time} · {locOf(e)}</div></div>
                      <Btn variant="ghost" size="sm">{t('c.details')}</Btn>
                    </div>
                  ))}
                </div>
              </div>
            </Card>
          </div>
        </div>
      ) : (
        <Card><div className="card-bd"><div className="rowlist">
          {rows.map((e, i) => (
            <div className="lrow" key={i}>
              <div className="l-ic" style={evTone(e.tone)}><Icon name={e.ic} size={18} /></div>
              <div className="l-bd"><div className="l-t">{titleOf(e)}</div><div className="l-s">{dow(e.d)} {e.d} {dict.months[MONTH_IDX]} · {e.time} · {locOf(e)}</div></div>
              <Btn variant="ghost" size="sm">{t('c.details')}</Btn>
            </div>
          ))}
        </div></div></Card>
      )}
    </>
  );
}

/* ===== TASKS ===== */
const TASK_CATEGORIES = [
  { key: 'immigration', icon: 'shield', tone: 'info' },
  { key: 'document', icon: 'file-text', tone: 'neut' },
  { key: 'finance', icon: 'receipt', tone: 'warn' },
  { key: 'appointment', icon: 'calendar', tone: 'info' },
  { key: 'admin', icon: 'briefcase', tone: 'neut' },
  { key: 'other', icon: 'circle-dashed', tone: 'neut' },
];

function taskCatMeta(key) {
  return TASK_CATEGORIES.find((c) => c.key === key) || TASK_CATEGORIES[TASK_CATEGORIES.length - 1];
}

function TasksPage({ tasks, openModal, onSync, syncState, onToggleTask, contact, isAdmin, onAddSelfTask }) {
  const { t } = useT();
  const [filter, setFilter] = useState('all');
  const TICKET_TITLE_RE = /^\[[^\]]+\]\s*/;
  const rows = (tasks || [])
    .filter((tk) => !TICKET_TITLE_RE.test(String(tk.title || '')))
    .map((tk) => ({ ...tk, category: tk.category || 'other' }));
  const filtered = filter === 'all' ? rows : rows.filter((tk) => tk.category === filter);
  const chipStyle = (active) => ({
    display: 'inline-flex', alignItems: 'center', gap: 6, padding: '6px 11px', borderRadius: 999,
    border: '1px solid ' + (active ? 'var(--brand-500)' : 'var(--line)'),
    background: active ? 'var(--brand-50)' : 'var(--surface)', color: active ? 'var(--brand-700)' : 'var(--ink-700)',
    fontSize: 12.5, fontWeight: 600, cursor: 'pointer', whiteSpace: 'nowrap',
  });
  return (
    <>
      <PageHead title={t('nav.tasks')} sub={t('sub.tasks')}
        actions={isAdmin ? <Btn variant="ghost" icon="refresh-cw" onClick={onSync} disabled={syncState && syncState.syncing}>{syncState && syncState.syncing ? t('task.syncing') : t('task.syncGhl')}</Btn> : null} />
      {syncState && syncState.error && (
        <div className="alert warn" style={{ marginBottom: 14 }}>
          <div className="a-ic"><Icon name="alert-triangle" size={16} /></div>
          <div className="grow"><div className="a-t">{syncState.error}</div></div>
        </div>
      )}
      <div className="flex wrap gap-8" style={{ marginBottom: 16 }}>
        <button style={chipStyle(filter === 'all')} onClick={() => setFilter('all')}>{t('task.cat.all')}</button>
        {TASK_CATEGORIES.map((c) => (
          <button key={c.key} style={chipStyle(filter === c.key)} onClick={() => setFilter(c.key)}>
            <Icon name={c.icon} size={13} />{t('task.cat.' + c.key)}
          </button>
        ))}
      </div>
      <Card className="card-pad mb-16">
        <div className="flex ac gap-10 wrap">
          <Icon name="square-pen" size={17} className="dim" />
          <div className="grow" style={{ minWidth: 0, fontSize: 13, color: 'var(--ink-600)' }}>{t('task.ownPlaceholder')}</div>
          <Btn variant="primary" icon="plus" onClick={() => openModal && openModal('task')}>{t('task.addOwn')}</Btn>
        </div>
      </Card>
      <Card><div className="card-bd"><div className="rowlist">
        {filtered.length === 0 ? (
          <div className="lrow" style={{ borderBottom: 'none', justifyContent: 'center', padding: '24px 0', color: 'var(--ink-400)', fontSize: 13 }}>
            <Icon name="circle-check-big" size={16} />
            <span style={{ marginLeft: 8 }}>{t('task.empty')}</span>
          </div>
        ) : filtered.map((tk, i) => {
          const meta = taskCatMeta(tk.category);
          return (
            <div className="lrow" key={i}>
              <button className="icon-btn" onClick={() => onToggleTask && onToggleTask(tk)} style={{ width: 28, height: 28, color: tk.done ? 'var(--brand-500)' : 'var(--ink-300)' }}><Icon name={tk.done ? 'circle-check-big' : 'circle'} size={20} /></button>
              <div className="l-bd">
                <div className="l-t" style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap', color: tk.done ? 'var(--ink-400)' : 'var(--ink-900)' }}>
                  {tk.taskType && <Badge tone={tk.taskTypeTone}>{t(tk.taskTypeLabelKey)}</Badge>}
                  <span style={{ textDecoration: tk.done ? 'line-through' : 'none' }}>{tk.title || t(tk.tk)}</span>
                </div>
                <div className="l-s" style={{ display: 'inline-flex', alignItems: 'center', gap: 5, marginTop: 2 }}>
                  <Icon name={meta.icon} size={12} />{t('task.cat.' + tk.category)}
                </div>
              </div>
              <div className="flex ac gap-8">
                <Badge tone={tk.tone} dot>{(tk.done ? t('c.done') : t('c.due')) + ' ' + tk.due}</Badge>
                {tk.taskType !== 'bilgi' && <Btn variant="ghost" size="sm" icon="paperclip" onClick={(e) => { e.stopPropagation(); openModal("taskAttachment", { task: tk, contact }); }}>{t("task.attach.btn")}</Btn>}
              </div>
            </div>
          );
        })}
      </div></div></Card>
    </>
  );
}

/* ===== REPORTS ===== */
function MiniBars() {
  const data = [40, 55, 48, 62, 70, 58, 75, 68, 82, 78, 90, 85];
  return (
    <div style={{ display: 'flex', alignItems: 'flex-end', gap: 8, height: 96, padding: '0 2px' }}>
      {data.map((h, i) => (
        <div key={i} className="grow" style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6 }}>
          <div style={{ width: '100%', height: h + '%', borderRadius: 6, background: i === data.length - 1 ? 'var(--brand-500)' : 'var(--brand-100)' }} />
          <span className="dim" style={{ fontSize: 9.5 }}>{i + 1}</span>
        </div>
      ))}
    </div>
  );
}
function ReportsPage() {
  const { t } = useT();
  return (
    <>
      <PageHead title={t('nav.reports')} sub={t('sub.reports')} actions={<Btn variant="ghost" icon="download">{t('c.exportPdf')}</Btn>} />
      <div className="grid g-12 mb-20" style={{ gap: 16 }}>
        <div className="col-3"><Stat icon="folder-check" value="92%" label={t('rep.completion')} trend="+8%" /></div>
        <div className="col-3"><Stat icon="clock" tone="blue" value="34d" label={t('rep.processing')} /></div>
        <div className="col-3"><Stat icon="shield-check" value="100%" label={t('rep.compliance')} /></div>
        <div className="col-3"><Stat icon="file-check-2" value="18" label={t('rep.docs')} /></div>
      </div>
      <Card><CardHead icon="chart-line" title={t('rep.activity')} sub={t('rep.last12')} /><div className="card-bd"><MiniBars /></div></Card>
    </>
  );
}

function SimplePage({ icon, title, sub }) {
  return (
    <div style={{ maxWidth: 520, margin: '8vh auto', textAlign: 'center' }}>
      <div className="hd-ic" style={{ width: 60, height: 60, margin: '0 auto 18px', borderRadius: 16 }}><Icon name={icon} size={28} /></div>
      <h1 className="h1" style={{ marginBottom: 8 }}>{title}</h1>
      <p className="muted">{sub}</p>
    </div>
  );
}

function ProfilePage({ contact, onRefresh }) {
  const { t } = useT();
  const [wizardOpen, setWizardOpen] = useState(false);
  const [wizardSection, setWizardSection] = useState(null);
  const authState = (window.YEYE_AUTH && window.YEYE_AUTH.getState && window.YEYE_AUTH.getState()) || {};

  if (!contact) {
    return (
      <>
        <PageHead title={t('nav.profile')} sub={t('pg.profileSub')} />
        <Card className="profile-loading-card">
          <div className="card-bd">
            <div className="profile-loading-dot" aria-hidden="true" />
            <span>{t('profileFields.loading')}</span>
          </div>
        </Card>
      </>
    );
  }

  const user = authState.user || {};
  const name = contactDisplayName(contact) || user.name || t('nav.profile');
  const email = contact.email || user.email || '';
  const initials = name.split(/\s+/).filter(Boolean).map((word) => word[0]).join('').slice(0, 2).toUpperCase();
  const customAvatar = window.YEYE_AUTH && window.YEYE_AUTH.getAvatar && window.YEYE_AUTH.getAvatar();
  const avatar = customAvatar && customAvatar.type === 'emoji'
    ? <div className="profile-page-avatar profile-page-avatar-emoji">{customAvatar.value}</div>
    : customAvatar && customAvatar.type === 'image'
      ? <img className="profile-page-avatar" src={customAvatar.value} alt="" />
      : user.picture
        ? <img className="profile-page-avatar" src={user.picture} alt="" />
        : <Avatar size="lg" tone={{ bg: 'var(--brand-500)', fg: '#fff' }}>{initials}</Avatar>;

  return (
    <>
      <PageHead title={t('nav.profile')} sub={t('pg.profileSub')} />
      <Card className="profile-page-head mb-18">
        <div className="card-bd">
          {avatar}
          <div>
            <h2>{name}</h2>
            {email && <p>{email}</p>}
          </div>
        </div>
      </Card>
      <Card>
        <div className="card-bd">
          <RequiredFieldsGrid
            contact={contact}
            title={t('profileFields.essentials')}
            onEdit={(entry) => {
              setWizardSection(entry.section);
              setWizardOpen(true);
            }}
          />
        </div>
      </Card>
      {wizardOpen && (
        <ProfileWizard
          contact={contact}
          initialSection={wizardSection}
          onClose={() => setWizardOpen(false)}
          onSaved={() => {
            setWizardOpen(false);
            if (onRefresh) onRefresh();
          }}
        />
      )}
    </>
  );
}

const AVATAR_EMOJIS = ['🙂', '😎', '🤩', '🥳', '🦸', '🧑‍💻', '🐱', '🐶', '🦊', '🐼', '🐨', '🐯', '🦁', '🌟', '⚡', '🚀', '🎯', '🌈', '🌵', '🍀', '☕', '🎨', '📚', '💼'];

function AvatarSection() {
  const { t } = useT();
  const [avatar, setAvatarState] = useState(() => (window.YEYE_AUTH.getAvatar && window.YEYE_AUTH.getAvatar()) || null);
  const [uploadErr, setUploadErr] = useState(null);

  const apply = (av) => { window.YEYE_AUTH.setAvatar(av); setAvatarState(av); setUploadErr(null); };

  const onFile = (e) => {
    const file = e.target.files && e.target.files[0];
    if (!file) return;
    if (file.size > 400 * 1024) { setUploadErr(t('set.avatarTooLarge')); return; }
    const reader = new FileReader();
    reader.onload = () => apply({ type: 'image', value: reader.result });
    reader.onerror = () => setUploadErr(t('set.avatarReadFailed'));
    reader.readAsDataURL(file);
    e.target.value = '';
  };

  const preview = avatar && avatar.type === 'emoji'
    ? <div className="avatar a-lg" style={{ background: 'var(--brand-100)', color: 'var(--ink-900)', fontSize: 26, width: 60, height: 60 }}>{avatar.value}</div>
    : avatar && avatar.type === 'image'
      ? <img src={avatar.value} alt="" className="avatar a-lg" style={{ width: 60, height: 60, borderRadius: '50%', objectFit: 'cover' }} />
      : <Avatar size="lg" tone={{ bg: 'var(--brand-500)', fg: '#fff' }}>?</Avatar>;

  return (
    <Card>
      <CardHead icon="user" title={t('set.avatar')} sub={t('set.avatarSub')} />
      <div className="card-bd">
        <div className="flex ac gap-16" style={{ marginBottom: 18 }}>
          {preview}
          <div className="flex col gap-6">
            <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--ink-900)' }}>{t('set.avatarCurrent')}</div>
            {avatar && <button className="btn btn-ghost btn-sm" onClick={() => apply(null)} style={{ alignSelf: 'flex-start' }}>{t('set.avatarRemove')}</button>}
          </div>
        </div>
        <div style={{ fontSize: 12, fontWeight: 700, color: 'var(--ink-700)', marginBottom: 10 }}>{t('set.avatarPickEmoji')}</div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(48px, 1fr))', gap: 8, marginBottom: 18 }}>
          {AVATAR_EMOJIS.map((emo) => (
            <button key={emo} type="button" onClick={() => apply({ type: 'emoji', value: emo })}
              style={{
                aspectRatio: '1', border: '1px solid var(--line)', borderRadius: 12, background: avatar && avatar.value === emo ? 'var(--brand-100)' : 'var(--surface)',
                fontSize: 24, cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center',
              }}>{emo}</button>
          ))}
        </div>
        <div style={{ fontSize: 12, fontWeight: 700, color: 'var(--ink-700)', marginBottom: 8 }}>{t('set.avatarUpload')}</div>
        <label className="btn btn-soft btn-sm" style={{ cursor: 'pointer', display: 'inline-flex' }}>
          <Icon name="upload" size={14} />{t('set.avatarUploadBtn')}
          <input type="file" accept="image/*" onChange={onFile} style={{ display: 'none' }} />
        </label>
        {uploadErr && <div className="alert bad" style={{ marginTop: 12 }}><div className="a-ic"><Icon name="alert-triangle" size={16} /></div><div className="grow"><div className="a-t">{uploadErr}</div></div></div>}
        <div className="dim" style={{ fontSize: 11, marginTop: 8 }}>{t('set.avatarUploadHint')}</div>
      </div>
    </Card>
  );
}

function CurrencySection() {
  const { t, currency, setCurrency } = useT();
  const options = [
    { k: 'EUR', label: 'EUR', sub: '€' },
    { k: 'CZK', label: 'CZK', sub: 'Kč' },
    { k: 'TRY', label: 'TL', sub: '₺' },
  ];
  return (
    <Card>
      <CardHead icon="coins" title={t('currency.title')} sub={t('currency.sub')} />
      <div className="card-bd">
        <div className="flex gap-8 wrap">
          {options.map((opt) => (
            <Btn key={opt.k} variant={currency === opt.k ? 'primary' : 'ghost'} icon={currency === opt.k ? 'check' : 'coins'} onClick={() => setCurrency(opt.k)}>
              {opt.label} <span className="mono" style={{ opacity: 0.75 }}>{opt.sub}</span>
            </Btn>
          ))}
        </div>
        <div className="muted" style={{ fontSize: 12.5, marginTop: 10 }}>{t('currency.rateNote')}</div>
      </div>
    </Card>
  );
}

function SettingsPage() {
  const { t } = useT();
  const [current, setCurrent] = useState('');
  const [next, setNext] = useState('');
  const [confirm, setConfirm] = useState('');
  const [status, setStatus] = useState(null);
  const [busy, setBusy] = useState(false);

  const errText = (code) => {
    switch (code) {
      case 'wrong-current': return t('set.pwWrongCurrent');
      case 'too-short': return t('set.pwTooShort');
      case 'same-as-current': return t('set.pwSameAsCurrent');
      case 'mismatch': return t('set.pwMismatch');
      case 'not-signed-in': return t('set.pwNotSignedIn');
      default: return t('set.pwGeneric');
    }
  };

  const submit = async (e) => {
    e.preventDefault();
    setStatus(null);
    if (next !== confirm) { setStatus({ ok: false, code: 'mismatch' }); return; }
    setBusy(true);
    try {
      const res = await window.YEYE_AUTH.changePassword(current, next);
      if (res && res.ok) {
        setStatus({ ok: true });
        setCurrent(''); setNext(''); setConfirm('');
      } else {
        setStatus({ ok: false, code: (res && res.code) || 'unknown' });
      }
    } catch (err) {
      setStatus({ ok: false, code: 'unknown' });
    } finally {
      setBusy(false);
    }
  };

  const fieldStyle = {
    height: 44, borderRadius: 10, border: '1px solid var(--line)',
    padding: '0 12px', fontSize: 14, background: 'var(--surface)',
    color: 'var(--ink-900)', outline: 'none',
  };

  return (
    <>
      <PageHead title={t('nav.settings')} sub={t('pg.settingsSub')} />
      <div style={{ maxWidth: 520, display: 'flex', flexDirection: 'column', gap: 20 }}>
        <AvatarSection />
        <CurrencySection />
        <Card>
          <CardHead icon="lock" title={t('set.changePassword')} sub={t('set.changePasswordSub')} />
          <div className="card-bd">
            <form onSubmit={submit} style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
              <label style={{ display: 'flex', flexDirection: 'column', gap: 6, fontSize: 12, fontWeight: 700, color: 'var(--ink-700)' }}>
                {t('set.currentPassword')}
                <input type="password" value={current} onChange={(e) => setCurrent(e.target.value)} required autoComplete="current-password" style={fieldStyle} />
              </label>
              <label style={{ display: 'flex', flexDirection: 'column', gap: 6, fontSize: 12, fontWeight: 700, color: 'var(--ink-700)' }}>
                {t('set.newPassword')}
                <input type="password" value={next} onChange={(e) => setNext(e.target.value)} required minLength={6} autoComplete="new-password" style={fieldStyle} />
              </label>
              <label style={{ display: 'flex', flexDirection: 'column', gap: 6, fontSize: 12, fontWeight: 700, color: 'var(--ink-700)' }}>
                {t('set.confirmPassword')}
                <input type="password" value={confirm} onChange={(e) => setConfirm(e.target.value)} required minLength={6} autoComplete="new-password" style={fieldStyle} />
              </label>
              {status && !status.ok && (
                <div className="alert bad" style={{ margin: 0 }}>
                  <div className="a-ic"><Icon name="alert-triangle" size={16} /></div>
                  <div className="grow"><div className="a-t">{errText(status.code)}</div></div>
                </div>
              )}
              {status && status.ok && (
                <div className="alert ok" style={{ margin: 0 }}>
                  <div className="a-ic"><Icon name="check" size={16} /></div>
                  <div className="grow"><div className="a-t">{t('set.pwUpdated')}</div></div>
                </div>
              )}
              <div>
                <Btn variant="primary" type="submit" disabled={busy}>{busy ? t('c.saving') : t('set.savePassword')}</Btn>
              </div>
            </form>
          </div>
        </Card>
      </div>
    </>
  );
}

Object.assign(window, {
  ServicesPage, PurchasedServicesPage, DocumentsPage, MessagesPage, InvoicesPage, SupportPage,
  FormSubmissionPage, AppointmentsPage, TasksPage, ReportsPage, SimplePage, ProfilePage, SettingsPage, AvatarSection,
});
