const { useState: useStateN, useEffect: useEffectN, useRef: useRefN, useMemo: useMemoN } = React;

// ── helpers ───────────────────────────────────────────────────────────────────

function fmtDateN(iso) {
  if (!iso) return '—';
  return new Date(iso).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
}

function fmtRelN(iso) {
  if (!iso) return '—';
  const diff = Date.now() - new Date(iso).getTime();
  const m = Math.floor(diff / 60000);
  if (m < 1) return 'just now';
  if (m < 60) return `${m}m ago`;
  const h = Math.floor(m / 60);
  if (h < 24) return `${h}h ago`;
  return `${Math.floor(h / 24)}d ago`;
}

const TARGET_OPTIONS = [
  { value: 'all',           label: 'All users',          description: 'Everyone with a push token' },
  { value: 'buyers',        label: 'Buyers',             description: 'Users with at least one order' },
  { value: 'sellers',       label: 'Sellers',            description: 'Users with the seller role' },
  { value: 'new_users',     label: 'New users',          description: 'Users who never placed an order' },
  { value: 'inactive_30d',  label: 'Lapsed (30d)',       description: 'Buyers inactive 30+ days' },
  { value: 'inactive_90d',  label: 'Churned (90d)',      description: 'Buyers inactive 90+ days' },
  { value: 'specific_user', label: 'Specific user',      description: 'Search and pick one person' },
];

// ── UserSearch ────────────────────────────────────────────────────────────────

const UserSearch = ({ selected, onSelect, onClear }) => {
  const I = window.Icons;
  const sb = window.supabaseClient;
  const [query, setQuery] = useStateN('');
  const [results, setResults] = useStateN([]);
  const [searching, setSearching] = useStateN(false);
  const timer = useRefN(null);

  const search = (q) => {
    if (timer.current) clearTimeout(timer.current);
    if (!q.trim()) { setResults([]); return; }
    timer.current = setTimeout(async () => {
      setSearching(true);
      const { data } = await sb
        .from('user_profiles')
        .select('id, display_name, username, phone, avatar_url')
        .or(`display_name.ilike.%${q}%,username.ilike.%${q}%,phone.ilike.%${q}%`)
        .limit(8);
      setResults(data || []);
      setSearching(false);
    }, 300);
  };

  if (selected) {
    return (
      <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '8px 12px', border: '1px solid var(--ink)', borderRadius: 6, background: 'var(--surface-2)' }}>
        <div style={{ width: 28, height: 28, borderRadius: '50%', background: 'var(--surface-3)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, overflow: 'hidden' }}>
          {selected.avatar_url
            ? <img src={selected.avatar_url} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
            : <span style={{ fontSize: 11, fontWeight: 600, color: 'var(--ink-2)' }}>{(selected.display_name ?? selected.username ?? '?')[0].toUpperCase()}</span>
          }
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13, fontWeight: 500, color: 'var(--ink)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{selected.display_name ?? selected.username}</div>
          {selected.phone && <div style={{ fontSize: 11, color: 'var(--ink-3)' }}>{selected.phone}</div>}
        </div>
        <button onClick={onClear} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--ink-3)', padding: 2, display: 'flex' }}>
          <I.x size={14} />
        </button>
      </div>
    );
  }

  return (
    <div style={{ position: 'relative' }}>
      <div style={{ position: 'relative' }}>
        <I.search size={13} style={{ position: 'absolute', left: 10, top: '50%', transform: 'translateY(-50%)', color: 'var(--ink-3)', pointerEvents: 'none' }} />
        <input
          style={{ width: '100%', boxSizing: 'border-box', padding: '7px 12px 7px 32px', fontSize: 13, borderRadius: 6, border: '1px solid var(--hairline)', background: 'var(--surface-2)', color: 'var(--ink)', outline: 'none', fontFamily: 'var(--font-sans)' }}
          placeholder="Name, username or phone…"
          value={query}
          onChange={e => { setQuery(e.target.value); search(e.target.value); }}
        />
      </div>
      {(results.length > 0 || searching || (query && !searching)) && (
        <div style={{ position: 'absolute', zIndex: 20, marginTop: 4, width: '100%', background: 'var(--surface)', border: '1px solid var(--hairline)', borderRadius: 6, boxShadow: '0 4px 16px rgba(0,0,0,0.12)', overflow: 'hidden' }}>
          {searching && <div style={{ padding: '8px 12px', fontSize: 12, color: 'var(--ink-3)' }}>Searching…</div>}
          {results.map(u => (
            <button
              key={u.id}
              onClick={() => { onSelect(u); setQuery(''); setResults([]); }}
              style={{ width: '100%', display: 'flex', alignItems: 'center', gap: 10, padding: '8px 12px', background: 'none', border: 'none', cursor: 'pointer', textAlign: 'left' }}
              onMouseEnter={e => e.currentTarget.style.background = 'var(--surface-2)'}
              onMouseLeave={e => e.currentTarget.style.background = 'none'}
            >
              <div style={{ width: 28, height: 28, borderRadius: '50%', background: 'var(--surface-3)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, overflow: 'hidden' }}>
                {u.avatar_url
                  ? <img src={u.avatar_url} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
                  : <span style={{ fontSize: 11, fontWeight: 600, color: 'var(--ink-2)' }}>{(u.display_name ?? u.username ?? '?')[0].toUpperCase()}</span>
                }
              </div>
              <div style={{ minWidth: 0 }}>
                <div style={{ fontSize: 13, fontWeight: 500, color: 'var(--ink)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{u.display_name ?? u.username}</div>
                <div style={{ fontSize: 11, color: 'var(--ink-3)' }}>{u.username && `@${u.username}`}{u.phone && ` · ${u.phone}`}</div>
              </div>
            </button>
          ))}
          {!searching && results.length === 0 && query && (
            <div style={{ padding: '8px 12px', fontSize: 12, color: 'var(--ink-3)' }}>No users found</div>
          )}
        </div>
      )}
    </div>
  );
};

// ── NotifPreview ──────────────────────────────────────────────────────────────

const NotifPreview = ({ title, body, targetLabel }) => (
  <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12, padding: '12px 14px', background: 'var(--surface-2)', border: '1px solid var(--hairline)', borderRadius: 12, maxWidth: 340 }}>
    <div style={{ width: 32, height: 32, borderRadius: 8, background: 'var(--ink)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0, marginTop: 2 }}>
      <span style={{ color: 'var(--paper)', fontWeight: 700, fontSize: 13 }}>P</span>
    </div>
    <div style={{ minWidth: 0 }}>
      <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--ink-3)', fontFamily: 'var(--font-mono)' }}>Pipal · {targetLabel}</div>
      <div style={{ fontSize: 13, fontWeight: 600, color: 'var(--ink)', marginTop: 2, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{title}</div>
      <div style={{ fontSize: 12, color: 'var(--ink-2)', marginTop: 2, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' }}>{body}</div>
    </div>
  </div>
);

// ── HistoryTable ──────────────────────────────────────────────────────────────

const HistoryTable = ({ history, loading }) => {
  if (loading) {
    return <div style={{ padding: '32px', textAlign: 'center', color: 'var(--ink-3)', fontSize: 13 }}>Loading…</div>;
  }
  if (!history.length) {
    return <div style={{ padding: '40px', textAlign: 'center', color: 'var(--ink-3)', fontSize: 13 }}>No notifications sent yet</div>;
  }
  return (
    <div className="t-wrap">
      <table className="t">
        <thead>
          <tr>
            <th>Title</th>
            <th>Message</th>
            <th>Target</th>
            <th style={{ textAlign: 'right' }}>Sent to</th>
            <th style={{ textAlign: 'right' }}>Sent</th>
          </tr>
        </thead>
        <tbody>
          {history.map(c => (
            <tr key={c.id}>
              <td style={{ fontWeight: 500, fontSize: 13, color: 'var(--ink)' }}>{c.title}</td>
              <td style={{ color: 'var(--ink-2)', fontSize: 12.5, maxWidth: 260 }}>
                <span style={{ display: 'block', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                  {c.body}
                </span>
              </td>
              <td><span className="chip">{TARGET_OPTIONS.find(o => o.value === c.target)?.label ?? c.target}</span></td>
              <td className="num" style={{ textAlign: 'right' }}>{c.sent_count.toLocaleString()}</td>
              <td style={{ textAlign: 'right', fontSize: 12, color: 'var(--ink-3)', fontFamily: 'var(--font-mono)' }} title={fmtDateN(c.created_at)}>{fmtRelN(c.created_at)}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
};

// ── NotificationsPage ─────────────────────────────────────────────────────────

const NotificationsPage = () => {
  const I = window.Icons;
  const sb = window.supabaseClient;

  // compose state
  const [title, setTitle]           = useStateN('');
  const [body, setBody]             = useStateN('');
  const [target, setTarget]         = useStateN('all');
  const [selectedUser, setSelectedUser] = useStateN(null);
  const [showPreview, setShowPreview]   = useStateN(false);
  const [sending, setSending]       = useStateN(false);
  const [error, setError]           = useStateN(null);

  // history state
  const [history, setHistory]       = useStateN([]);
  const [loadingHistory, setLoadingHistory] = useStateN(true);

  // toast
  const [toast, setToast]           = useStateN(null);

  // stats
  const [stats, setStats]           = useStateN({ total: 0, last7d: 0, totalReach: 0 });

  const showToast = (msg, ok = true) => {
    setToast({ msg, ok });
    setTimeout(() => setToast(null), 3000);
  };

  const loadHistory = async () => {
    setLoadingHistory(true);
    const { data } = await sb
      .from('user_notifications')
      .select('id, title, body, data, created_at')
      .eq('type', 'promotional')
      .order('created_at', { ascending: false })
      .limit(50);

    if (data) {
      const seen = new Set();
      const campaigns = [];
      for (const row of data) {
        const key = `${row.title}|${row.body}|${row.created_at?.slice(0, 16)}`;
        if (!seen.has(key)) {
          seen.add(key);
          campaigns.push({
            id: row.id,
            title: row.title,
            body: row.body,
            target: row.data?.target ?? 'all',
            sent_count: row.data?.sent_count ?? 1,
            created_at: row.created_at,
          });
        }
      }

      setHistory(campaigns);

      const now = Date.now();
      const last7d = campaigns.filter(c => (now - new Date(c.created_at).getTime()) < 7 * 86400000).length;
      const totalReach = campaigns.reduce((s, c) => s + c.sent_count, 0);
      setStats({ total: campaigns.length, last7d, totalReach });
    }
    setLoadingHistory(false);
  };

  useEffectN(() => { if (sb) loadHistory(); }, []);

  const resolveUserIds = async () => {
    if (target === 'specific_user') {
      if (!selectedUser) throw new Error('Select a user first');
      return [selectedUser.id];
    }

    if (target === 'all') {
      const { data } = await sb.from('user_push_tokens').select('user_id');
      return [...new Set((data || []).map(r => r.user_id))];
    }

    if (target === 'sellers') {
      const { data: profiles } = await sb.from('user_profiles').select('id').eq('role', 'seller');
      const sellerIds = new Set((profiles || []).map(r => r.id));
      const { data: tokens } = await sb.from('user_push_tokens').select('user_id');
      return [...new Set((tokens || []).map(r => r.user_id).filter(id => sellerIds.has(id)))];
    }

    if (target === 'buyers') {
      const { data: orders } = await sb.from('orders').select('buyer_id').neq('order_status', 'cancelled');
      const buyerIds = new Set((orders || []).map(r => r.buyer_id));
      const { data: tokens } = await sb.from('user_push_tokens').select('user_id');
      return [...new Set((tokens || []).map(r => r.user_id).filter(id => buyerIds.has(id)))];
    }

    // new_users / inactive_30d / inactive_90d
    const { data: orders } = await sb.from('orders').select('buyer_id, created_at').neq('order_status', 'cancelled');
    const buyerLastOrder = new Map();
    for (const o of orders || []) {
      const d = new Date(o.created_at);
      const prev = buyerLastOrder.get(o.buyer_id);
      if (!prev || d > prev) buyerLastOrder.set(o.buyer_id, d);
    }
    const { data: tokens } = await sb.from('user_push_tokens').select('user_id');
    const tokenIds = [...new Set((tokens || []).map(r => r.user_id))];
    const now = new Date();

    if (target === 'new_users') {
      return tokenIds.filter(id => !buyerLastOrder.has(id));
    }
    if (target === 'inactive_30d') {
      return tokenIds.filter(id => {
        const last = buyerLastOrder.get(id);
        return last && (now - last) / 86400000 >= 30;
      });
    }
    // inactive_90d
    return tokenIds.filter(id => {
      const last = buyerLastOrder.get(id);
      return last && (now - last) / 86400000 >= 90;
    });
  };

  const handleSend = async () => {
    if (!title.trim()) { setError('Title is required'); return; }
    if (!body.trim())  { setError('Message body is required'); return; }
    setError(null);
    setSending(true);

    try {
      const userIds = await resolveUserIds();

      if (userIds.length === 0) {
        setError('No users found for this target segment');
        setSending(false);
        return;
      }

      const rows = userIds.map(userId => ({
        user_id: userId,
        type: 'promotional',
        title: title.trim(),
        body: body.trim(),
        data: { target, sent_count: userIds.length },
        read: false,
        created_at: new Date().toISOString(),
      }));

      for (let i = 0; i < rows.length; i += 100) {
        const { error: dbErr } = await sb.from('user_notifications').insert(rows.slice(i, i + 100));
        if (dbErr) throw new Error(dbErr.message);
      }

      showToast(`Sent to ${userIds.length.toLocaleString()} user${userIds.length !== 1 ? 's' : ''}`);
      setTitle('');
      setBody('');
      setShowPreview(false);
      loadHistory();
    } catch (err) {
      setError(err.message ?? 'Failed to send');
    } finally {
      setSending(false);
    }
  };

  const selectedTargetOption = TARGET_OPTIONS.find(o => o.value === target);

  return (
    <div className="page" data-screen-label="Notifications">

      {/* Toast */}
      {toast && (
        <div style={{
          position: 'fixed', bottom: 24, left: '50%', transform: 'translateX(-50%)',
          zIndex: 200, padding: '10px 18px', borderRadius: 8,
          background: toast.ok ? 'var(--ink)' : 'var(--neg)',
          color: '#fff', fontSize: 13, fontWeight: 500, boxShadow: '0 4px 16px rgba(0,0,0,0.18)',
          pointerEvents: 'none',
        }}>{toast.msg}</div>
      )}

      {/* Header */}
      <div className="page-h">
        <div>
          <div className="ts">{stats.last7d} campaigns last 7 days · {stats.totalReach.toLocaleString()} total reach</div>
          <h1>Notifications</h1>
        </div>
      </div>

      {/* KPIs */}
      <div className="kpi-grid" style={{ gridTemplateColumns: 'repeat(3,1fr)' }}>
        <div className="kpi">
          <div className="lbl">Campaigns sent</div>
          <div className="val">{stats.total}</div>
          <div className="sub"><span className="muted">{stats.last7d} this week</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">Total reach</div>
          <div className="val">{stats.totalReach >= 1000 ? (stats.totalReach / 1000).toFixed(1) + 'k' : stats.totalReach}</div>
          <div className="sub"><span className="muted">unique notification rows</span></div>
        </div>
        <div className="kpi">
          <div className="lbl">Target segments</div>
          <div className="val">{TARGET_OPTIONS.length - 1}</div>
          <div className="sub"><span className="muted">+ individual user targeting</span></div>
        </div>
      </div>

      {/* Compose */}
      <div className="panel" style={{ marginTop: 14, overflow: 'hidden' }}>
        <div className="panel-h">
          <I.bell size={13} style={{ color: 'var(--ink-3)', marginRight: 6 }} />
          <span>Compose notification</span>
        </div>

        <div style={{ padding: 16, display: 'flex', flexDirection: 'column', gap: 16 }}>

          {/* Target grid */}
          <div>
            <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--ink-3)', letterSpacing: '0.06em', textTransform: 'uppercase', marginBottom: 8 }}>Target audience</div>
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(140px, 1fr))', gap: 8 }}>
              {TARGET_OPTIONS.map(opt => (
                <button
                  key={opt.value}
                  onClick={() => {
                    setTarget(opt.value);
                    if (opt.value !== 'specific_user') setSelectedUser(null);
                  }}
                  style={{
                    textAlign: 'left', padding: '8px 10px', borderRadius: 6, cursor: 'pointer',
                    border: target === opt.value ? '1px solid var(--ink)' : '1px solid var(--hairline)',
                    background: target === opt.value ? 'var(--surface-2)' : 'var(--surface)',
                    boxShadow: target === opt.value ? 'inset 0 0 0 1px var(--ink)' : 'none',
                    transition: 'border-color 0.1s',
                  }}
                >
                  <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--ink)' }}>{opt.label}</div>
                  <div style={{ fontSize: 11, color: 'var(--ink-3)', marginTop: 2 }}>{opt.description}</div>
                </button>
              ))}
            </div>
          </div>

          {/* User search */}
          {target === 'specific_user' && (
            <div>
              <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--ink-3)', letterSpacing: '0.06em', textTransform: 'uppercase', marginBottom: 8 }}>Search user</div>
              <UserSearch
                selected={selectedUser}
                onSelect={setSelectedUser}
                onClear={() => setSelectedUser(null)}
              />
            </div>
          )}

          {/* Title + body */}
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
            <div>
              <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--ink-3)', letterSpacing: '0.06em', textTransform: 'uppercase', marginBottom: 6 }}>Title <span style={{ color: 'var(--ink-3)', fontWeight: 400 }}>{title.length}/65</span></div>
              <input
                style={{ width: '100%', boxSizing: 'border-box', padding: '7px 10px', fontSize: 13, borderRadius: 6, border: '1px solid var(--hairline)', background: 'var(--surface-2)', color: 'var(--ink)', outline: 'none', fontFamily: 'var(--font-sans)' }}
                placeholder="e.g. Happy New Year 🎉"
                value={title}
                onChange={e => setTitle(e.target.value)}
                maxLength={65}
              />
            </div>
            <div>
              <div style={{ fontSize: 10, fontFamily: 'var(--font-mono)', color: 'var(--ink-3)', letterSpacing: '0.06em', textTransform: 'uppercase', marginBottom: 6 }}>Message <span style={{ color: 'var(--ink-3)', fontWeight: 400 }}>{body.length}/180</span></div>
              <textarea
                style={{ width: '100%', boxSizing: 'border-box', padding: '7px 10px', fontSize: 13, borderRadius: 6, border: '1px solid var(--hairline)', background: 'var(--surface-2)', color: 'var(--ink)', outline: 'none', fontFamily: 'var(--font-sans)', resize: 'none', height: 64 }}
                placeholder="e.g. Enjoy 10% off all orders today."
                value={body}
                onChange={e => setBody(e.target.value)}
                maxLength={180}
              />
            </div>
          </div>

          {/* Preview */}
          {showPreview && title && body && (
            <NotifPreview title={title} body={body} targetLabel={selectedTargetOption?.label ?? target} />
          )}

          {/* Error */}
          {error && (
            <div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 12.5, color: 'var(--neg)' }}>
              <I.warn size={13} /> {error}
            </div>
          )}

          {/* Actions */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <button
              className="btn primary"
              onClick={handleSend}
              disabled={sending}
              style={{ gap: 6 }}
            >
              <I.bell size={12} />
              {sending ? 'Sending…' : `Send to ${selectedTargetOption?.label?.toLowerCase() ?? target}`}
            </button>
            <button
              className="btn"
              onClick={() => setShowPreview(p => !p)}
            >
              {showPreview ? 'Hide preview' : 'Preview'}
            </button>
          </div>
        </div>
      </div>

      {/* History */}
      <div className="panel" style={{ marginTop: 14, overflow: 'hidden' }}>
        <div className="panel-h">
          <span>Recent campaigns</span>
          <button className="btn right" style={{ height: 26, fontSize: 11 }} onClick={loadHistory}>
            <I.refresh size={11} /> Refresh
          </button>
        </div>
        <HistoryTable history={history} loading={loadingHistory} />
      </div>
    </div>
  );
};

window.NotificationsPage = NotificationsPage;
