// dashboard.jsx — Top bar, sidebar, quick actions, module grid, bottom row, bottom nav

const COMM_MINI_COPY = {
  hint: {
    fa: "نمای سریع؛ برای ورود، کلیک کنید",
    en: "Quick preview; click to open",
    ar: "معاينة سريعة؛ انقر للدخول"
  },
  demo: { fa: "نمونه محلی", en: "Local demo", ar: "نموذج محلي" },
  openPanel: { fa: "ورود به پنل کامل", en: "Open full panel", ar: "فتح اللوحة الكاملة" },
  empty: { fa: "مورد فعالی برای نمایش نیست.", en: "Nothing active to preview.", ar: "لا توجد عناصر نشطة للعرض." },
  unread: { fa: "خوانده‌نشده", en: "Unread", ar: "غير مقروء" }
};

const CommMiniPreviewTrigger = ({
  tab,
  lang,
  label,
  count,
  items,
  Icon,
  open,
  onPreviewChange,
  onOpenPanel
}) => {
  const previewId = `comm-mini-${tab}`;
  const triggerRef = React.useRef(null);
  const openTimer = React.useRef(null);
  const closeTimer = React.useRef(null);
  const suppressFocusOpen = React.useRef(false);
  const localize = (value) => window.ShahdadCommunications.localize(lang, value);
  const clearTimers = () => {
    window.clearTimeout(openTimer.current);
    window.clearTimeout(closeTimer.current);
    openTimer.current = null;
    closeTimer.current = null;
  };
  const scheduleShow = () => {
    clearTimers();
    if (open) return;
    openTimer.current = window.setTimeout(() => onPreviewChange(tab), 140);
  };
  const showImmediately = () => {
    if (suppressFocusOpen.current) return;
    clearTimers();
    onPreviewChange(tab);
  };
  const scheduleHide = () => {
    window.clearTimeout(openTimer.current);
    window.clearTimeout(closeTimer.current);
    closeTimer.current = window.setTimeout(() => {
      onPreviewChange((current) => current === tab ? null : current);
    }, 180);
  };
  const closeImmediately = () => {
    clearTimers();
    onPreviewChange((current) => current === tab ? null : current);
  };
  const openPanel = () => {
    closeImmediately();
    onOpenPanel(tab);
  };
  const handleBlur = (event) => {
    if (!event.currentTarget.contains(event.relatedTarget)) scheduleHide();
  };
  const handleKeyDown = (event) => {
    if (!open || event.key !== "Escape") return;
    event.preventDefault();
    event.stopPropagation();
    suppressFocusOpen.current = true;
    closeImmediately();
    triggerRef.current?.focus({ preventScroll: true });
    window.setTimeout(() => { suppressFocusOpen.current = false; }, 0);
  };

  React.useEffect(() => () => {
    window.clearTimeout(openTimer.current);
    window.clearTimeout(closeTimer.current);
  }, []);

  const DirectionIcon = lang === "en" ? Ic.chevR : Ic.chevL;

  return (
    <div
      className={"comm-mini-anchor comm-desktop-trigger" + (open ? " is-open" : "")}
      onMouseEnter={scheduleShow}
      onMouseLeave={scheduleHide}
      onFocus={showImmediately}
      onBlur={handleBlur}
      onKeyDown={handleKeyDown}
    >
      <button
        ref={triggerRef}
        type="button"
        className={"icon-btn" + (open ? " active" : "")}
        aria-label={`${label} — ${fmt(count, lang)}`}
        aria-haspopup="dialog"
        aria-expanded={open}
        aria-controls={previewId}
        aria-describedby={open ? `${previewId}-hint` : undefined}
        onClick={openPanel}
      >
        <Icon size={18} />
        {count > 0 && <span className="badge fa-num">{fmt(count, lang)}</span>}
      </button>

      {open && (
        <section
          id={previewId}
          className={`comm-mini-preview comm-mini-${tab}`}
          role="region"
          aria-label={`${label} — ${localize(COMM_MINI_COPY.hint)}`}
        >
          <header className="comm-mini-head">
            <span className="comm-mini-head-icon" aria-hidden="true"><Icon size={16} /></span>
            <span className="comm-mini-head-copy">
              <strong>{label}</strong>
              <small id={`${previewId}-hint`}>{localize(COMM_MINI_COPY.hint)}</small>
            </span>
            <span className="comm-mini-count fa-num">{fmt(count, lang)}</span>
          </header>

          <div className="comm-mini-demo">
            <span></span>
            {localize(COMM_MINI_COPY.demo)}
          </div>

          {items.length ? (
            <div className="comm-mini-list" role="list">
              {items.map((item) => {
                const title = tab === "letters" ? localize(item.subject) : localize(item.title);
                const secondary = tab === "letters"
                  ? localize(item.from)
                  : tab === "activities"
                    ? localize(item.actor)
                    : localize(item.meta);
                const markerKind = item.kind || item.category || item.folder || "info";
                return (
                  <article
                    key={item.id}
                    className={"comm-mini-item" + (item.unread ? " unread" : "")}
                    role="listitem"
                  >
                    <span className={`comm-mini-item-mark kind-${markerKind}`} aria-hidden="true">
                      {item.unread && <i></i>}
                    </span>
                    <span className="comm-mini-item-copy">
                      <strong>{title}</strong>
                      <small>
                        <span>{secondary}</span>
                        <time className="fa-num">{localize(item.timeText)}</time>
                      </small>
                    </span>
                    {item.unread && (
                      <span className="comm-mini-unread" aria-hidden="true"></span>
                    )}
                  </article>
                );
              })}
            </div>
          ) : (
            <p className="comm-mini-empty">{localize(COMM_MINI_COPY.empty)}</p>
          )}

          <button type="button" className="comm-mini-open" onClick={openPanel}>
            <span>{localize(COMM_MINI_COPY.openPanel)}</span>
            <DirectionIcon size={14} aria-hidden="true" />
          </button>
        </section>
      )}
    </div>
  );
};

const TopBar = ({ lang, setLang, muted, toggleMute, onOpen, onAuth, menuOpen, setMenuOpen, session }) => {
  const t = T[lang];
  const currentPlan = window.ShahdadPlans?.getCurrentPlan?.(session);
  const currentPlanName = currentPlan
    ? window.ShahdadPlans.localize(lang, currentPlan.name)
    : (lang === "fa" ? "پلوتون" : lang === "ar" ? "بلوتو" : "Pluto");
  const planLabel = session && !session.isGuest
    ? (lang === "fa" ? `پلن: ${currentPlanName}` : lang === "ar" ? `الخطة: ${currentPlanName}` : `Plan: ${currentPlanName}`)
    : (lang === "fa" ? "مشاهده پلن‌ها" : lang === "ar" ? "عرض الخطط" : "View plans");
  const walletSummary = window.ShahdadWallet?.getSummary?.(session) || { availableBalance: null, source: "unavailable", isGuest: true };
  const walletLabel = walletSummary.isGuest
    ? (lang === "fa" ? "کیف پول" : lang === "ar" ? "المحفظة" : "Wallet")
    : walletSummary.source === "server" && Number.isFinite(walletSummary.availableBalance)
      ? window.ShahdadWallet?.formatMoney?.(walletSummary.availableBalance, lang) || fmt(walletSummary.availableBalance, lang)
      : (lang === "fa" ? "کیف پول" : lang === "ar" ? "المحفظة" : "Wallet");
  const [communications] = window.ShahdadCommunications.useStore(session);
  const [communicationsPreview, setCommunicationsPreview] = React.useState(null);
  const [communicationsNow, setCommunicationsNow] = React.useState(() => Date.now());
  React.useEffect(() => {
    const timer = window.setInterval(() => setCommunicationsNow(Date.now()), 60 * 1000);
    return () => window.clearInterval(timer);
  }, []);
  const unreadNotifications = communications.notifications.filter((item) =>
    item.unread && !item.archived && (!item.snoozedUntil || item.snoozedUntil <= communicationsNow)
  ).length;
  const recentActivities = communications.activities.filter((item) =>
    !item.archived && communicationsNow - item.time < 24 * 60 * 60 * 1000
  ).length;
  const unreadLetters = communications.letters.filter((item) => item.folder === "inbox" && item.unread && !item.archived).length;
  const communicationTotal = unreadNotifications + unreadLetters;
  const notificationPreview = window.ShahdadCommunications.getPreviewItems(communications, "notifications", communicationsNow);
  const activityPreview = window.ShahdadCommunications.getPreviewItems(communications, "activities", communicationsNow);
  const letterPreview = window.ShahdadCommunications.getPreviewItems(communications, "letters", communicationsNow);
  const openCommunications = (tab) => {
    setCommunicationsPreview(null);
    window.ShahdadCommunications.setInitialTab(tab);
    AudioCtl.open();
    onOpen("communications");
  };
  const [q, setQ] = React.useState("");
  const ask = () => { if (!q.trim()) return; window.__pendingAsk = q.trim(); AudioCtl.open(); onOpen("aiChat"); setQ(""); };
  return (
    <div className="topbar">
      <div className="brand">
        <img className="brand-logo-img" src="uploads/shahdad-logo-mobile-vector-gold.png" alt="لوگوی کامل شهداد AI" />
      </div>

      <div className="top-middle">
        <div className="searchbar">
          <Ic.search size={20} className="search-ico" />
          <input value={q} onChange={(e) => setQ(e.target.value)} onKeyDown={(e) => {if (e.key === "Enter") ask();}}
            placeholder={lang === "fa" ? "جستجو یا پرسش از دستیار حقوقی..." : lang === "ar" ? "ابحث أو اسأل المساعد..." : "Search or ask the legal assistant..."} />
          <button className="searchbar-go" onClick={ask} title={lang === "fa" ? "پرسش از دستیار" : "Ask the assistant"}><Ic.send size={15} /></button>
        </div>
      </div>

      <div className="top-actions">
        <button
          className="account-pill plan"
          onClick={() => { AudioCtl.click(); onOpen("plans"); }}
          title={lang === "fa" ? "مشاهده و مقایسه پلن‌ها" : lang === "ar" ? "عرض الخطط ومقارنتها" : "View and compare plans"}
          aria-haspopup="dialog"
        >
          <Ic.shieldCheck size={14} />
          <span>{planLabel}</span>
        </button>
        <button
          className={"account-pill wallet" + (session && session.isGuest ? " locked" : "")}
          onClick={() => { AudioCtl.click(); onOpen("wallet"); }}
          title={lang === "fa" ? "کیف پول و پرداخت‌ها" : lang === "ar" ? "المحفظة والمدفوعات" : "Wallet & payments"}
          aria-haspopup="dialog"
        >
          <Ic.coin size={14} />
          <span className="fa-num">{walletLabel}</span>
        </button>
        <CommMiniPreviewTrigger
          tab="notifications"
          lang={lang}
          label={t.importantNotifs}
          count={unreadNotifications}
          items={notificationPreview}
          Icon={Ic.bell}
          open={communicationsPreview === "notifications"}
          onPreviewChange={setCommunicationsPreview}
          onOpenPanel={openCommunications}
        />
        <CommMiniPreviewTrigger
          tab="activities"
          lang={lang}
          label={t.recentActs}
          count={recentActivities}
          items={activityPreview}
          Icon={Ic.clock}
          open={communicationsPreview === "activities"}
          onPreviewChange={setCommunicationsPreview}
          onOpenPanel={openCommunications}
        />
        <CommMiniPreviewTrigger
          tab="letters"
          lang={lang}
          label={lang === "fa" ? "نامه‌ها" : lang === "ar" ? "الرسائل" : "Letters"}
          count={unreadLetters}
          items={letterPreview}
          Icon={Ic.mail}
          open={communicationsPreview === "letters"}
          onPreviewChange={setCommunicationsPreview}
          onOpenPanel={openCommunications}
        />
        <button
          className="icon-btn comm-mobile-trigger"
          title={lang === "fa" ? "مرکز ارتباطات" : lang === "ar" ? "مركز الاتصالات" : "Communications center"}
          aria-label={`${lang === "fa" ? "مرکز ارتباطات" : lang === "ar" ? "مركز الاتصالات" : "Communications center"} — ${fmt(communicationTotal, lang)}`}
          aria-haspopup="dialog"
          onClick={() => openCommunications(unreadLetters > unreadNotifications ? "letters" : "notifications")}
        >
          <Ic.mail size={18} />
          {communicationTotal > 0 && <span className="badge fa-num">{fmt(communicationTotal, lang)}</span>}
        </button>
        <div className="lang-toggle">
          <button className={lang === "fa" ? "on" : ""} onClick={() => {AudioCtl.click();setLang("fa");}}>FA</button>
          <button className={lang === "ar" ? "on" : ""} onClick={() => {AudioCtl.click();setLang("ar");}}>AR</button>
          <button className={lang === "en" ? "on" : ""} onClick={() => {AudioCtl.click();setLang("en");}}>EN</button>
        </div>
        <button className="icon-btn" title={muted ? "Unmute" : "Mute"} onClick={toggleMute}>
          {muted ? <Ic.speakerMute size={18} /> : <Ic.speaker size={18} />}
        </button>
        {session && session.isGuest ?
        <React.Fragment>
          <button
            className="btn-login"
            onClick={onAuth}
            title={lang === "fa" ? "ورود یا ثبت‌نام" : lang === "ar" ? "تسجيل الدخول أو إنشاء حساب" : "Sign in or sign up"}
            aria-haspopup="dialog"
          >
            <Ic.user size={15} /> <span>{lang === "fa" ? "ورود / ثبت‌نام" : lang === "ar" ? "دخول / تسجيل" : "Sign in"}</span>
          </button>
          <button className="user-chip guest" type="button" onClick={onAuth} aria-haspopup="dialog">
            <div className="meta" style={{ textAlign: "end" }}>
              <div className="nm">{lang === "fa" ? "کاربر مهمان" : lang === "ar" ? "مستخدم ضيف" : "Guest user"}</div>
              <div className="rl">{lang === "fa" ? "بدون ثبت‌نام" : lang === "ar" ? "بدون تسجيل" : "No account"}</div>
            </div>
            <div className="av guest"><Ic.user size={16} /></div>
          </button>
        </React.Fragment> :
        <button className="user-chip" type="button" onClick={() => {AudioCtl.click();onOpen("profile");}} aria-haspopup="dialog">
          <div className="meta" style={{ textAlign: "end" }}>
            <div className="nm">{session && session.displayName ? session.displayName : t.userName}</div>
            <div className="rl">{session && session.role === "lawyer" ? t.userRole : lang === "fa" ? "کاربر" : lang === "ar" ? "مستخدم" : "Member"}</div>
          </div>
          <div className="av">{(session && session.displayName ? session.displayName : "ح").slice(0, 1)}</div>
        </button>}
      </div>
    </div>);

};

const Sidebar = ({ lang, active, setActive, onOpen, open, onClose }) => {
  const t = T[lang];
  return (
    <React.Fragment>
      <div className={"sidebar-bd " + (open ? "open" : "")} onClick={onClose}></div>
      <aside className={"sidebar " + (open ? "open" : "")}>
      <div className="nav">
        {NAV.map((n) => {
            const Icon = Ic[n.iconKey] || Ic.chip;
            return (
              <button key={n.id} className={"nav-item" + (active === n.id ? " active" : "")}
              onClick={() => {AudioCtl.click();setActive(n.id);if (n.id !== "dashboard") onOpen(n.id);onClose && onClose();}}>
              <Icon size={16} className="ico" />
              <span className="lbl">
                {lang === "fa" ? n.fa : n.en}
                {n.isNew && <span className="tag-new">{t.new}</span>}
                {n.faSub && <span className="sub-lbl">{lang === "fa" ? n.faSub : n.enSub}</span>}
              </span>
              {active === n.id && <Ic.chevR size={14} />}
            </button>);

          })}
      </div>
      <div className="sidebar-ai">
        <div className="head">
          <div className="botico"><Ic.bot size={18} color="#04101C" /></div>
          <h4>{t.chatTitle}</h4>
        </div>
        <p>{t.chatSub}</p>
        <button onClick={() => {onOpen("aiChat");onClose && onClose();}}>{t.chatStart}</button>
      </div>
    </aside>
    </React.Fragment>);

};

const QuickActions = ({ lang, onOpen }) => {
  const t = T[lang];
  return (
    <div className="quick-actions">
      {QUICK.map((q) => {
        const Icon = Ic[q.iconKey] || Ic.chip;
        return (
          <button key={q.id} className="qa" onClick={() => onOpen(q.id)}>
            <div className="icoR"><Icon size={18} color="#EEF6FA" /></div>
            <div className="lbl">{t[q.faKey]}</div>
            {q.isNew && <div className="dot"></div>}
          </button>);

      })}
    </div>);

};

const ModuleGrid = ({ lang, onOpen }) => {
  const t = T[lang];
  return (
    <div className="panel" style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
      <div className="panel-head">
        <h3>{t.quickModules}</h3>
        <span className="more">{t.seeAll}</span>
      </div>
      <div className="module-grid">
        {QGRID.map((m) => {
          const Icon = Ic[m.iconKey] || Ic.chip;
          const isNew = ["whistle", "social", "reintegration"].includes(m.id);
          return (
            <button key={m.id} className={"mod " + (m.tint || "")} onClick={() => onOpen(m.id)} title={m[lang]}>
              <Icon size={20} className="ico" />
              <div className="lbl">{m[lang]}</div>
              {isNew && <div className="new"></div>}
            </button>);

        })}
      </div>
    </div>);

};

// ----- Social-proof preview for the dashboard -----
// This fixed dataset exists only to validate the interface before analytics is
// connected. It is labelled as preview data and must never be presented as live.
const SOCIAL_PROOF_PREVIEW = {
  mode: "ui-preview",
  periodDays: 30,
  visitors: 18640,
  toolUses: 12486,
  successfulTransactions: 618,
  breakdown: [
    { id: "ai-chat", value: 5284, iconKey: "bot" },
    { id: "calculators", value: 3946, iconKey: "calc" },
    { id: "other-tools", value: 3256, iconKey: "chip" },
  ],
};

const SOCIAL_PROOF_COPY = {
  fa: {
    kicker: "آمار استفاده",
    title: "شهداد در یک نگاه",
    period: "پیش‌نمایش ۳۰ روزه",
    visitors: "بازدیدکننده",
    toolUses: "بار استفاده از ابزارها",
    transactions: "خرید و پرداخت موفق",
    breakdownTitle: "محبوب‌ترین ابزارها",
    breakdown: {
      "ai-chat": "گفت‌وگو با دستیار",
      calculators: "محاسبات حقوقی",
      "other-tools": "ابزارهای دیگر",
    },
    provenance: "با شروع فعالیت، آمار واقعی همین‌جا نمایش داده می‌شود.",
  },
  ar: {
    kicker: "المؤشرات الرئيسية",
    title: "نبض استخدام شهداد",
    period: "نموذج ٣٠ يوماً",
    visitors: "زوار فريدون",
    toolUses: "استخدامات الأدوات",
    transactions: "معاملات ناجحة",
    breakdownTitle: "توزيع الاستخدام",
    breakdown: {
      "ai-chat": "محادثات الذكاء الاصطناعي",
      calculators: "الحاسبات القانونية",
      "other-tools": "أدوات أخرى",
    },
    provenance: "ستُستبدل الأرقام ببيانات حقيقية بعد ربط نظام التحليلات.",
  },
  en: {
    kicker: "Key metrics",
    title: "Shahdad usage pulse",
    period: "30-day sample",
    visitors: "Unique visitors",
    toolUses: "Tool uses",
    transactions: "Successful transactions",
    breakdownTitle: "Usage mix",
    breakdown: {
      "ai-chat": "AI conversations",
      calculators: "Legal calculations",
      "other-tools": "Other tools",
    },
    provenance: "Real analytics will replace these figures after tracking is connected.",
  },
};

const StatsCard = ({ lang }) => {
  const copy = SOCIAL_PROOF_COPY[lang] || SOCIAL_PROOF_COPY.en;
  const breakdownTotal = SOCIAL_PROOF_PREVIEW.breakdown.reduce((sum, item) => sum + item.value, 0);
  const stages = [
    { id: "visitors", value: SOCIAL_PROOF_PREVIEW.visitors, iconKey: "user", label: copy.visitors },
    { id: "tools", value: SOCIAL_PROOF_PREVIEW.toolUses, iconKey: "chip", label: copy.toolUses },
    { id: "transactions", value: SOCIAL_PROOF_PREVIEW.successfulTransactions, iconKey: "card", label: copy.transactions },
  ];

  return (
    <section
      className="panel stats-card stats-social-proof"
      aria-labelledby="social-proof-title"
      data-mode={SOCIAL_PROOF_PREVIEW.mode}
      data-breakdown-balanced={breakdownTotal === SOCIAL_PROOF_PREVIEW.toolUses ? "true" : "false"}
    >
      <header className="proof-head">
        <div>
          <span className="proof-kicker">{copy.kicker}</span>
          <h3 id="social-proof-title">{copy.title}</h3>
        </div>
        <span className="proof-period"><Ic.barchart size={13} />{copy.period}</span>
      </header>

      <div className="proof-flow">
        <div className="proof-track" aria-hidden="true"><i></i><i></i><i></i></div>
        <dl className="proof-stages" aria-label={copy.title}>
          {stages.map((stage) => {
            const Icon = Ic[stage.iconKey] || Ic.chip;
            return (
              <div className={`proof-stage is-${stage.id}`} key={stage.id}>
                <span className="proof-stage-icon" aria-hidden="true"><Icon size={14} /></span>
                <dt>{stage.label}</dt>
                <dd className="fa-num">{fmt(stage.value, lang)}</dd>
              </div>
            );
          })}
        </dl>
      </div>

      <section className="proof-mix" aria-labelledby="proof-mix-title">
        <header>
          <h4 id="proof-mix-title">{copy.breakdownTitle}</h4>
        </header>
        <div className="proof-mix-bar" aria-hidden="true">
          {SOCIAL_PROOF_PREVIEW.breakdown.map((item) => (
            <i
              className={`is-${item.id}`}
              key={item.id}
              style={{ "--proof-share": `${(item.value / SOCIAL_PROOF_PREVIEW.toolUses) * 100}%` }}
            ></i>
          ))}
        </div>
        <dl className="proof-legend">
          {SOCIAL_PROOF_PREVIEW.breakdown.map((item) => {
            const Icon = Ic[item.iconKey] || Ic.chip;
            return (
              <div className={`proof-legend-item is-${item.id}`} key={item.id}>
                <dt><span aria-hidden="true"><Icon size={12} /></span>{copy.breakdown[item.id]}</dt>
                <dd className="fa-num">{fmt(item.value, lang)}</dd>
              </div>
            );
          })}
        </dl>
      </section>

      <footer className="proof-provenance">
        <span className="proof-status" aria-hidden="true"><Ic.info size={12} /></span>
        <p>{copy.provenance}</p>
      </footer>
    </section>
  );
};

// ---------- Live Persian + Gregorian calendar driven by real time ----------
const useLiveTehranTime = () => {
  const [now, setNow] = React.useState(() => new Date());
  React.useEffect(() => {
    const id = setInterval(() => setNow(new Date()), 1000);
    return () => clearInterval(id);
  }, []);
  return now;
};

const persianParts = (d) => {
  // Use Intl with persian calendar; returns Jalali parts.
  const f = new Intl.DateTimeFormat("en-US-u-ca-persian", {
    timeZone: "Asia/Tehran",
    year: "numeric", month: "numeric", day: "numeric", weekday: "long"
  });
  const parts = Object.fromEntries(f.formatToParts(d).map((p) => [p.type, p.value]));
  return {
    year: parseInt(parts.year, 10),
    month: parseInt(parts.month, 10),
    day: parseInt(parts.day, 10),
    weekday: parts.weekday // Saturday … Friday (English names)
  };
};

const tehranTimeParts = (d) => {
  const f = new Intl.DateTimeFormat("en-GB", {
    timeZone: "Asia/Tehran", hour12: false,
    hour: "2-digit", minute: "2-digit", second: "2-digit"
  });
  const parts = Object.fromEntries(f.formatToParts(d).map((p) => [p.type, p.value]));
  return { h: parts.hour, m: parts.minute, s: parts.second };
};

// English weekday → 0=Sat … 6=Fri (Persian week starts Saturday)
const WD_TO_PIDX = { Saturday: 0, Sunday: 1, Monday: 2, Tuesday: 3, Wednesday: 4, Thursday: 5, Friday: 6 };

// Days in Persian month (Jalali rules: 1-6 = 31, 7-11 = 30, 12 = 29 or 30 in leap year)
const persianDaysInMonth = (year, month) => {
  if (month <= 6) return 31;
  if (month <= 11) return 30;
  // Esfand — leap-year approximation: cycle of 33-year intervals
  // Use a brute check: convert (year, 12, 29) and (year, 12, 30) back via Intl and see if valid.
  // Practical shortcut: known leap pattern (works for 2020s-2030s):
  const leaps = [1399, 1403, 1407, 1411, 1415, 1419, 1423, 1427, 1431, 1435];
  return leaps.includes(year) ? 30 : 29;
};

const PERSIAN_MONTH_NAMES_FA = ["فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند"];
const PERSIAN_MONTH_NAMES_EN = ["Farvardin", "Ordibehesht", "Khordad", "Tir", "Mordad", "Shahrivar", "Mehr", "Aban", "Azar", "Dey", "Bahman", "Esfand"];
const PERSIAN_MONTH_NAMES_AR = ["فروردين", "ارديبهشت", "خرداد", "تير", "مرداد", "شهريور", "مهر", "آبان", "آذر", "دي", "بهمن", "إسفند"];
const PERSIAN_DAY_INITIALS_FA = ["ش", "ی", "د", "س", "چ", "پ", "ج"];
const PERSIAN_DAY_INITIALS_EN = ["Sa", "Su", "Mo", "Tu", "We", "Th", "Fr"];
const PERSIAN_DAY_INITIALS_AR = ["سبت", "أحد", "اثن", "ثلا", "أرب", "خمي", "جمع"];
const MINI_PLAN_RGB = { task: "73,210,220", deadline: "255,127,132", hearing: "217,195,123", meeting: "217,195,123", reminder: "105,229,176" };
const MINI_PRIORITY = { low: 1, normal: 2, high: 3, critical: 4 };
function miniPlannerStorageKey(session) {
  const raw = session?.user?.email || session?.email || session?.user?.id || session?.userId || session?.displayName || (session?.localPreview ? "preview" : "guest");
  let hash = 2166136261;
  for (const character of String(raw).toLowerCase()) {
    hash ^= character.charCodeAt(0);
    hash = Math.imul(hash, 16777619);
  }
  return `shahdad.v31.planner.u-${(hash >>> 0).toString(36)}.v1`;
}
function readMiniPlanner(key) {
  try {
    const payload = JSON.parse(localStorage.getItem(key) || "null");
    if (!payload || !Array.isArray(payload.items)) return [];
    return payload.items.filter((item) => item && item.dueDate && !item.deletedAt && !item.archivedAt && !["done", "cancelled"].includes(item.status));
  } catch (error) {
    return [];
  }
}
function miniPlanCellStyle(items = []) {
  const colors = [...new Set(items.map((item) => MINI_PLAN_RGB[item.kind]).filter(Boolean))].slice(0, 3);
  if (!colors.length) return undefined;
  const fill = colors.length === 1
    ? `linear-gradient(145deg, rgba(${colors[0]},.76), rgba(${colors[0]},.34))`
    : `linear-gradient(135deg, ${colors.map((color, index) => `rgba(${color},${index === 0 ? ".76" : ".58"}) ${Math.round((index * 100) / (colors.length - 1))}%`).join(",")})`;
  return { "--mini-plan-rgb": colors[0], "--mini-plan-fill": fill };
}

const ClockCalCard = ({ lang, onOpen, session }) => {
  const t = T[lang];
  const now = useLiveTehranTime();
  const plannerKey = miniPlannerStorageKey(session);
  const [plannerTick, setPlannerTick] = React.useState(0);
  React.useEffect(() => {
    const refresh = (event) => {
      if (!event || !event.key || event.key === plannerKey) setPlannerTick((value) => value + 1);
    };
    const timer = window.setInterval(refresh, 2000);
    window.addEventListener("storage", refresh);
    window.addEventListener("focus", refresh);
    return () => {
      window.clearInterval(timer);
      window.removeEventListener("storage", refresh);
      window.removeEventListener("focus", refresh);
    };
  }, [plannerKey]);

  // Today's Persian date
  const today = persianParts(now);
  const time = tehranTimeParts(now);

  // Days in current Persian month
  const dim = persianDaysInMonth(today.year, today.month);

  // Find weekday-of-month-start: walk back (today.day - 1) days from "today" within Jalali
  const startWeekdayIdx = (() => {
    const todayWdIdx = WD_TO_PIDX[today.weekday] ?? 0;
    // (today.day - 1) days before today => start of month
    let idx = (todayWdIdx - (today.day - 1)) % 7;
    if (idx < 0) idx += 7;
    return idx;
  })();

  // Build 6-row grid
  const totalCells = 42;
  const cells = [];
  for (let i = 0; i < totalCells; i++) {
    const d = i - startWeekdayIdx + 1;
    cells.push(d >= 1 && d <= dim ? d : null);
  }
  // Trim trailing empty rows
  while (cells.length > 35 && cells.slice(-7).every((c) => c === null)) cells.length -= 7;

  const dows = lang === "fa" ? PERSIAN_DAY_INITIALS_FA : lang === "ar" ? PERSIAN_DAY_INITIALS_AR : PERSIAN_DAY_INITIALS_EN;
  const dg = (x) => lang === "fa" ? toFa(x) : lang === "ar" ? toAr(x) : String(x);

  // Header: month name + Jalali year + Gregorian short
  const monthName = lang === "fa" ? PERSIAN_MONTH_NAMES_FA[today.month - 1] : lang === "ar" ? PERSIAN_MONTH_NAMES_AR[today.month - 1] : PERSIAN_MONTH_NAMES_EN[today.month - 1];
  const yearFmt = lang === "fa" ? toFa(today.year) : lang === "ar" ? toAr(today.year) : today.year;
  const gregMonth = now.toLocaleString(lang === "fa" ? "fa-IR" : lang === "ar" ? "ar" : "en-US", { timeZone: "Asia/Tehran", month: "short", day: "numeric" });

  const timeFmt = `${dg(time.h)}:${dg(time.m)}:${dg(time.s)}`;

  const plansByDay = React.useMemo(() => {
    const grouped = {};
    readMiniPlanner(plannerKey).forEach((item) => {
      const date = new Date(`${item.dueDate}T12:00:00Z`);
      if (Number.isNaN(date.getTime())) return;
      const persian = persianParts(date);
      if (persian.year !== today.year || persian.month !== today.month) return;
      (grouped[persian.day] || (grouped[persian.day] = [])).push(item);
    });
    Object.values(grouped).forEach((items) => items.sort((a, b) => (MINI_PRIORITY[b.priority] || 0) - (MINI_PRIORITY[a.priority] || 0)));
    return grouped;
  }, [plannerKey, plannerTick, today.year, today.month]);

  return (
    <div className="panel cal-card clickable"
    role="button" tabIndex={0}
    title={lang === "fa" ? "باز کردن تقویم و جلسات" : lang === "ar" ? "فتح التقويم والجلسات" : "Open calendar & hearings"}
    onClick={() => onOpen && onOpen("clock")}
    onKeyDown={(e) => {if ((e.key === "Enter" || e.key === " ") && onOpen) {e.preventDefault();onOpen("clock");}}}>
      <div className="clock-row">
        <div className="clock-time fa-num">{timeFmt}</div>
        <div className="clock-tz">{lang === "fa" ? "تهران" : lang === "ar" ? "طهران" : "Tehran · IRST"}</div>
      </div>
      <div className="cal-head">
        <div className="m">
          {monthName} <span className="fa-num" style={{ opacity: 0.7 }}>{yearFmt}</span>
          <span style={{ fontSize: 9, opacity: 0.5, marginInlineStart: 6 }}>· {gregMonth}</span>
        </div>
        <div className="nav">
          <button><Ic.chevR size={12} /></button>
          <button><Ic.chevL size={12} /></button>
        </div>
      </div>
      <div className="cal-grid">
        {dows.map((d, i) => <div key={"h" + i} className="dow">{d}</div>)}
        {cells.map((d, i) => {
          if (d === null) return <div key={i} className="d mute"></div>;
          const dayPlans = plansByDay[d] || [];
          const planKinds = new Set(dayPlans.map((item) => item.kind));
          const cls = "d" + (d === today.day ? " today" : "") + (dayPlans.length ? " has-plan" : "");
          return <div key={i} className={cls} data-plan-kind={dayPlans[0]?.kind || undefined} data-mixed={planKinds.size > 1}
            style={miniPlanCellStyle(dayPlans)} title={dayPlans.length ? dayPlans.map((item) => item.title).join(" • ") : undefined}
            aria-label={`${dg(d)}${dayPlans.length ? `، ${dg(dayPlans.length)} برنامه` : ""}`}>{dg(d)}</div>;
        })}
      </div>
    </div>);

};

const CalCard = ({ lang, onOpen, session }) => {
  const t = T[lang];
  // Keep old static fallback only if Intl persian-calendar unsupported (very old browsers)
  try {
    new Intl.DateTimeFormat("en-US-u-ca-persian").format(new Date());
    return <ClockCalCard lang={lang} onOpen={onOpen} session={session} />;
  } catch (e) {
    const days = Array.from({ length: 35 }, (_, i) => {
      const d = i - CAL_OFFSET + 1;
      return d >= 1 && d <= CAL_DAYS ? d : null;
    });
    const dows = t.persianDays;
    return (
      <div className="panel">
        <div className="cal-head">
          <div className="m">{t.monthName}</div>
          <div className="nav">
            <button><Ic.chevR size={12} /></button>
            <button><Ic.chevL size={12} /></button>
          </div>
        </div>
        <div className="cal-grid">
          {dows.map((d, i) => <div key={"h" + i} className="dow">{d}</div>)}
          {days.map((d, i) => {
            if (d === null) return <div key={i} className="d mute"></div>;
            const cls = "d" + (d === CAL_TODAY ? " today" : "") + (d === CAL_SEL ? " sel" : "") + (CAL_EVENTS.includes(d) ? " has-event" : "");
            return <div key={i} className={cls}>{lang === "fa" ? toFa(d) : d}</div>;
          })}
        </div>
      </div>);

  }
};

// BottomNav removed per design update

window.TopBar = TopBar;
window.Sidebar = Sidebar;
window.QuickActions = QuickActions;
window.ModuleGrid = ModuleGrid;
window.StatsCard = StatsCard;
window.CalCard = CalCard;
