// Influencer Detail — deep dive into a single influencer's performance
const { useState: useStateID } = React;

const idFmt = (n) => (window.PulseStore ? window.PulseStore.fmt(n) : PULSE.fmt(n));
const idNum = (n) => {
  const value = Number(n);
  return Number.isFinite(value) ? Math.max(0, value) : 0;
};
const idEng = (p) => idNum(p.likes) + idNum(p.comments) + idNum(p.shares);
const idPct = (a, b) => b ? Math.round((a / b) * 100) : 0;
const idSafeDate = (value) => {
  if (!value) return null;
  const d = new Date(value);
  return Number.isNaN(d.getTime()) ? null : d;
};
const idShortDate = (value) => {
  const d = idSafeDate(value);
  return d ? `${String(d.getDate()).padStart(2, '0')}/${String(d.getMonth() + 1).padStart(2, '0')}` : '—';
};
const idDateTime = (value) => {
  if (typeof value === 'string' && value.length >= 16) return value.slice(0, 16).replace('T', ' ');
  const d = idSafeDate(value);
  if (!d) return '—';
  return `${d.toISOString().slice(0, 10)} ${d.toISOString().slice(11, 16)}`;
};
const idIsCountablePost = (post) => !!post.url && !['missing_url', 'not_found', 'private_or_removed', 'error'].includes(post.pullStatus);
const idIsStalePost = (post) => {
  const staleAfterHours = +(window.PulseStore?.getSyncStatus()?.staleAfterHours || 6);
  const d = idSafeDate(post.lastPulledAt);
  return !d || (Date.now() - d.getTime()) > staleAfterHours * 60 * 60 * 1000;
};
const idPostStatus = (post) => {
  if (post.pullStatus === 'missing_url' || !post.url) return { label: 'Missing URL', tone: 'warn', icon: 'alert' };
  if (post.pullStatus === 'not_found') return { label: 'Not found', tone: 'warn', icon: 'alert' };
  if (post.pullStatus === 'private_or_removed') return { label: 'Private/removed', tone: 'warn', icon: 'eye-off' };
  if (post.pullStatus === 'rate_limited') return { label: 'Rate limited', tone: 'amber', icon: 'refresh' };
  if (post.pullStatus === 'error') return { label: 'Error', tone: 'warn', icon: 'alert' };
  if (post.pullStatus === 'pending') return { label: 'Pending pull', tone: 'amber', icon: 'refresh' };
  if (post.metricsScope === 'profile_list_limited') return { label: 'Metric limited', tone: 'amber', icon: 'alert' };
  if (idIsStalePost(post)) return { label: 'Stale', tone: 'amber', icon: 'refresh' };
  return { label: 'Pulled', tone: 'ok', icon: 'check' };
};
const idThumbnailSrc = (url) => {
  if (!url) return '';
  if (typeof window === 'undefined' || window.location.protocol === 'file:') return url;
  const apiStatus = window.PulseStore?.getApiStatus ? window.PulseStore.getApiStatus() : { enabled: false, baseUrl: '' };
  const canUseLocalProxy = ['127.0.0.1', 'localhost'].includes(window.location.hostname);
  if (!apiStatus.enabled && !canUseLocalProxy) return url;
  try {
    const parsed = new URL(url, window.location.href);
    if (!['http:', 'https:'].includes(parsed.protocol)) return url;
    const baseUrl = ((apiStatus.enabled && apiStatus.baseUrl) || window.location.origin || '').replace(/\/$/, '');
    return `${baseUrl}/api/media-proxy?url=${encodeURIComponent(parsed.toString())}`;
  } catch (err) {
    return url;
  }
};
const idPlatformName = (platform) => {
  const key = String(platform || '').toLowerCase();
  if (key === 'tiktok') return 'TikTok';
  if (key === 'instagram') return 'Instagram';
  if (key === 'facebook') return 'Facebook';
  return 'Social';
};
const idExternalUrl = (value) => {
  if (!value) return '';
  try {
    const parsed = new URL(value, window.location.href);
    return ['http:', 'https:', 'mailto:'].includes(parsed.protocol) ? parsed.toString() : '';
  } catch (err) {
    return '';
  }
};
const idProfileUrlFor = (inf, posts) => {
  const explicit = idExternalUrl(inf.profileUrl || inf.profileURL || inf.profile || inf.url);
  if (explicit) return explicit;
  const firstPost = (posts || []).find(p => idExternalUrl(p.url));
  return firstPost ? idExternalUrl(firstPost.url) : '';
};
const idEmailFor = (inf) => {
  const email = String(inf.contactEmail || inf.email || '').trim();
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email) ? email : '';
};

const InfluencerDetail = () => {
  const isMobile = useIsMobile();
  const requestedId = window.getQueryParam ? window.getQueryParam('id', '') : '';
  const requestedCampaignId = window.getQueryParam ? (window.getQueryParam('campaignId', '') || window.getQueryParam('campaign', '')) : '';
  const allBookings = window.PulseStore ? window.PulseStore.getBookings() : [];
  const defaultBooking = allBookings[2] || allBookings[0];
  const baseInfluencer = window.PulseStore
    ? (window.PulseStore.getInfluencer(requestedId) || window.PulseStore.getInfluencer(defaultBooking?.influencerId))
    : PULSE.influencers[2];
  const currentBooking = allBookings.find(b => b.influencerId === baseInfluencer?.id && (!requestedCampaignId || b.campaignId === requestedCampaignId))
    || allBookings.find(b => b.influencerId === baseInfluencer?.id)
    || defaultBooking
    || {};
  const campaign = window.PulseStore ? window.PulseStore.getCampaign(currentBooking.campaignId) : PULSE.campaigns[0];
  const realPosts = window.PulseStore ? window.PulseStore.getPosts({ influencerId: baseInfluencer?.id, campaignId: currentBooking.campaignId }) : [];
  const posts = realPosts.map((p, i) => ({
    ...p,
    type: p.type || 'Video',
    title: p.title || p.caption || `Post ${i + 1}`,
    caption: p.caption || p.title || '',
    hue: i * 90,
    engRate: p.views ? +((idEng(p) / p.views) * 100).toFixed(2) : 0,
  }));
  const actualViewsFromPosts = posts.reduce((s, p) => s + idNum(p.views), 0);
  const actualEngFromPosts = posts.reduce((s, p) => s + idEng(p), 0);
  const actualLikesFromPosts = posts.reduce((s, p) => s + idNum(p.likes), 0);
  const actualCommentsFromPosts = posts.reduce((s, p) => s + idNum(p.comments), 0);
  const actualSharesFromPosts = posts.reduce((s, p) => s + idNum(p.shares), 0);
  const actualPostCount = posts.filter(idIsCountablePost).length;
  const committedPostCount = Math.max(idNum(currentBooking.postsPlanned), posts.length, 0);
  const inf = {
    ...(baseInfluencer || {}),
    ...currentBooking,
    id: baseInfluencer?.id || currentBooking.influencerId,
    name: baseInfluencer?.name || currentBooking.name || 'Influencer',
    handle: baseInfluencer?.handle || currentBooking.handle || '',
    avatar: baseInfluencer?.avatar || currentBooking.avatar || '',
    followers: baseInfluencer?.followers || currentBooking.followers || 0,
    platform: currentBooking.platform || baseInfluencer?.platform || 'tiktok',
    engagementRate: posts.length && actualViewsFromPosts ? +((actualEngFromPosts / actualViewsFromPosts) * 100).toFixed(2) : (currentBooking.engagementRate || baseInfluencer?.avgEngagementRate || 0),
    kpiPct: posts.length ? idPct(actualViewsFromPosts, currentBooking.committedViews || 0) : (currentBooking.kpiPct || 0),
    committedViews: currentBooking.committedViews || 0,
    actualViews: posts.length ? actualViewsFromPosts : (currentBooking.actualViews || 0),
    likes: posts.length ? actualLikesFromPosts : (currentBooking.likes || 0),
    comments: posts.length ? actualCommentsFromPosts : (currentBooking.comments || 0),
    shares: posts.length ? actualSharesFromPosts : (currentBooking.shares || 0),
    engagement: posts.length ? actualEngFromPosts : (currentBooking.engagement || 0),
  };
  const [tab, setTab] = useStateID('performance');
  const tabsRef = React.useRef(null);
  const showAllPosts = () => {
    setTab('posts');
    setTimeout(() => tabsRef.current?.scrollIntoView({ behavior: 'smooth', block: 'start' }), 0);
  };

  let cumV = 0, cumE = 0;
  const daily = posts
    .map(p => {
      const d = idSafeDate(p.postedAt || p.lastPulledAt);
      if (!d) return null;
      const views = p.views || 0;
      const engagement = (p.likes || 0) + (p.comments || 0) + (p.shares || 0);
      cumV += views; cumE += engagement;
      return { date: d.toISOString().slice(0,10), label: `${d.getDate()}/${d.getMonth()+1}`, views, engagement, cumViews: cumV, cumEng: cumE };
    })
    .filter(Boolean)
    .sort((a, b) => a.date.localeCompare(b.date));
  if (daily.length < 2) {
    daily.length = 0;
    daily.push(
      { date: campaign?.startDate || '2026-04-01', label: 'Start', views: 0, engagement: 0, cumViews: 0, cumEng: 0 },
      { date: campaign?.endDate || '2026-04-30', label: 'Now', views: inf.actualViews || 0, engagement: inf.engagement || 0, cumViews: inf.actualViews || 0, cumEng: inf.engagement || 0 },
    );
  }

  return (
    <div style={{ padding: isMobile ? '16px 16px 84px' : '24px 32px 64px', maxWidth: 1400, margin: '0 auto' }}>
      {/* Hero header */}
      <div style={idStyles.hero}>
        <div style={{ display: 'flex', gap: 20, alignItems: 'center', flexWrap: 'wrap' }}>
          <img src={idThumbnailSrc(inf.avatar)} style={idStyles.avatar}/>
          <div style={{ flex: '1 1 300px', minWidth: 0 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 8, flexWrap: 'wrap' }}>
              <PlatformBadge platform={inf.platform} size={22}/>
              <span style={{ fontSize: 12, color: 'var(--ink-500)' }}>Booked for <a href={window.withQuery ? window.withQuery('Campaign Detail.html', { id: currentBooking.campaignId || 'c1' }) : `Campaign Detail.html?id=${encodeURIComponent(currentBooking.campaignId || 'c1')}`} style={{ color: 'var(--brand-500)', fontWeight: 500 }}>{campaign?.name || 'Campaign'}</a></span>
              <span className="chip violet" style={{ fontSize: 11 }}>{(inf.tier || 'micro').toUpperCase()}</span>
              <span className="chip" style={{ fontSize: 11 }}>Beauty · Lifestyle</span>
            </div>
            <h1 style={idStyles.title}>{inf.name}</h1>
            <div style={{ display: 'flex', gap: 16, marginTop: 8, fontSize: 13, color: 'var(--ink-500)', flexWrap: 'wrap' }}>
              <span>{inf.handle}</span>
              <span><span style={{ color: 'var(--ink-900)', fontWeight: 500 }}>{idFmt(inf.followers)}</span> followers</span>
              <span><span style={{ color: 'var(--ink-900)', fontWeight: 500 }}>{inf.engagementRate}%</span> avg engagement</span>
              <span>{actualPostCount} posts delivered</span>
            </div>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 6 }}>
            <KpiRing pct={inf.kpiPct} size={88} thickness={9}/>
            <div style={{ fontSize: 11, color: 'var(--ink-500)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>Overall KPI</div>
          </div>
          <div style={{ display: 'flex', flexDirection: isMobile ? 'row' : 'column', gap: 8, flexWrap: 'wrap' }}>
            {(() => {
              const profileUrl = idProfileUrlFor(inf, posts);
              return profileUrl ? (
                <a className="btn" href={profileUrl} target="_blank" rel="noreferrer"><Icon name="external" size={13}/> View profile</a>
              ) : (
                <button className="btn" disabled title="No profile URL" style={{ opacity: 0.55, cursor: 'not-allowed' }}><Icon name="external" size={13}/> No profile URL</button>
              );
            })()}
            {(() => {
              const email = idEmailFor(inf);
              return email ? (
                <a className="btn" href={`mailto:${email}?subject=${encodeURIComponent(`PULSE booking: ${campaign?.name || ''}`)}`}><Icon name="message" size={13}/> Message</a>
              ) : (
                <button className="btn" disabled title="No contact email" style={{ opacity: 0.55, cursor: 'not-allowed' }}><Icon name="message" size={13}/> No contact email</button>
              );
            })()}
          </div>
        </div>

        {/* Commit vs Actual grid */}
        <div style={{ ...idStyles.kpiBlocks, gridTemplateColumns: `repeat(auto-fit, minmax(${isMobile ? '180px' : '260px'}, 1fr))` }}>
          <KpiBlock
            label="Views"
            committed={inf.committedViews}
            actual={inf.actualViews}
            pct={inf.kpiPct}
            primary
          />
          <KpiBlock
            label="Engagement"
            committed={Math.round(inf.committedViews * 0.05)}
            actual={inf.engagement}
            pct={Math.round((inf.engagement / (inf.committedViews * 0.05)) * 100)}
          />
          <KpiBlock
            label="Post count"
            committed={committedPostCount}
            actual={actualPostCount}
            pct={idPct(actualPostCount, committedPostCount)}
            isCount
          />
        </div>
      </div>

      {/* Tabs */}
        <div style={idStyles.tabs} ref={tabsRef}>
        {[
          { k: 'performance', l: 'Performance' },
          { k: 'posts', l: `Posts · ${posts.length}` },
          { k: 'contract', l: 'Contract' },
        ].map(t => (
          <button key={t.k} onClick={() => setTab(t.k)} style={{
            ...idStyles.tab,
            ...(tab === t.k ? idStyles.tabActive : {}),
          }}>{t.l}</button>
        ))}
      </div>

      {tab === 'performance' && (
        <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : 'minmax(0, 2.2fr) minmax(260px, 0.8fr)', gap: 16 }}>
          <div className="panel" style={{ padding: 20 }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 14 }}>
              <div>
                <div style={{ fontSize: 14, fontWeight: 600 }}>Daily growth</div>
                <div style={{ fontSize: 12, color: 'var(--ink-500)', marginTop: 2 }}>Views spike on post days (8, 14, 19 Apr)</div>
              </div>
            </div>
            <AreaChart data={daily} height={240}/>
          </div>

          <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
            <div className="panel" style={{ padding: 18 }}>
              <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--ink-700)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 14 }}>Engagement breakdown</div>
              {[
                { label: 'Likes', value: inf.likes, color: '#EC2024', pct: idPct(inf.likes, inf.engagement || 1) },
                { label: 'Comments', value: inf.comments, color: '#111111', pct: idPct(inf.comments, inf.engagement || 1) },
                { label: 'Shares', value: inf.shares, color: '#6E6E6E', pct: idPct(inf.shares, inf.engagement || 1) },
              ].map(m => (
                <div key={m.label} style={{ marginBottom: 14 }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, marginBottom: 4 }}>
                    <span>{m.label}</span>
                    <span className="num" style={{ fontWeight: 500 }}>{idFmt(m.value)}</span>
                  </div>
                  <div style={{ height: 5, background: 'var(--ink-100)', borderRadius: 999 }}>
                    <div style={{ width: `${m.pct}%`, height: '100%', background: m.color, borderRadius: 999 }}/>
                  </div>
                </div>
              ))}
            </div>

          </div>

          {/* Posts list full width */}
          <div style={{ gridColumn: '1 / -1' }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
              <div style={{ fontSize: 14, fontWeight: 600 }}>Posts delivered</div>
              <button className="btn" style={{ fontSize: 12 }} onClick={showAllPosts}>View all posts <Icon name="arrow-right" size={12}/></button>
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: `repeat(auto-fit, minmax(${isMobile ? '220px' : '280px'}, 1fr))`, gap: 14 }}>
              {posts.length ? posts.map(p => <PostCard key={p.id} post={p}/>) : <EmptyPostsState planned={committedPostCount}/>}
            </div>
          </div>
        </div>
      )}

      {tab === 'posts' && (
        posts.length ? (
          <div>
            <div className="panel" style={{ padding: 16, marginBottom: 14, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
              <div>
                <div style={{ fontSize: 15, fontWeight: 800, color: 'var(--text-primary)' }}>All delivered public posts</div>
                <div style={{ fontSize: 12, color: 'var(--text-secondary)', marginTop: 4 }}>Pulled by n8n + ScrapeCreators from staff-approved public URLs. TikTok, Instagram, and Facebook formats use the same safe card layout.</div>
              </div>
              <span className="chip" style={{ background: 'var(--ink-100)', fontSize: 11 }}>{posts.length} posts</span>
            </div>
            <div style={{ display: 'grid', gridTemplateColumns: `repeat(auto-fit, minmax(${isMobile ? '240px' : '300px'}, 1fr))`, gap: 14, marginBottom: 16 }}>
              {posts.map(p => <PostCard key={p.id} post={p} expanded/>)}
            </div>
            <PostCompactTable posts={posts}/>
          </div>
        ) : <EmptyPostsState planned={committedPostCount} expanded/>
      )}

      {tab === 'contract' && (
        <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '2fr 1fr', gap: 16 }}>
          <div className="panel" style={{ padding: 24 }}>
            <div style={idStyles.sectionHeader}>Booking contract</div>
            <div style={idStyles.contractGrid}>
              <ContractRow label="Booking date" value={currentBooking.contractDetails?.bookingDate || currentBooking.createdAt || '—'} visibility={currentBooking.contractDetails?.clientVisibleFields?.bookingDate}/>
              <ContractRow label="Fee" value={`$${idNum(currentBooking.fee).toLocaleString()}`} visibility={currentBooking.contractDetails?.clientVisibleFields?.fee}/>
              <ContractRow label="Posts committed" value={`${committedPostCount || '—'} public post/video URLs`} visibility={currentBooking.contractDetails?.clientVisibleFields?.postsCommitted}/>
              <ContractRow label="Views committed" value={idFmt(inf.committedViews)} visibility={currentBooking.contractDetails?.clientVisibleFields?.viewsCommitted}/>
              <ContractRow label="Min engagement rate" value={`${inf.engagementRate || baseInfluencer?.avgEngagementRate || 0}%`} visibility={currentBooking.contractDetails?.clientVisibleFields?.engagementRate}/>
              <ContractRow label="Exclusivity" value={currentBooking.contractDetails?.exclusivity || '—'} visibility={currentBooking.contractDetails?.clientVisibleFields?.exclusivity}/>
              <ContractRow label="Usage rights" value={currentBooking.contractDetails?.usageRights || '—'} visibility={currentBooking.contractDetails?.clientVisibleFields?.usageRights}/>
              <ContractRow label="Payment status" value={<span className="chip amber" style={{ fontSize: 11 }}>{currentBooking.contractDetails?.paymentStatus || '—'}</span>} visibility={currentBooking.contractDetails?.clientVisibleFields?.paymentStatus}/>
            </div>
          </div>
          <div className="panel" style={{ padding: 20 }}>
            <div style={idStyles.sectionHeader}>Deliverables checklist</div>
            {(currentBooking.deliverables || [
              { done: true, label: 'Brief signed', date: 'Mar 30', visibility: 'client' },
              { done: true, label: 'Script approved', date: 'Apr 3', visibility: 'client' },
              { done: posts.length > 0, label: 'Public post URLs added', date: `${posts.length}/${committedPostCount || posts.length || 0}`, visibility: 'client' },
              { done: posts.some(p => p.pullStatus === 'ok'), label: 'ScrapeCreators metrics pulled', date: idDateTime(posts[0]?.lastPulledAt), visibility: 'agency' },
              { done: actualPostCount >= committedPostCount && committedPostCount > 0, label: 'Committed posts delivered', date: `${actualPostCount}/${committedPostCount || 0}`, visibility: 'client' },
              { done: false, label: 'Final report sign-off', date: 'Due Apr 30', visibility: 'agency' },
            ]).map((d, i, arr) => (
              <div key={d.id || i} style={{ display: 'flex', gap: 10, padding: '10px 0', borderBottom: i < arr.length - 1 ? '1px solid var(--border)' : 'none' }}>
                <div style={{
                  width: 20, height: 20, borderRadius: 6,
                  background: d.done ? 'var(--mint-100)' : 'var(--ink-100)',
                  color: d.done ? 'var(--mint-500)' : 'var(--ink-400)',
                  display: 'grid', placeItems: 'center', flexShrink: 0,
                }}>
                  <Icon name={d.done ? 'check' : 'calendar'} size={11} stroke={2.5}/>
                </div>
                <div style={{ flex: 1 }}>
                  <div style={{ fontSize: 13, fontWeight: 500, color: d.done ? 'var(--ink-900)' : 'var(--ink-500)' }}>{d.label}</div>
                  <div style={{ fontSize: 11, color: 'var(--ink-500)' }}>{d.date || '—'} · {d.visibility === 'client' ? 'Client visible' : 'Agency only'}</div>
                </div>
              </div>
            ))}
          </div>
        </div>
      )}
    </div>
  );
};

const KpiBlock = ({ label, committed, actual, pct, primary, isCount }) => (
  <div style={{ ...idStyles.kpiBlock, ...(primary ? { background: 'var(--brand-500)', color: '#FFFFFF', borderColor: 'var(--brand-500)' } : {}) }}>
    <div style={{ fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600, opacity: primary ? 0.78 : 1, color: primary ? '#FFFFFF' : 'var(--ink-500)' }}>{label}</div>
    <div style={{ display: 'flex', alignItems: 'baseline', gap: 8, marginTop: 10 }}>
      <div className="num" style={{ fontSize: 32, fontWeight: 600, letterSpacing: 0, lineHeight: 1 }}>
        {isCount ? actual : idFmt(actual)}
      </div>
      <div style={{ fontSize: 13, opacity: primary ? 0.72 : 1, color: primary ? '#FFFFFF' : 'var(--ink-500)' }}>
        / {isCount ? committed : idFmt(committed)}
      </div>
    </div>
    <div style={{ marginTop: 12 }}>
      <div style={{ height: 6, background: primary ? 'rgba(255,255,255,0.24)' : 'var(--ink-100)', borderRadius: 999, overflow: 'hidden' }}>
        <div style={{
          width: `${Math.min(Number.isFinite(+pct) ? +pct : 0, 100)}%`, height: '100%',
          background: primary ? '#FFFFFF' : 'var(--brand-500)',
          borderRadius: 0,
        }}/>
      </div>
      <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 6, fontSize: 11, opacity: primary ? 0.78 : 1, color: primary ? '#FFFFFF' : 'var(--ink-500)' }}>
        <span>{Number.isFinite(+pct) ? pct : 0}% delivered</span>
        {pct >= 100 ? <span style={{ color: primary ? '#FFFFFF' : 'var(--text-primary)', fontWeight: 800 }}>✓ MET</span> : <span>{Math.max(0, 100 - (Number.isFinite(+pct) ? +pct : 0))}% to go</span>}
      </div>
    </div>
  </div>
);

const StatusChip = ({ status }) => {
  const styles = {
    ok:    { background: 'var(--ink-900)', color: 'var(--text-inverse)', borderColor: 'var(--ink-900)' },
    amber: { background: 'var(--brand-100)', color: 'var(--brand-600)', borderColor: 'transparent' },
    warn:  { background: 'var(--brand-500)', color: '#FFFFFF', borderColor: 'var(--brand-500)' },
  };
  return (
    <span className="chip" style={{ ...(styles[status.tone] || styles.ok), fontSize: 10, padding: '4px 8px', minWidth: 0 }}>
      <Icon name={status.icon} size={10}/>
      <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{status.label}</span>
    </span>
  );
};

const PostCard = ({ post, expanded }) => {
  const [imageFailed, setImageFailed] = useStateID(false);
  const status = idPostStatus(post);
  const isLimitedMetric = post.metricsScope === 'profile_list_limited';
  const title = post.caption || post.title || `${post.platform || 'Social'} post`;
  const thumbSrc = idThumbnailSrc(post.thumbnailUrl);
  const hasImage = thumbSrc && !imageFailed;
  const thumbStateLabel = post.thumbnailUrl ? 'Thumbnail unavailable' : 'No thumbnail from provider';
  const urlLabel = post.platformPostId || post.url || 'No public URL yet';
  const platform = String(post.platform || 'tiktok').toLowerCase();
  const platformLabel = idPlatformName(platform);
  const placeholderFg = platform === 'tiktok' ? '#FFFFFF' : (platform === 'instagram' ? 'var(--brand-500)' : 'var(--text-primary)');
  const mediaHeight = expanded ? 'clamp(220px, 28vw, 360px)' : 'clamp(190px, 22vw, 300px)';

  return (
    <div className="panel" style={{ overflow: 'hidden', minWidth: 0, display: 'flex', flexDirection: 'column' }}>
      <div style={{
        height: mediaHeight,
        minHeight: 0,
        position: 'relative',
        background: platform === 'tiktok' ? '#111111' : 'var(--ink-50)',
        color: placeholderFg,
        overflow: 'hidden',
        borderBottom: '1px solid var(--border)',
      }}>
        {hasImage ? (
          <>
            <img
              src={thumbSrc}
              alt=""
              aria-hidden="true"
              onError={() => setImageFailed(true)}
              referrerPolicy="no-referrer"
              style={{
                position: 'absolute',
                inset: 0,
                width: '100%',
                height: '100%',
                objectFit: 'cover',
                objectPosition: 'center',
                display: 'block',
                filter: 'blur(18px) saturate(0.88)',
                transform: 'scale(1.08)',
                opacity: 0.32,
              }}
            />
            <img
              src={thumbSrc}
              alt={title}
              onError={() => setImageFailed(true)}
              referrerPolicy="no-referrer"
              style={{
                position: 'absolute',
                inset: '10px',
                width: 'calc(100% - 20px)',
                height: 'calc(100% - 20px)',
                objectFit: 'contain',
                objectPosition: 'center',
                display: 'block',
                borderRadius: 8,
              }}
            />
          </>
        ) : (
          <>
            <div style={{ position: 'absolute', inset: 0, opacity: 0.45, background: 'linear-gradient(135deg, transparent 0 44%, var(--border) 44% 45%, transparent 45% 100%)' }}/>
            <div style={{ position: 'absolute', inset: 0, display: 'grid', placeItems: 'center', padding: 26, textAlign: 'center' }}>
              <div>
                <div style={{ margin: '0 auto 12px', width: 42, height: 42, display: 'grid', placeItems: 'center', borderRadius: 10, background: platform === 'tiktok' ? 'rgba(255,255,255,0.12)' : 'var(--bg-panel)', border: '1px solid var(--border)' }}>
                  <PlatformBadge platform={platform} size={28}/>
                </div>
                <div style={{ fontFamily: 'var(--font-mono)', fontSize: 10, fontWeight: 800, textTransform: 'uppercase', letterSpacing: '0.12em', opacity: 0.75 }}>{post.source || 'scrapecreators'}</div>
                <div style={{ marginTop: 8, fontFamily: 'var(--font-display)', fontSize: 15, fontWeight: 900, lineHeight: 1.1, letterSpacing: 0, textTransform: 'uppercase' }}>{thumbStateLabel}</div>
                <div style={{ marginTop: 8, fontSize: 11, lineHeight: 1.4, opacity: 0.72, maxWidth: 260 }}>
                  {post.thumbnailUrl ? 'Image URL exists, but the platform/CDN did not allow preview loading.' : 'ScrapeCreators did not return a thumbnail for this post.'}
                </div>
              </div>
            </div>
          </>
        )}
        <div style={{ position: 'absolute', top: 10, left: 10, right: 10, display: 'flex', gap: 6, zIndex: 2, alignItems: 'flex-start', justifyContent: 'space-between', minWidth: 0 }}>
          <div style={{ display: 'flex', gap: 6, minWidth: 0, maxWidth: 'calc(100% - 112px)', flexWrap: 'wrap' }}>
            <PlatformBadge platform={post.platform} size={26}/>
            <span className="chip" style={{ background: 'rgba(17,17,17,0.86)', color: '#FFFFFF', border: 'none', fontSize: 10, maxWidth: 132, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', flexShrink: 1 }}>{platformLabel}</span>
            <span className="chip" style={{ background: 'rgba(17,17,17,0.86)', color: '#FFFFFF', border: 'none', fontSize: 10, maxWidth: 164, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', flexShrink: 1 }}>{post.type || 'Post'}</span>
          </div>
          <StatusChip status={status}/>
        </div>
      </div>
      <div style={{ padding: 14, minWidth: 0, display: 'flex', flexDirection: 'column', gap: 12, flex: 1 }}>
        {isLimitedMetric && (
          <div style={{
            display: 'flex',
            alignItems: 'flex-start',
            gap: 7,
            padding: '8px 10px',
            borderRadius: 6,
            background: 'var(--brand-50)',
            color: 'var(--brand-600)',
            fontSize: 11,
            lineHeight: 1.35,
            fontWeight: 700,
          }}>
            <Icon name="alert" size={13}/>
            <span>Profile-source metrics only. Use exact post URL when this post is used for verified client KPI.</span>
          </div>
        )}
        <div style={{ minWidth: 0 }}>
          <div style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--text-muted)', fontWeight: 800, textTransform: 'uppercase', letterSpacing: '0.08em', marginBottom: 6 }}>{idShortDate(post.postedAt || post.lastPulledAt)}</div>
          <div title={title} style={{ fontSize: 14, fontWeight: 800, color: 'var(--text-primary)', lineHeight: 1.25, minHeight: 36, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden', wordBreak: 'break-word' }}>{title}</div>
          <div title={post.url || ''} style={{ marginTop: 7, fontFamily: 'var(--font-mono)', fontSize: 10, color: post.url ? 'var(--brand-500)' : 'var(--text-muted)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: '100%' }}>{urlLabel}</div>
        </div>
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 10, marginTop: 'auto' }}>
          <PostStat icon="eye" label="Views" value={idFmt(post.views)}/>
          <PostStat icon="heart" label="Likes" value={idFmt(post.likes)}/>
          <PostStat icon="message" label="Comments" value={idFmt(post.comments)}/>
          <PostStat icon="share" label="Shares" value={idFmt(post.shares)}/>
        </div>
        {expanded && (
          <div style={{ paddingTop: 12, borderTop: '1px solid var(--border)', display: 'grid', gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 10 }}>
            <MiniMeta label="Saves" value={idFmt(post.saves)}/>
            <MiniMeta label="Reach" value={idFmt(post.reach)}/>
            <MiniMeta label="ER" value={`${post.engRate || 0}%`}/>
            <MiniMeta label="Last pull" value={idDateTime(post.lastPulledAt)}/>
            {post.errorMessage && <div style={{ gridColumn: '1 / -1', fontSize: 11, color: 'var(--brand-500)', lineHeight: 1.4, wordBreak: 'break-word' }}>{post.errorMessage}</div>}
          </div>
        )}
        <div style={{ display: 'flex', gap: 8, alignItems: 'center', justifyContent: 'space-between', minWidth: 0 }}>
          <span style={{ fontSize: 11, color: 'var(--text-muted)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{post.source || 'scrapecreators'} / n8n</span>
          {post.url ? (
            <a href={post.url} target="_blank" rel="noreferrer" className="btn ghost" style={{ padding: '6px 8px', fontSize: 11, flexShrink: 0 }}><Icon name="external" size={12}/> Open</a>
          ) : (
            <span className="btn ghost" style={{ padding: '6px 8px', fontSize: 11, color: 'var(--text-muted)', flexShrink: 0 }}>No URL</span>
          )}
        </div>
      </div>
    </div>
  );
};

const MiniMeta = ({ label, value }) => (
  <div style={{ minWidth: 0 }}>
    <div style={{ fontSize: 10, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 800 }}>{label}</div>
    <div className="num" style={{ marginTop: 3, fontSize: 12, fontWeight: 700, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{value}</div>
  </div>
);

const EmptyPostsState = ({ planned, expanded }) => (
  <div className="panel" style={{ gridColumn: '1 / -1', padding: expanded ? 44 : 28, textAlign: 'center', borderStyle: 'dashed', background: 'var(--bg-panel)' }}>
    <div style={{ width: 44, height: 44, display: 'grid', placeItems: 'center', margin: '0 auto 12px', background: 'var(--brand-100)', color: 'var(--brand-500)', borderRadius: 8 }}>
      <Icon name="link" size={20}/>
    </div>
    <div style={{ fontSize: 15, fontWeight: 800, color: 'var(--text-primary)' }}>No real public posts connected yet</div>
    <div style={{ fontSize: 12, color: 'var(--text-secondary)', lineHeight: 1.5, margin: '8px auto 0', maxWidth: 520 }}>
      Staff should add the committed public post/video URLs in Booking setup. n8n will call ScrapeCreators, then PULSE will show real metrics here.
      {planned ? ` Planned deliverables: ${planned}.` : ''}
    </div>
  </div>
);

const PostCompactTable = ({ posts }) => (
  <div className="panel" style={{ padding: 0, overflow: 'auto' }}>
    <table style={{ width: '100%', borderCollapse: 'collapse', minWidth: 820 }}>
      <thead>
        <tr style={{ background: 'var(--ink-50)', borderBottom: '1px solid var(--border)' }}>
          <th style={idTable.th}>Post</th>
          <th style={idTable.th}>Platform</th>
          <th style={idTable.th}>Status</th>
          <th style={{ ...idTable.th, textAlign: 'right' }}>Views</th>
          <th style={{ ...idTable.th, textAlign: 'right' }}>Eng.</th>
          <th style={idTable.th}>Last pull</th>
        </tr>
      </thead>
      <tbody>
        {posts.map(p => {
          const status = idPostStatus(p);
          return (
            <tr key={p.id} style={{ borderBottom: '1px solid var(--border)' }}>
              <td style={{ ...idTable.td, maxWidth: 320 }}>
                <div style={{ fontWeight: 700, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{p.caption || p.title || p.platformPostId || 'Public post'}</div>
                <div style={{ fontFamily: 'var(--font-mono)', fontSize: 10, color: 'var(--text-muted)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{p.url || 'Missing public URL'}</div>
              </td>
              <td style={idTable.td}>
                <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                  <PlatformBadge platform={p.platform} size={22}/>
                  <span style={{ fontSize: 11, fontWeight: 800 }}>{idPlatformName(p.platform)}</span>
                </span>
              </td>
              <td style={idTable.td}><StatusChip status={status}/></td>
              <td style={{ ...idTable.td, textAlign: 'right' }} className="num">{idFmt(p.views)}</td>
              <td style={{ ...idTable.td, textAlign: 'right' }} className="num">{idFmt(idEng(p))}</td>
              <td style={idTable.td}><span style={{ fontFamily: 'var(--font-mono)', fontSize: 11 }}>{idDateTime(p.lastPulledAt)}</span></td>
            </tr>
          );
        })}
      </tbody>
    </table>
  </div>
);

const PostStat = ({ icon, label, value }) => (
  <div style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0 }}>
    <div style={{ width: 28, height: 28, borderRadius: 7, background: 'var(--ink-100)', color: 'var(--ink-600)', display: 'grid', placeItems: 'center' }}>
      <Icon name={icon} size={13}/>
    </div>
    <div style={{ minWidth: 0 }}>
      <div className="num" style={{ fontSize: 13, fontWeight: 700, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{value}</div>
      <div style={{ fontSize: 10, color: 'var(--ink-500)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{label}</div>
    </div>
  </div>
);

const ContractRow = ({ label, value, visibility }) => (
  <>
    <div style={{ fontSize: 12, color: 'var(--ink-500)', padding: '10px 0', borderBottom: '1px solid var(--border)' }}>{label}</div>
    <div style={{ fontSize: 13, fontWeight: 500, padding: '10px 0', borderBottom: '1px solid var(--border)', display: 'flex', justifyContent: 'space-between', gap: 10, alignItems: 'center' }}>
      <span>{value}</span>
      <span className="chip" style={{ fontSize: 9, padding: '2px 6px', color: visibility ? 'var(--brand-500)' : 'var(--ink-500)' }}>{visibility ? 'Client' : 'Agency'}</span>
    </div>
  </>
);

const idStyles = {
  hero: { background: 'var(--bg-panel)', border: '1px solid var(--border)', borderRadius: 16, padding: 24, marginBottom: 24, boxShadow: 'var(--sh-xs)' },
  avatar: { width: 88, height: 88, borderRadius: 16, objectFit: 'cover', border: '3px solid var(--bg-panel)', boxShadow: 'var(--sh-md)' },
  title: { fontFamily: 'var(--font-display)', fontSize: 40, fontWeight: 400, margin: 0, letterSpacing: 0, lineHeight: 1.05 },
  kpiBlocks: { display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12, marginTop: 24 },
  kpiBlock: { padding: 20, borderRadius: 14, background: 'var(--ink-50)', border: '1px solid var(--border)' },
  tabs: { display: 'flex', gap: 4, borderBottom: '1px solid var(--border)', marginBottom: 16 },
  tab: { padding: '10px 14px', fontSize: 13, color: 'var(--ink-500)', fontWeight: 500, borderBottomWidth: 2, borderBottomStyle: 'solid', borderBottomColor: 'transparent', marginBottom: -1 },
  tabActive: { color: 'var(--ink-900)', borderBottomColor: 'var(--ink-900)' },
  sectionHeader: { fontSize: 12, fontWeight: 600, color: 'var(--ink-700)', textTransform: 'uppercase', letterSpacing: '0.06em', marginBottom: 14 },
  contractGrid: { display: 'grid', gridTemplateColumns: '180px 1fr', rowGap: 0 },
};

const idTable = {
  th: { padding: '10px 12px', fontSize: 10, color: 'var(--text-muted)', textTransform: 'uppercase', letterSpacing: '0.08em', fontWeight: 800, textAlign: 'left', whiteSpace: 'nowrap' },
  td: { padding: '12px', fontSize: 12, color: 'var(--text-primary)', verticalAlign: 'middle' },
};

Object.assign(window, { InfluencerDetail });
