import { useState, useEffect, useCallback, lazy, Suspense } from 'react';
import {
  Typography,
  Tabs,
  Input,
  Button,
  Switch,
  Space,
  Tag,
  Spin,
  Avatar,
  Grid,
  Timeline,
  Progress,
  Upload,
  message,
  theme,
  Result,
} from 'antd';
import {
  CameraOutlined,
  EnvironmentOutlined,
  LockOutlined,
  MailOutlined,
  PhoneOutlined,
  SaveOutlined,
  ScheduleOutlined,
  HeartOutlined,
  VideoCameraOutlined,
  TeamOutlined,
  ThunderboltOutlined,
} from '@ant-design/icons';
import { useParams } from 'react-router-dom';
import axios from 'axios';
import type { ContactProfile, ContactActivityItem, PaginationMeta, ContactSource } from '@/types/api';
import { CONTACT_SOURCE_LABELS, CONTACT_SOURCE_COLORS, SUPPORT_LEVEL_LABELS, SUPPORT_LEVEL_COLORS } from '@/types/api';
import { useAuthStore } from '@/stores/auth.store';
import { useSSE } from '@/hooks/useSSE';

// Lazy-load social tab components to avoid loading them for anonymous visitors
const FriendsPage = lazy(() => import('@/pages/volunteer/FriendsPage'));
const SocialFeedPage = lazy(() => import('@/pages/volunteer/SocialFeedPage'));
const AchievementsPage = lazy(() => import('@/pages/volunteer/AchievementsPage'));
const NotificationsPage = lazy(() => import('@/pages/volunteer/NotificationsPage'));
const DiscoverPage = lazy(() => import('@/pages/volunteer/DiscoverPage'));
const NotificationBell = lazy(() => import('@/components/social/NotificationBell'));

// Use relative URL so requests go through Vite's /api proxy (which handles
// Docker container routing). VITE_API_URL is a Docker-internal hostname that
// the browser cannot resolve.
const API_BASE = '';

type AccessState = 'loading' | 'ok' | 'expired' | 'password_required' | 'not_found';

interface ProfileBranding {
  organizationName: string;
  organizationShortName: string;
  organizationLogoUrl: string | null;
  publicColorPrimary: string;
  publicColorBgBase: string;
  publicColorBgContainer: string;
  publicHeaderGradient: string;
}

const SOURCE_AVATAR_COLORS: Record<ContactSource, string> = {
  USER: '#1890ff',
  ADDRESS_OCCUPANT: '#52c41a',
  CAMPAIGN_SENDER: '#722ed1',
  SHIFT_SIGNUP: '#13c2c2',
  SMS_CONTACT: '#fa8c16',
  DONATION: '#fadb14',
  MANUAL: '#8c8c8c',
};

function getInitials(name: string): string {
  if (!name) return '?';
  const parts = name.trim().split(/\s+/);
  if (parts.length >= 2) return ((parts[0]?.[0] || '') + (parts[parts.length - 1]?.[0] || '')).toUpperCase();
  return (name[0] || '?').toUpperCase();
}

const ACTIVITY_ICONS: Record<string, React.ReactNode> = {
  EMAIL_SENT: <MailOutlined />,
  RESPONSE_SUBMITTED: <ThunderboltOutlined />,
  SHIFT_SIGNUP: <ScheduleOutlined />,
  CANVASS_VISIT: <TeamOutlined />,
  DONATION: <HeartOutlined />,
  PURCHASE: <HeartOutlined />,
  VIDEO_VIEW: <VideoCameraOutlined />,
  PROFILE_SELF_EDIT: <SaveOutlined />,
  PROFILE_PHOTO_UPDATED: <CameraOutlined />,
};

export default function ContactProfilePage() {
  const { token } = useParams<{ token: string }>();
  const screens = Grid.useBreakpoint();
  const isMobile = !screens.md;
  const { token: themeToken } = theme.useToken();

  // Auth — used to send JWT on profile fetch (enables isOwnProfile detection)
  const accessToken = useAuthStore((s) => s.accessToken);
  const isAuthenticated = useAuthStore((s) => s.isAuthenticated);

  // SSE for real-time social notifications (hook guards on isAuthenticated + enableSocial)
  useSSE();

  // Access state machine
  const [accessState, setAccessState] = useState<AccessState>('loading');
  const [profile, setProfile] = useState<ContactProfile | null>(null);
  const [expiredAt, setExpiredAt] = useState<string | null>(null);
  const [branding, setBranding] = useState<ProfileBranding | null>(null);

  // Password gate state
  const [password, setPassword] = useState('');
  const [passwordError, setPasswordError] = useState('');
  const [verifying, setVerifying] = useState(false);

  // Edit state
  const [editFirstName, setEditFirstName] = useState('');
  const [editLastName, setEditLastName] = useState('');
  const [editDisplayName, setEditDisplayName] = useState('');
  const [editEmail, setEditEmail] = useState('');
  const [editPhone, setEditPhone] = useState('');
  const [editAddress, setEditAddress] = useState('');
  const [editEmailOptOut, setEditEmailOptOut] = useState(false);
  const [editSmsOptOut, setEditSmsOptOut] = useState(false);
  const [saving, setSaving] = useState(false);
  const [uploading, setUploading] = useState(false);
  const [photoVersion, setPhotoVersion] = useState(0);

  // Activity tab
  const [activities, setActivities] = useState<ContactActivityItem[]>([]);
  const [activityPagination, setActivityPagination] = useState<PaginationMeta | null>(null);
  const [loadingActivity, setLoadingActivity] = useState(false);

  const populateEditFields = (data: ContactProfile) => {
    setProfile(data);
    setEditFirstName(data.firstName || '');
    setEditLastName(data.lastName || '');
    setEditDisplayName(data.displayName || '');
    setEditEmail(data.email || '');
    setEditPhone(data.phone || '');
    setEditAddress(data.primaryAddress || '');
    setEditEmailOptOut(data.emailOptOut);
    setEditSmsOptOut(data.smsOptOut);
  };

  const fetchProfile = useCallback(async () => {
    if (!token) return;
    setAccessState('loading');
    try {
      const headers: Record<string, string> = {};
      if (isAuthenticated && accessToken) {
        headers.Authorization = `Bearer ${accessToken}`;
      }
      const { data } = await axios.get<ContactProfile>(`${API_BASE}/api/profile/${token}`, { headers });
      populateEditFields(data);
      setAccessState('ok');
    } catch (err: unknown) {
      if (axios.isAxiosError(err) && err.response) {
        const status = err.response.status;
        const body = err.response.data;
        if (status === 404) {
          setAccessState('not_found');
        } else if (status === 410) {
          setExpiredAt(body?.expiresAt || null);
          if (body?.branding) setBranding(body.branding);
          setAccessState('expired');
        } else if (status === 401 && body?.error?.code === 'PASSWORD_REQUIRED') {
          if (body?.branding) setBranding(body.branding);
          setAccessState('password_required');
        } else {
          message.error('Failed to load profile');
          setAccessState('not_found');
        }
      } else {
        message.error('Failed to load profile');
        setAccessState('not_found');
      }
    }
  }, [token, isAuthenticated, accessToken]);

  useEffect(() => {
    fetchProfile();
  }, [fetchProfile]);

  const handlePasswordSubmit = async () => {
    if (!token || !password.trim()) return;
    setVerifying(true);
    setPasswordError('');
    try {
      const { data } = await axios.post<ContactProfile>(
        `${API_BASE}/api/profile/${token}/verify`,
        { password },
      );
      populateEditFields(data);
      setAccessState('ok');
    } catch (err: unknown) {
      if (axios.isAxiosError(err) && err.response) {
        const status = err.response.status;
        const body = err.response.data;
        if (status === 429) {
          setPasswordError('Too many attempts, please try again later.');
        } else if (status === 401 && body?.error?.code === 'INVALID_PASSWORD') {
          setPasswordError('Incorrect password. Please try again.');
        } else {
          setPasswordError('An error occurred. Please try again.');
        }
      } else {
        setPasswordError('An error occurred. Please try again.');
      }
    } finally {
      setVerifying(false);
    }
  };

  const buildPayload = () => ({
    displayName: editDisplayName,
    firstName: editFirstName || null,
    lastName: editLastName || null,
    email: editEmail || null,
    phone: editPhone || null,
    address: editAddress || null,
    emailOptOut: editEmailOptOut,
    smsOptOut: editSmsOptOut,
  });

  const handleSave = async () => {
    if (!token) return;
    setSaving(true);
    try {
      await axios.put(`${API_BASE}/api/profile/${token}`, buildPayload());
      message.success('Profile updated');
      fetchProfile();
    } catch {
      message.error('Failed to save changes');
    } finally {
      setSaving(false);
    }
  };

  const handleSavePreferences = async () => {
    if (!token) return;
    setSaving(true);
    try {
      await axios.put(`${API_BASE}/api/profile/${token}`, buildPayload());
      message.success('Preferences updated');
      fetchProfile();
    } catch {
      message.error('Failed to save preferences');
    } finally {
      setSaving(false);
    }
  };

  const handlePhotoUpload = async (file: File) => {
    if (!token) return;
    setUploading(true);
    try {
      const formData = new FormData();
      formData.append('photo', file);
      await axios.post(`${API_BASE}/api/profile/${token}/photo`, formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
      });
      message.success('Cover photo updated');
      setPhotoVersion((v) => v + 1);
      fetchProfile();
    } catch (err: unknown) {
      if (axios.isAxiosError(err) && err.response?.data?.error?.message) {
        message.error(err.response.data.error.message);
      } else {
        message.error('Failed to upload photo');
      }
    } finally {
      setUploading(false);
    }
  };

  const fetchActivity = useCallback(async (page = 1) => {
    if (!token) return;
    setLoadingActivity(true);
    try {
      const { data } = await axios.get(`${API_BASE}/api/profile/${token}/activity`, {
        params: { page, limit: 20 },
      });
      setActivities(data.activities);
      setActivityPagination(data.pagination);
    } catch {
      message.error('Failed to load activity');
    } finally {
      setLoadingActivity(false);
    }
  }, [token]);

  // --- Access state screens ---

  if (accessState === 'loading') {
    return (
      <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '60vh' }}>
        <Spin size="large" />
      </div>
    );
  }

  if (accessState === 'not_found') {
    return (
      <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '60vh' }}>
        <Result
          status="404"
          title="Profile Not Found"
          subTitle="This profile link may have been revoked or is invalid."
        />
      </div>
    );
  }

  if (accessState === 'expired') {
    const orgName = branding?.organizationName || 'the organization';
    return (
      <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '60vh' }}>
        <div style={{ maxWidth: 480, width: '100%', textAlign: 'center' }}>
          {branding?.organizationLogoUrl && (
            <img
              src={branding.organizationLogoUrl}
              alt={branding.organizationName}
              style={{ height: 48, marginBottom: 24, objectFit: 'contain' }}
            />
          )}
          <Result
            status="warning"
            title="This profile link has expired"
            subTitle={
              <>
                Please contact {orgName} for a new link.
                {expiredAt && (
                  <Typography.Text type="secondary" style={{ display: 'block', marginTop: 8, fontSize: 12 }}>
                    Expired on {new Date(expiredAt).toLocaleDateString(undefined, {
                      year: 'numeric',
                      month: 'long',
                      day: 'numeric',
                    })}
                  </Typography.Text>
                )}
              </>
            }
          />
        </div>
      </div>
    );
  }

  if (accessState === 'password_required') {
    const orgName = branding?.organizationName || 'Organization';
    const primaryColor = branding?.publicColorPrimary || '#9d4edd';
    return (
      <div
        style={{
          display: 'flex',
          justifyContent: 'center',
          alignItems: 'center',
          minHeight: '60vh',
          padding: 24,
        }}
      >
        <div
          style={{
            maxWidth: 400,
            width: '100%',
            textAlign: 'center',
            padding: isMobile ? 24 : 40,
            borderRadius: 12,
            background: branding?.publicColorBgContainer || 'rgba(255,255,255,0.04)',
            border: '1px solid rgba(255,255,255,0.08)',
          }}
        >
          {branding?.organizationLogoUrl ? (
            <img
              src={branding.organizationLogoUrl}
              alt={orgName}
              style={{ height: 48, marginBottom: 20, objectFit: 'contain' }}
            />
          ) : (
            <div
              style={{
                width: 64,
                height: 64,
                borderRadius: '50%',
                background: `${primaryColor}22`,
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
                margin: '0 auto 20px',
              }}
            >
              <LockOutlined style={{ fontSize: 28, color: primaryColor }} />
            </div>
          )}
          <Typography.Title level={4} style={{ margin: '0 0 4px' }}>
            {orgName}
          </Typography.Title>
          <Typography.Text type="secondary" style={{ display: 'block', marginBottom: 24, fontSize: 13 }}>
            Enter the password to access your profile
          </Typography.Text>
          <Input.Password
            size="large"
            placeholder="Password"
            prefix={<LockOutlined />}
            value={password}
            onChange={(e) => {
              setPassword(e.target.value);
              if (passwordError) setPasswordError('');
            }}
            onPressEnter={handlePasswordSubmit}
            status={passwordError ? 'error' : undefined}
            style={{ marginBottom: passwordError ? 4 : 16 }}
          />
          {passwordError && (
            <Typography.Text type="danger" style={{ display: 'block', fontSize: 12, marginBottom: 12, textAlign: 'left' }}>
              {passwordError}
            </Typography.Text>
          )}
          <Button
            type="primary"
            size="large"
            block
            loading={verifying}
            onClick={handlePasswordSubmit}
            disabled={!password.trim()}
            style={{ backgroundColor: primaryColor, borderColor: primaryColor }}
          >
            Access Profile
          </Button>
        </div>
      </div>
    );
  }

  // accessState === 'ok' — but profile must be populated
  if (!profile) {
    return (
      <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '60vh' }}>
        <Spin size="large" />
      </div>
    );
  }

  const coverPhotoUrl = profile.coverPhotoPath
    ? `${API_BASE}/api/profile/${token}/photo?v=${photoVersion}`
    : null;

  const primaryColor = profile.branding.publicColorPrimary || '#9d4edd';

  const tabItems = [
    {
      key: 'profile',
      label: 'Profile',
      children: (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          <div>
            <Typography.Text type="secondary" style={{ fontSize: 12, display: 'block', marginBottom: 4 }}>
              Display Name
            </Typography.Text>
            <Input value={editDisplayName} onChange={(e) => setEditDisplayName(e.target.value)} />
          </div>
          <div style={{ display: 'flex', gap: 12 }}>
            <div style={{ flex: 1 }}>
              <Typography.Text type="secondary" style={{ fontSize: 12, display: 'block', marginBottom: 4 }}>
                First Name
              </Typography.Text>
              <Input value={editFirstName} onChange={(e) => setEditFirstName(e.target.value)} />
            </div>
            <div style={{ flex: 1 }}>
              <Typography.Text type="secondary" style={{ fontSize: 12, display: 'block', marginBottom: 4 }}>
                Last Name
              </Typography.Text>
              <Input value={editLastName} onChange={(e) => setEditLastName(e.target.value)} />
            </div>
          </div>
          <div>
            <Typography.Text type="secondary" style={{ fontSize: 12, display: 'block', marginBottom: 4 }}>
              Email
            </Typography.Text>
            <Input value={editEmail} onChange={(e) => setEditEmail(e.target.value)} prefix={<MailOutlined />} />
          </div>
          <div>
            <Typography.Text type="secondary" style={{ fontSize: 12, display: 'block', marginBottom: 4 }}>
              Phone
            </Typography.Text>
            <Input value={editPhone} onChange={(e) => setEditPhone(e.target.value)} prefix={<PhoneOutlined />} />
          </div>
          <div>
            <Typography.Text type="secondary" style={{ fontSize: 12, display: 'block', marginBottom: 4 }}>
              Address
            </Typography.Text>
            <Input
              value={editAddress}
              onChange={(e) => setEditAddress(e.target.value)}
              prefix={<EnvironmentOutlined />}
              placeholder="123 Main St, City, Province, Postal Code"
            />
          </div>
          <Button type="primary" icon={<SaveOutlined />} loading={saving} onClick={handleSave} style={{ marginTop: 8 }}>
            Save Changes
          </Button>
        </div>
      ),
    },
    {
      key: 'preferences',
      label: 'Preferences',
      children: (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
          <div>
            <Typography.Title level={5} style={{ marginBottom: 12 }}>Notification Preferences</Typography.Title>
            <Typography.Text type="secondary" style={{ display: 'block', marginBottom: 16, fontSize: 13 }}>
              Control which types of communications you receive from {profile.branding.organizationName}.
            </Typography.Text>
          </div>
          <div style={{
            display: 'flex', justifyContent: 'space-between', alignItems: 'center',
            padding: '12px 16px', borderRadius: 8,
            background: 'rgba(255,255,255,0.04)',
          }}>
            <div>
              <Typography.Text strong>Unsubscribe from emails</Typography.Text>
              <Typography.Text type="secondary" style={{ display: 'block', fontSize: 12, marginTop: 2 }}>
                Stop receiving email communications from us
              </Typography.Text>
            </div>
            <Switch checked={editEmailOptOut} onChange={setEditEmailOptOut} />
          </div>
          <div style={{
            display: 'flex', justifyContent: 'space-between', alignItems: 'center',
            padding: '12px 16px', borderRadius: 8,
            background: 'rgba(255,255,255,0.04)',
          }}>
            <div>
              <Typography.Text strong>Unsubscribe from SMS</Typography.Text>
              <Typography.Text type="secondary" style={{ display: 'block', fontSize: 12, marginTop: 2 }}>
                Stop receiving text message communications from us
              </Typography.Text>
            </div>
            <Switch checked={editSmsOptOut} onChange={setEditSmsOptOut} />
          </div>
          <Button type="primary" icon={<SaveOutlined />} loading={saving} onClick={handleSavePreferences} style={{ marginTop: 8 }}>
            Save Preferences
          </Button>
        </div>
      ),
    },
    {
      key: 'activity',
      label: 'Activity',
      children: (
        <ActivityTab
          activities={activities}
          pagination={activityPagination}
          loading={loadingActivity}
          onPageChange={fetchActivity}
          onLoad={fetchActivity}
        />
      ),
    },
    // Social tabs — only shown when viewer owns this profile and social is enabled
    ...(profile.isOwnProfile && profile.enableSocial ? [
      {
        key: 'friends',
        label: 'Friends',
        children: <Suspense fallback={<Spin style={{ display: 'block', margin: '32px auto' }} />}><FriendsPage /></Suspense>,
      },
      {
        key: 'feed',
        label: 'Feed',
        children: <Suspense fallback={<Spin style={{ display: 'block', margin: '32px auto' }} />}><SocialFeedPage /></Suspense>,
      },
      {
        key: 'achievements',
        label: 'Achievements',
        children: <Suspense fallback={<Spin style={{ display: 'block', margin: '32px auto' }} />}><AchievementsPage /></Suspense>,
      },
      {
        key: 'notifications',
        label: 'Notifications',
        children: <Suspense fallback={<Spin style={{ display: 'block', margin: '32px auto' }} />}><NotificationsPage /></Suspense>,
      },
      {
        key: 'discover',
        label: 'Discover',
        children: <Suspense fallback={<Spin style={{ display: 'block', margin: '32px auto' }} />}><DiscoverPage /></Suspense>,
      },
    ] : []),
  ];

  return (
    <div style={{ maxWidth: 720, margin: '0 auto' }}>
      {/* Cover Photo Banner */}
      <div
        style={{
          width: '100%',
          height: isMobile ? 180 : 280,
          borderRadius: '0 0 16px 16px',
          overflow: 'hidden',
          position: 'relative',
          background: coverPhotoUrl
            ? `url(${coverPhotoUrl}) center/cover no-repeat`
            : `linear-gradient(135deg, ${primaryColor}33, ${primaryColor}11)`,
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        {!coverPhotoUrl && (
          <CameraOutlined style={{ fontSize: 48, color: 'rgba(255,255,255,0.2)' }} />
        )}
        <Upload
          showUploadList={false}
          accept="image/jpeg,image/png,image/webp"
          beforeUpload={(file) => {
            handlePhotoUpload(file);
            return false;
          }}
        >
          <Button
            icon={<CameraOutlined />}
            loading={uploading}
            style={{
              position: 'absolute',
              bottom: 12,
              right: 12,
              opacity: 0.85,
            }}
            size="small"
          >
            {coverPhotoUrl ? 'Change Photo' : 'Add Photo'}
          </Button>
        </Upload>
      </div>

      {/* Profile Header */}
      <div
        style={{
          display: 'flex',
          alignItems: isMobile ? 'flex-start' : 'center',
          gap: 16,
          padding: '20px 16px 0',
          flexDirection: isMobile ? 'column' : 'row',
        }}
      >
        <Avatar
          size={isMobile ? 56 : 72}
          style={{
            backgroundColor: SOURCE_AVATAR_COLORS[profile.primarySource],
            fontWeight: 600,
            fontSize: isMobile ? 20 : 28,
            marginTop: isMobile ? -28 : -36,
            border: '3px solid',
            borderColor: themeToken.colorBgContainer,
          }}
        >
          {getInitials(profile.displayName)}
        </Avatar>
        <div style={{ flex: 1 }}>
          <Typography.Title level={isMobile ? 4 : 3} style={{ margin: 0 }}>
            {profile.displayName}
          </Typography.Title>
          <Space size={6} style={{ marginTop: 4 }} wrap>
            <Tag color={CONTACT_SOURCE_COLORS[profile.primarySource]}>
              {CONTACT_SOURCE_LABELS[profile.primarySource]}
            </Tag>
            {profile.supportLevel && (
              <Tag color={SUPPORT_LEVEL_COLORS[profile.supportLevel]}>
                {SUPPORT_LEVEL_LABELS[profile.supportLevel]}
              </Tag>
            )}
            {profile.tags.map((t) => (
              <Tag key={t}>{t}</Tag>
            ))}
          </Space>
        </div>
        <Space size={12} align="start">
          {profile.isOwnProfile && profile.enableSocial && (
            <Suspense fallback={null}>
              <NotificationBell />
            </Suspense>
          )}
          <div style={{ textAlign: 'center' }}>
            <Progress
              type="circle"
              percent={profile.engagementScore}
              size={isMobile ? 56 : 72}
              strokeColor={primaryColor}
              format={(pct) => <span style={{ fontSize: isMobile ? 14 : 18, fontWeight: 600 }}>{pct}</span>}
            />
            <Typography.Text type="secondary" style={{ display: 'block', fontSize: 11, marginTop: 4 }}>
              Engagement
            </Typography.Text>
          </div>
        </Space>
      </div>

      {/* Engagement Summary Bar */}
      <div
        style={{
          display: 'flex',
          gap: 8,
          padding: '16px',
          flexWrap: 'wrap',
          justifyContent: 'center',
        }}
      >
        {profile.engagement.emailsSent > 0 && (
          <Tag icon={<MailOutlined />}>{profile.engagement.emailsSent} emails</Tag>
        )}
        {profile.engagement.shiftsSignedUp > 0 && (
          <Tag icon={<ScheduleOutlined />}>{profile.engagement.shiftsSignedUp} shifts</Tag>
        )}
        {profile.engagement.canvassVisits > 0 && (
          <Tag icon={<TeamOutlined />}>{profile.engagement.canvassVisits} visits</Tag>
        )}
        {profile.engagement.donationCount > 0 && (
          <Tag icon={<HeartOutlined />}>{profile.engagement.donationCount} donations</Tag>
        )}
        {profile.engagement.videoViews > 0 && (
          <Tag icon={<VideoCameraOutlined />}>{profile.engagement.videoViews} views</Tag>
        )}
        {profile.engagement.responsesSubmitted > 0 && (
          <Tag icon={<ThunderboltOutlined />}>{profile.engagement.responsesSubmitted} responses</Tag>
        )}
      </div>

      {/* Tabs */}
      <div style={{ padding: '0 16px 32px' }}>
        <Tabs items={tabItems} size="large" />
      </div>

      {/* Footer */}
      <div style={{ textAlign: 'center', padding: '16px', borderTop: '1px solid rgba(255,255,255,0.06)' }}>
        <Typography.Text type="secondary" style={{ fontSize: 12 }}>
          {profile.branding.organizationName}
        </Typography.Text>
      </div>
    </div>
  );
}

/** Activity timeline sub-component */
function ActivityTab({
  activities,
  pagination,
  loading,
  onPageChange,
  onLoad,
}: {
  activities: ContactActivityItem[];
  pagination: PaginationMeta | null;
  loading: boolean;
  onPageChange: (page: number) => void;
  onLoad: () => void;
}) {
  useEffect(() => {
    onLoad();
  }, []); // eslint-disable-line react-hooks/exhaustive-deps

  if (loading && activities.length === 0) {
    return (
      <div style={{ textAlign: 'center', padding: 32 }}>
        <Spin />
      </div>
    );
  }

  if (activities.length === 0) {
    return <Typography.Text type="secondary">No activity yet.</Typography.Text>;
  }

  return (
    <div>
      <Timeline
        items={activities.map((a) => ({
          dot: ACTIVITY_ICONS[a.type] || undefined,
          children: (
            <div>
              <Typography.Text strong style={{ fontSize: 13 }}>{a.title}</Typography.Text>
              {a.description && (
                <Typography.Text type="secondary" style={{ display: 'block', fontSize: 12 }}>
                  {a.description}
                </Typography.Text>
              )}
              <Typography.Text type="secondary" style={{ display: 'block', fontSize: 11, marginTop: 2 }}>
                {new Date(a.occurredAt).toLocaleDateString(undefined, {
                  year: 'numeric',
                  month: 'short',
                  day: 'numeric',
                  hour: '2-digit',
                  minute: '2-digit',
                })}
              </Typography.Text>
            </div>
          ),
        }))}
      />
      {pagination && pagination.totalPages > 1 && (
        <div style={{ textAlign: 'center', marginTop: 16 }}>
          <Space>
            <Button
              size="small"
              disabled={pagination.page <= 1}
              onClick={() => onPageChange(pagination.page - 1)}
            >
              Previous
            </Button>
            <Typography.Text type="secondary">
              Page {pagination.page} of {pagination.totalPages}
            </Typography.Text>
            <Button
              size="small"
              disabled={pagination.page >= pagination.totalPages}
              onClick={() => onPageChange(pagination.page + 1)}
            >
              Next
            </Button>
          </Space>
        </div>
      )}
    </div>
  );
}
