// PromoSubscribers.jsx — read-only dashboard listing every
// promo_customers row. Status is derived from last_fetched_at:
//
//   Active        polled within the last 7 days
//   Lapsed        polled, but not in the last 7 days
//   Never synced  subscribed, but the customer never finished adding
//                 the URL to their calendar app (no poll yet)
//
// No PII to display — the customer model is anonymous. The auto-
// assigned label ("Customer 0001") is the only identifier.

const SUBSCRIBE_URL = 'https://promo-calendar.snap-a-box.com';

const PromoSubscribers = () => {
  const [rows, setRows] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    if (!window.supa) return;
    let cancelled = false;
    const load = async () => {
      const { data, error } = await window.supa.from('promo_customers')
        .select('token, display_label, source, created_at, last_fetched_at, fetch_count, last_user_agent, last_country, last_region, last_city')
        .eq('restaurant_id', window.RESTAURANT_ID)
        .order('created_at', { ascending: false });
      if (cancelled) return;
      if (error) {
        console.error('promo_customers load failed', error);
        setRows([]);
      } else {
        setRows(data || []);
      }
      setLoading(false);
    };
    load();
    // Live updates: new subscribers + fetch bumps both arrive via
    // realtime so the dashboard reflects activity without manual reload.
    const ch = window.supa
      .channel('portal-promo-customers:' + window.RESTAURANT_ID)
      .on('postgres_changes', {
        event: '*', schema: 'public', table: 'promo_customers',
        filter: 'restaurant_id=eq.' + window.RESTAURANT_ID,
      }, () => load())
      .subscribe();
    return () => { cancelled = true; window.supa.removeChannel(ch); };
  }, []);

  // Only synced subscribers show in the table — a "Never synced" row
  // means the customer started the subscribe flow but never finished
  // adding the URL to their calendar app, which is noise rather than
  // signal for the admin.
  const visibleRows = useMemo(
    () => rows.filter(r => !!r.last_fetched_at),
    [rows],
  );

  const counts = useMemo(() => {
    const now = Date.now();
    const week = 7 * 24 * 60 * 60 * 1000;
    let active = 0, lapsed = 0;
    visibleRows.forEach(r => {
      if (now - new Date(r.last_fetched_at).getTime() <= week) active += 1;
      else lapsed += 1;
    });
    return { active, lapsed, total: visibleRows.length };
  }, [visibleRows]);

  const copyShareUrl = async () => {
    try {
      await navigator.clipboard.writeText(SUBSCRIBE_URL);
    } catch {}
  };

  return (
    <div className="portal-page-wide" style={{ maxWidth: 1080 }}>
      <div className="portal-page-header">
        <div>
          <h1 className="portal-page-title">Promo Subscribers</h1>
          <div className="portal-page-subtitle">
            Anonymous tokens, auto-labeled "Customer NNNN" on subscribe. Counts here are derived
            from the .ics polling cadence — iOS polls roughly hourly when synced.
          </div>
        </div>
      </div>

      {/* Share link + summary stat row */}
      <div style={{ display: 'flex', gap: 12, marginBottom: 16, flexWrap: 'wrap' }}>
        <div style={{
          flex: '1 1 360px', minWidth: 0,
          background: 'var(--bg-surface)', border: '1px solid var(--border-2)',
          borderRadius: 12, padding: '14px 16px',
          display: 'flex', alignItems: 'center', gap: 12,
        }}>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 11, fontWeight: 500, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'var(--fg-3)', marginBottom: 4 }}>
              Share this link
            </div>
            <div style={{
              fontFamily: 'var(--font-num)', fontSize: 13, color: 'var(--fg-1)',
              whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
            }}>{SUBSCRIBE_URL}</div>
          </div>
          <PBtn variant="secondary" size="sm" onClick={copyShareUrl}>Copy</PBtn>
          <a href={SUBSCRIBE_URL} target="_blank" rel="noreferrer">
            <PBtn variant="secondary" size="sm">Open</PBtn>
          </a>
        </div>

        <StatChip label="Total" value={counts.total} />
        <StatChip label="Active" value={counts.active} accent="#16A34A" />
        <StatChip label="Lapsed" value={counts.lapsed} accent="#CA8A04" />
      </div>

      <div className="portal-card" style={{ padding: 0 }}>
        <table className="portal-table">
          <thead>
            <tr>
              <th>Subscriber</th>
              <th style={{ width: 110 }}>Status</th>
              <th style={{ width: 130 }}>Subscribed</th>
              <th style={{ width: 130 }}>Last synced</th>
              <th style={{ width: 140 }}>Device</th>
              <th style={{ width: 180 }}>Location</th>
            </tr>
          </thead>
          <tbody>
            {loading ? (
              <tr><td colSpan={6} style={{ padding: 40, textAlign: 'center', color: 'var(--fg-3)', fontSize: 13 }}>Loading…</td></tr>
            ) : visibleRows.length === 0 ? (
              <tr><td colSpan={6} style={{ padding: 40, textAlign: 'center', color: 'var(--fg-3)', fontSize: 13 }}>
                {rows.length === 0
                  ? 'No subscribers yet. Share the link above and check back here.'
                  : 'No synced subscribers yet — customers have started the subscribe flow but their calendar apps haven\'t polled the feed.'}
              </td></tr>
            ) : visibleRows.map(r => (
              <SubscriberRow key={r.token} row={r} />
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
};

const SubscriberRow = ({ row }) => {
  const status = subscriberStatus(row);
  const device = parseDevice(row.last_user_agent);
  const isGoogleFetch = device.isGoogle;
  const location = formatLocation(row);
  return (
    <tr>
      <td>
        <span style={{
          fontWeight: 500, fontSize: 14,
          fontFamily: 'var(--font-num)',
          letterSpacing: '0.04em',
        }}>
          {/* Drop the "Customer " prefix and just show the number
              (auto-labeled "Customer 0001" → "0001"). Falls back to a
              short token slice for the unlikely no-label case. */}
          {(row.display_label || '').replace(/^Customer\s+/i, '') || row.token.slice(0, 8)}
        </span>
      </td>
      <td>
        <span style={{
          display: 'inline-block',
          padding: '3px 9px',
          background: status.bg,
          color: status.fg,
          borderRadius: 999,
          fontSize: 11.5,
          fontWeight: 600,
        }}>{status.label}</span>
      </td>
      <td style={{ fontSize: 12.5, color: 'var(--fg-2)', fontFamily: 'var(--font-num)' }}>
        {formatRelative(row.created_at)}
      </td>
      <td style={{ fontSize: 12.5, color: 'var(--fg-2)', fontFamily: 'var(--font-num)' }}>
        {formatRelative(row.last_fetched_at)}
      </td>
      <td style={{ fontSize: 12.5, color: 'var(--fg-2)' }} title={row.last_user_agent || ''}>
        {device.label}
      </td>
      <td style={{ fontSize: 12.5, color: 'var(--fg-2)' }}>
        {location
          ? <>
              {location}
              {isGoogleFetch && (
                <span title="Google Calendar fetches the .ics from its own servers, so this location is Google's data center — not the customer's." style={{ marginLeft: 6, fontSize: 10.5, color: 'var(--fg-3)', fontStyle: 'italic' }}>
                  (Google sync)
                </span>
              )}
            </>
          : <span style={{ color: 'var(--fg-3)' }}>—</span>}
      </td>
    </tr>
  );
};

// User-Agent → friendly device label. Heuristic; stored UA is kept on
// the row so we can refine the rules without touching the DB. The
// `isGoogle` flag lets the location column note that the IP/geo is
// Google's data center, not the customer's device.
function parseDevice(ua) {
  if (!ua) return { label: '—', isGoogle: false };
  const s = String(ua);
  if (/Google-Calendar-Importer|GoogleCalendar/i.test(s))            return { label: 'Google sync',   isGoogle: true };
  if (/iPad/i.test(s))                                                return { label: 'iPad',          isGoogle: false };
  if (/iPhone/i.test(s))                                              return { label: 'iPhone',        isGoogle: false };
  if (/CalendarAgent.*Mac OS X|Mac OS X.*CalendarAgent|Macintosh/i.test(s)) return { label: 'Mac',     isGoogle: false };
  if (/iOS|dataaccessd/i.test(s))                                     return { label: 'iOS device',    isGoogle: false };
  if (/Android/i.test(s))                                             return { label: 'Android',       isGoogle: false };
  if (/ICSx5|DAVx5/i.test(s))                                         return { label: 'ICSx5',         isGoogle: false };
  if (/Outlook|Microsoft/i.test(s))                                   return { label: 'Outlook',       isGoogle: false };
  return { label: 'Other', isGoogle: false };
}

function formatLocation(row) {
  const parts = [row.last_city, row.last_region, row.last_country].filter(Boolean);
  return parts.length === 0 ? '' : parts.join(', ');
}

const StatChip = ({ label, value, accent }) => (
  <div style={{
    background: 'var(--bg-surface)', border: '1px solid var(--border-2)',
    borderRadius: 12, padding: '10px 14px',
    minWidth: 110,
  }}>
    <div style={{ fontSize: 10.5, fontWeight: 500, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'var(--fg-3)' }}>
      {label}
    </div>
    <div style={{
      fontSize: 22, fontWeight: 600, fontFamily: 'var(--font-num)',
      color: accent || 'var(--fg-1)', letterSpacing: '-0.01em', marginTop: 2,
    }}>{value}</div>
  </div>
);

function subscriberStatus(row) {
  if (!row.last_fetched_at) return { label: 'Never synced', bg: 'var(--bg-sunken)', fg: 'var(--fg-3)' };
  const age = Date.now() - new Date(row.last_fetched_at).getTime();
  const week = 7 * 24 * 60 * 60 * 1000;
  if (age <= week) return { label: 'Active', bg: '#DCFCE7', fg: '#166534' };
  return { label: 'Lapsed', bg: '#FEF3C7', fg: '#92400E' };
}

function formatRelative(iso) {
  if (!iso) return '';
  const d = new Date(iso);
  const diff = Date.now() - d.getTime();
  const mins = Math.round(diff / 60000);
  if (mins < 60)      return mins <= 1 ? 'just now' : `${mins}m ago`;
  const hrs = Math.round(mins / 60);
  if (hrs < 24)       return `${hrs}h ago`;
  const days = Math.round(hrs / 24);
  if (days < 30)      return `${days}d ago`;
  return d.toLocaleDateString([], { month: 'short', day: 'numeric', year: 'numeric' });
}

window.PromoSubscribers = PromoSubscribers;
