// Main app
const { useState: useStateA, useEffect: useEffectA, useMemo: useMemoA } = React;

const ACCENT_VALUES = {
  indigo:  { accent: '#4F46E5', soft: '#EEF2FF', ink: '#312E81' },
  emerald: { accent: '#059669', soft: '#D1FAE5', ink: '#064E3B' },
  rose:    { accent: '#E11D48', soft: '#FFE4E6', ink: '#881337' },
  amber:   { accent: '#D97706', soft: '#FEF3C7', ink: '#78350F' },
  stone:   { accent: '#1C1917', soft: '#F5F5F4', ink: '#1C1917' },
};

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "density": "default",
  "theme": "light",
  "accent": "indigo",
  "qcBadge": "on"
}/*EDITMODE-END*/;

const PEOPLE_PAGE_SIZE = 200;

// API Configuration
const API_URL = window.__API_URL__ || 'http://localhost:8001';

// Login Component
function LoginForm({ onLogin, loading, error }) {
  const [email, setEmail] = React.useState('');
  const [password, setPassword] = React.useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    if (email && password) {
      onLogin(email, password);
    }
  };

  return (
    <div className="login-container">
      <div className="login-card">
        <div className="login-header">
          <h2>SOPHI</h2>
          <p><b>So</b>cial <b>P</b>rofile <b>H</b>andle <b>I</b>dentifier</p>
        </div>
        
        <form onSubmit={handleSubmit} className="login-form">
          {error && (
            <div className="login-error">
              <Icon name="alert" size={14} />
              {error}
            </div>
          )}
          
          <div className="login-field">
            <label htmlFor="email">Email</label>
            <input
              id="email"
              type="email"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              placeholder="user@example.com"
              required
              disabled={loading}
            />
          </div>
          
          <div className="login-field">
            <label htmlFor="password">Password</label>
            <input
              id="password"
              type="password"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              placeholder="Enter your password"
              required
              disabled={loading}
            />
          </div>
          
          <button 
            type="submit" 
            className="login-btn"
            disabled={loading || !email || !password}
          >
            {loading ? (
              <>
                <Icon name="loader" size={14} />
                Signing in...
              </>
            ) : (
              <>
                <Icon name="login" size={14} />
                Sign In
              </>
            )}
          </button>
        </form>
      </div>
    </div>
  );
}

function App() {
  const [people, setPeople] = useStateA([]);
  const [loading, setLoading] = useStateA(true);
  const [error, setError] = useStateA(null);
  const [route, setRoute] = useStateA({ view: 'dashboard', personId: null });
  const [filters, setFilters] = useStateA({ q: '', status: 'all', source: 'all' });
  const [showExport, setShowExport] = useStateA(false);
  const [tweaks, setTweaks] = useStateA(TWEAK_DEFAULTS);
  const [tweaksOpen, setTweaksOpen] = useStateA(false);
  const [toast, setToast] = useStateA(null);
  const [collide, setCollide] = useStateA(null); // { person, lock }
  const [isAuthenticated, setIsAuthenticated] = useStateA(false);
  const [authToken, setAuthToken] = useStateA(null);
  const [loginLoading, setLoginLoading] = useStateA(false);
  const [loginError, setLoginError] = useStateA(null);
  const [currentUser, setCurrentUser] = useStateA(null);
  const [teamActivity, setTeamActivity] = useStateA([]);
  const [teamStats, setTeamStats] = useStateA([]);
  const [peoplePage, setPeoplePage] = useStateA(1);
  const [peopleTotal, setPeopleTotal] = useStateA(0);
  const [peopleForCounts, setPeopleForCounts] = useStateA([]);
  const [hasLoadedPeople, setHasLoadedPeople] = useStateA(false);

  // When filters change, restart pagination from the first page.
  useEffectA(() => {
    setPeoplePage(1);
  }, [filters.q, filters.status, filters.source]);

  // Active soft-locks (others who opened a person in the last 5 minutes)
  const locks = useMemoA(() => getActiveLocks(teamActivity, currentUser), [teamActivity, currentUser]);

  // Check for existing auth token on load
  useEffectA(() => {
    const token = localStorage.getItem('auth_token');
    const tokenType = localStorage.getItem('token_type');
    if (token && tokenType) {
      setAuthToken(token);
      setIsAuthenticated(true);
      // Fetch user info if we have a token
      fetchUserInfo(token);
    }
  }, []);
  
  // Debug: log people state changes
  useEffectA(() => {
    console.log('People state updated:', people, 'length:', people?.length);
  }, [people]);

  // Persist route
  useEffectA(() => {
    const saved = localStorage.getItem('shqt_route');
    if (!saved) return;
    try {
      const parsed = JSON.parse(saved);
      const allowedViews = new Set(['dashboard', 'detail', 'qc', 'report', 'activity', 'source', 'guide']);
      if (!parsed || !allowedViews.has(parsed.view)) {
        setRoute({ view: 'dashboard', personId: null });
        return;
      }
      // Never restore login route into authenticated shell.
      setRoute(parsed.view === 'login' ? { view: 'dashboard', personId: null } : parsed);
    } catch {
      setRoute({ view: 'dashboard', personId: null });
    }
  }, []);
  useEffectA(() => { localStorage.setItem('shqt_route', JSON.stringify(route)); }, [route]);

  // Tweaks protocol
  useEffectA(() => {
    const handler = (e) => {
      if (e.data?.type === '__activate_edit_mode') setTweaksOpen(true);
      else if (e.data?.type === '__deactivate_edit_mode') setTweaksOpen(false);
    };
    window.addEventListener('message', handler);
    window.parent.postMessage({type: '__edit_mode_available'}, '*');
    return () => window.removeEventListener('message', handler);
  }, []);

  // Persist tweaks via host
  useEffectA(() => {
    window.parent.postMessage({type: '__edit_mode_set_keys', edits: tweaks}, '*');
  }, [tweaks]);

  // Apply tweaks to body
  useEffectA(() => {
    document.body.dataset.density = tweaks.density;
    document.body.dataset.theme = tweaks.theme;
    const a = ACCENT_VALUES[tweaks.accent] || ACCENT_VALUES.indigo;
    document.documentElement.style.setProperty('--accent', a.accent);
    document.documentElement.style.setProperty('--accent-2', a.soft);
    document.documentElement.style.setProperty('--accent-ink', a.ink);
  }, [tweaks]);

  // "/" opens search
  useEffectA(() => {
    const h = (e) => {
      if (e.key === '/' && route.view === 'dashboard' && e.target.tagName !== 'INPUT') {
        e.preventDefault();
        document.querySelector('.search input')?.focus();
      }
    };
    window.addEventListener('keydown', h);
    return () => window.removeEventListener('keydown', h);
  }, [route.view]);

  // Toast helper
  const onToast = (msg) => {
    setToast(msg);
    clearTimeout(window.__toastT);
    window.__toastT = setTimeout(() => setToast(null), 1800);
  };

  // Auth utility functions
  const makeAuthenticatedRequest = async (url, options = {}) => {
    const headers = {
      'Content-Type': 'application/json',
      ...options.headers
    };
    
    if (authToken) {
      headers['Authorization'] = `Bearer ${authToken}`;
    }
    
    return fetch(url, {
      ...options,
      headers
    });
  };

  // Fetch current user info
  const fetchUserInfo = async (token = authToken) => {
    try {
      const response = await fetch(`${API_URL}/auth/me`, {
        method: 'GET',
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json'
        }
      });
      
      if (!response.ok) {
        if (response.status === 401) {
          // Token expired or invalid
          handleLogout();
          return;
        }
        throw new Error(`Failed to fetch user info: ${response.status} ${response.statusText}`);
      }
      
      const userData = await response.json();
      setCurrentUser(userData);
      console.log('User info fetched:', userData);
    } catch (error) {
      console.error('Error fetching user info:', error);
      // Don't logout for user info fetch errors, just log them
    }
  };

  // Fetch team activity
  const fetchTeamActivity = async ({ updateState = true } = {}) => {
    try {
      const response = await makeAuthenticatedRequest(`${API_URL}/team/activity?limit=50`);
      
      if (!response.ok) {
        if (response.status === 401) {
          handleLogout();
          return [];
        }
        throw new Error(`Failed to fetch team activity: ${response.status} ${response.statusText}`);
      }
      
      const activityData = await response.json();
      const rows = activityData.data || [];
      if (updateState) setTeamActivity(rows);
      console.log('Team activity fetched:', activityData);
      return rows;
    } catch (error) {
      console.error('Error fetching team activity:', error);
      if (updateState) setTeamActivity([]);
      return [];
    }
  };

  const fetchLogs = async ({ limit = 500, skip = 0 } = {}) => {
    const params = new URLSearchParams({ limit, skip });
    const response = await makeAuthenticatedRequest(`${API_URL}/logs?${params}`);
    if (!response.ok) throw new Error(`Failed to fetch logs: ${response.status}`);
    return response.json();
  };

  const fetchTeamStats = async () => {
    try {
      const response = await makeAuthenticatedRequest(`${API_URL}/team/statistics`);
      if (!response.ok) {
        if (response.status === 401) { handleLogout(); return; }
        throw new Error(`Failed to fetch team statistics: ${response.status}`);
      }
      const data = await response.json();
      setTeamStats(data.data || []);
    } catch (error) {
      console.error('Error fetching team statistics:', error);
      setTeamStats([]);
    }
  };

    // Helper function to transform single person response
    const transformSinglePerson = (item) => {
      const getProfileStatus = (tool, mc, selected, originalStatus) => {
        if (tool && mc && selected && tool === mc && mc === selected) {
          return 'trusted';
        }
        return originalStatus === 'trusted' ? 'unverified' : originalStatus;
      };

      const person = {
        id: item.id,
        name: item.name,
        source: item.source || 'API',
        country: item.profile?.country?.selected || '',
        category: item.profile?.category?.selected || '',
        profile: {
          country: {
            sports: item.profile?.country?.tool || '',
            panel: item.profile?.country?.mc || '',
            merged: item.profile?.country?.selected || '',
            status: getProfileStatus(
              item.profile?.country?.tool,
              item.profile?.country?.mc,
              item.profile?.country?.selected,
              item.profile?.country?.status || 'missing'
            ),
            verified_by: item.profile?.country?.verified_by || null,
          },
          category: {
            sports: item.profile?.category?.tool || '',
            panel: item.profile?.category?.mc || '',
            merged: item.profile?.category?.selected || '',
            status: getProfileStatus(
              item.profile?.category?.tool,
              item.profile?.category?.mc,
              item.profile?.category?.selected,
              item.profile?.category?.status || 'missing'
            ),
            verified_by: item.profile?.category?.verified_by || null,
          },
        },
        handles: {}
      };

      // Initialize all platforms
      for (const platform of PLATFORMS) {
        person.handles[platform.id] = [];
      }

      // Process handles from API
      const apiHandles = item.handles || [];
      for (const handle of apiHandles) {
        const platform = handle.platform;
        if (!person.handles[platform]) {
          person.handles[platform] = [];
        }
        person.handles[platform].push({
          sports: handle.tool_handle || '',
          panel: handle.mc_handle || '',
          merged: handle.selected || '',
          status: handle.status || 'missing',
          verified_by: handle.verified_by || null,
        });
      }

      // Ensure every platform has at least one handle
      for (const platform of PLATFORMS) {
        if (!person.handles[platform.id] || person.handles[platform.id].length === 0) {
          person.handles[platform.id] = [{
            sports: '',
            panel: '',
            merged: '',
            status: 'missing',
          }];
        }
      }

      return person;
    };

    // Fetch latest person details from API
    const fetchPersonDetail = async (personId) => {
      try {
        const response = await makeAuthenticatedRequest(`${API_URL}/people/${personId}`);
        if (!response.ok) {
          if (response.status === 401) { handleLogout(); return; }
          if (response.status === 404) {
            console.warn(`Person ${personId} not found`);
            return;
          }
          throw new Error(`Failed to fetch person details: ${response.status}`);
        }
      
        const data = await response.json();
        const apiItem = data.data || data;
        const transformedPerson = transformSinglePerson(apiItem);
      
        // Update the person in the people array
        setPeople(prevPeople => {
          if (!Array.isArray(prevPeople)) return prevPeople;
          return prevPeople.map(p => p.id === personId ? transformedPerson : p);
        });
      
        console.log('Fetched latest person details:', transformedPerson);
      } catch (error) {
        console.error('Error fetching person details:', error);
      }
    };

  // Login function
  const handleLogin = async (email, password) => {
    setLoginLoading(true);
    setLoginError(null);
    
    try {
      const response = await fetch(`${API_URL}/auth/login`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          email,
          password
        })
      });

      if (!response.ok) {
        const errorData = await response.json().catch(() => ({}));
        throw new Error(errorData.detail || `Login failed: ${response.status} ${response.statusText}`);
      }

      const data = await response.json();
      
      if (!data.access_token) {
        throw new Error('No access token received');
      }

      // Store token and token type
      localStorage.setItem('auth_token', data.access_token);
      localStorage.setItem('token_type', data.token_type || 'Bearer');
      
      setAuthToken(data.access_token);
      setIsAuthenticated(true);
      setRoute({ view: 'dashboard', personId: null });
      onToast('Login successful');
      
      // Fetch user info and people data after successful login
      fetchUserInfo(data.access_token);
      fetchPeople();
      fetchTeamActivity();
      fetchTeamStats();
      
    } catch (err) {
      console.error('Login error:', err);
      setLoginError(err.message);
      onToast('Login failed');
    } finally {
      setLoginLoading(false);
    }
  };

  // Logout function
  const handleLogout = () => {
    localStorage.removeItem('auth_token');
    localStorage.removeItem('token_type');
    localStorage.removeItem('shqt_route');
    setAuthToken(null);
    setIsAuthenticated(false);
    setCurrentUser(null);
    setPeople([]);
    setPeopleForCounts([]);
    setPeoplePage(1);
    setPeopleTotal(0);
    setHasLoadedPeople(false);
    setRoute({ view: 'login', personId: null });
    onToast('Logged out successfully');
  };

  // Fetch people data from API
  useEffectA(() => {
    const fetchPeople = async () => {
      if (!isAuthenticated || !authToken) {
        setLoading(false);
        return;
      }
      
      try {
        // Keep dashboard mounted during incremental refetches (search/filter/paging)
        if (!hasLoadedPeople) setLoading(true);
        setError(null);
        console.log('Fetching data from API...');

        const transformPeopleRows = (rows) => {
          // Transform API data to match app structure
          const transformedData = rows.map(item => {
          console.log('Transforming item:', item.name);
          
          // Helper function to determine profile status
          const getProfileStatus = (tool, mc, selected, originalStatus) => {
            // If all three values are the same and not empty, it's trusted
            if (tool && mc && selected && tool === mc && mc === selected) {
              return 'trusted';
            }
            // Otherwise use the verification workflow
            return originalStatus === 'trusted' ? 'unverified' : originalStatus;
          };
          
          return {
            id: item.id,
            name: item.name,
            source: item.source || 'API',
            country: item.profile?.country?.selected || '',
            category: item.profile?.category?.selected || '',
            profile: {
              country: {
                sports: item.profile?.country?.tool || '',
                panel: item.profile?.country?.mc || '',
                merged: item.profile?.country?.selected || '',
                status: getProfileStatus(
                  item.profile?.country?.tool,
                  item.profile?.country?.mc,
                  item.profile?.country?.selected,
                  item.profile?.country?.status || 'missing'
                ),
                verified_by: item.profile?.country?.verified_by || null,
              },
              category: {
                sports: item.profile?.category?.tool || '',
                panel: item.profile?.category?.mc || '',
                merged: item.profile?.category?.selected || '',
                status: getProfileStatus(
                  item.profile?.category?.tool,
                  item.profile?.category?.mc,
                  item.profile?.category?.selected,
                  item.profile?.category?.status || 'missing'
                ),
                verified_by: item.profile?.category?.verified_by || null,
              },
            },
            handles: {}
          };
          });

          // Transform handles - new API format has handles as array with platform info in each handle
          for (const person of transformedData) {
            const apiItem = rows.find(p => p.id === person.id);
          const apiHandles = apiItem?.handles || [];
          
          // Initialize all platforms with empty handles to ensure all platforms show
          for (const platform of PLATFORMS) {
            person.handles[platform.id] = [];
          }
          
          // Process handles from API
          for (const handle of apiHandles) {
            const platform = handle.platform;
            if (!person.handles[platform]) {
              person.handles[platform] = [];
            }
            person.handles[platform].push({
              sports: handle.tool_handle || '',
              panel: handle.mc_handle || '',
              merged: handle.selected || '',
              status: handle.status || 'missing',
              verified_by: handle.verified_by || null,
            });
          }
          
          // Ensure every platform has at least one handle (even if empty)
          for (const platform of PLATFORMS) {
            if (!person.handles[platform.id] || person.handles[platform.id].length === 0) {
              person.handles[platform.id] = [{
                sports: '',
                panel: '',
                merged: '',
                status: 'missing',
              }];
            }
          }
          }

          return transformedData;
        };

        // Load all people once (supports APIs that paginate by default).
        const allRows = [];
        const seenIds = new Set();
        let skip = 0;
        let totalHint = null;

        for (let i = 0; i < 500; i++) {
          const params = new URLSearchParams();
          if (skip > 0) params.set('skip', String(skip));
          const url = params.toString()
            ? `${API_URL}/people?${params.toString()}`
            : `${API_URL}/people`;

          const response = await makeAuthenticatedRequest(url);
          if (!response.ok) {
            if (response.status === 401) {
              handleLogout();
              throw new Error('Authentication expired. Please log in again.');
            }
            throw new Error(`HTTP ${response.status}: ${response.statusText}`);
          }

          const apiData = await response.json();
          if (!apiData.data || !Array.isArray(apiData.data)) {
            throw new Error('Invalid API response structure - missing data array');
          }

          if (totalHint === null) {
            const n = Number(
              apiData.total ??
              apiData.total_count ??
              apiData.count ??
              apiData.pagination?.total ??
              apiData.meta?.total
            );
            totalHint = Number.isFinite(n) ? n : null;
          }

          const batch = apiData.data;
          let addedThisBatch = 0;
          for (const item of batch) {
            const itemId = item.id || `${item.name || ''}:${item.source || ''}`;
            if (!seenIds.has(itemId)) {
              seenIds.add(itemId);
              allRows.push(item);
              addedThisBatch++;
            }
          }

          if (batch.length === 0 || addedThisBatch === 0) break;
          skip += batch.length;
          if (totalHint !== null && allRows.length >= totalHint) break;
        }

        const transformedData = transformPeopleRows(allRows);
        console.log('Loaded people rows:', allRows.length, 'transformed:', transformedData.length);
        setPeople(transformedData);
        setPeopleForCounts(transformedData);
        setPeopleTotal(totalHint !== null ? totalHint : transformedData.length);
        setHasLoadedPeople(true);
      } catch (err) {
        console.error('API fetch error:', err);
        console.log('Using fallback data due to API error');
        
        // Create fallback test data 
        const fallbackData = [
          {
            id: '507f1f77bcf86cd799439011',
            name: 'John Doe',
            source: 'SportsTool',
            country: 'USA',
            category: 'Athlete',
            profile: {
              country: {
                sports: 'United States',
                panel: 'USA',
                merged: 'USA',
                status: 'verified',
              },
              category: {
                sports: 'Professional Athlete',
                panel: 'Athlete',
                merged: 'Athlete',
                status: 'unverified',
              },
            },
            handles: {
              instagram: [{
                sports: 'johndoe.official',
                panel: 'johndoe_athlete',
                merged: 'johndoe.official',
                status: 'verified',
              }],
              youtube: [{
                sports: '',
                panel: 'JohnDoeVlogs',
                merged: 'JohnDoeVlogs',
                status: 'unverified',
              }],
              tiktok: [{
                sports: '',
                panel: '',
                merged: '',
                status: 'missing',
              }],
              x: [{
                sports: 'johnanthlete',
                panel: 'johnanthlete',
                merged: 'johnanthlete',
                status: 'verified',
              }],
              facebook: [{
                sports: '',
                panel: '',
                merged: '',
                status: 'missing',
              }],
              twitch: [{
                sports: '',
                panel: '',
                merged: '',
                status: 'missing',
              }],
            }
          }
        ];
        console.log('Using fallback data:', fallbackData);
        setPeople(fallbackData);
        setPeopleForCounts(fallbackData);
        setPeopleTotal(fallbackData.length);
        setHasLoadedPeople(true);
      } finally {
        console.log('Setting loading to false');
        setLoading(false);
      }
    };
    fetchPeople();
  }, [isAuthenticated, authToken]);

  // Fetch team activity periodically (skip auto-refresh on Activity log page)
  useEffectA(() => {
    if (!isAuthenticated || !authToken) return;
    
    // Fetch immediately
    fetchTeamActivity();
    fetchTeamStats();
    
    // Don't auto-refresh intervals when on the Activity log page
    // User can manually refresh there
    const isOnActivityPage = route.view === 'activity';
    
    // Presence should feel live, so refresh activity more frequently (but not on activity page).
    const activityInterval = !isOnActivityPage ? setInterval(() => { fetchTeamActivity(); }, 8000) : null;
    const statsInterval = !isOnActivityPage ? setInterval(() => { fetchTeamStats(); }, 30000) : null;

    // Refresh as soon as the tab becomes active again.
    const refreshNow = () => { fetchTeamActivity(); };
    const onVisibilityChange = () => {
      if (document.visibilityState === 'visible') refreshNow();
    };
    window.addEventListener('focus', refreshNow);
    document.addEventListener('visibilitychange', onVisibilityChange);
    
    return () => {
      if (activityInterval) clearInterval(activityInterval);
      if (statsInterval) clearInterval(statsInterval);
      window.removeEventListener('focus', refreshNow);
      document.removeEventListener('visibilitychange', onVisibilityChange);
    };
  }, [isAuthenticated, authToken, route.view]);

  // Post a status-change log entry
  const postLog = async (personId, platform, accountType, statusChange, newValue) => {
    try {
      const person = people.find(p => p.id === personId);
      const logData = {
        person_id: personId,
        person_name: person?.name || 'Unknown',
        user_name: currentUser?.name || 'Unknown',
        platform,
        account_type: accountType,
        status_change: statusChange,
        new_value: newValue || null,
        since: new Date().toISOString(),
      };
      
      const response = await makeAuthenticatedRequest(`${API_URL}/logs`, {
        method: 'POST',
        body: JSON.stringify(logData),
      });
      
      if (!response.ok) {
        const errorData = await response.text();
        console.error('Log API error:', response.status, errorData);
      }
    } catch (err) {
      console.error('Failed to post log:', err);
    }
  };

  // API call to update a single field
  const updatePersonField = async (personId, updateData) => {
    try {
      console.log('Updating person field:', personId, updateData);
      const response = await makeAuthenticatedRequest(`${API_URL}/people/${personId}/update`, {
        method: 'PATCH',
        body: JSON.stringify(updateData)
      });
      
      if (!response.ok) {
        throw new Error(`API update failed: ${response.status} ${response.statusText}`);
      }
      
      console.log('Successfully updated person field');
      return { success: true };
    } catch (error) {
      console.error('Error updating person field:', error);
      return { success: false, error: error.message };
    }
  };

  const updateHandle = async (personId, platformId, handleIndex, mutator) => {
    const originalPerson = people.find(p => p.id === personId);
    if (!originalPerson) return;
    
    const originalHandle = Array.isArray(originalPerson.handles[platformId]) 
      ? originalPerson.handles[platformId][handleIndex]
      : originalPerson.handles[platformId];
    
    // Apply the mutation to get the new handle
    const newHandle = mutator(originalHandle);
    
    // Check if anything actually changed
    const hasChanges = originalHandle.status !== newHandle.status || originalHandle.merged !== newHandle.merged;
    if (!hasChanges) {
      // Update local state only (no API call needed)
      setPeople(ps => ps.map(p => {
        if (p.id !== personId) return p;
        const handles = [...p.handles[platformId]];
        handles[handleIndex] = newHandle;
        return { ...p, handles: { ...p.handles, [platformId]: handles } };
      }));
      return;
    }

    // Show loading state and update optimistically
    setPeople(ps => ps.map(p => {
      if (p.id !== personId) return p;
      const handles = [...p.handles[platformId]];
      handles[handleIndex] = { ...newHandle, _updating: true };
      return { ...p, handles: { ...p.handles, [platformId]: handles } };
    }));
    
    // Determine handle type based on index (0 = main, 1+ = second)
    const handleType = handleIndex === 0 ? "main" : "second";
    
    const updateData = {
      handle: {
        operation: "update",
        platform: platformId,
        type: handleType,
        selected: newHandle.merged || '',
        status: newHandle.status
      }
    };
    
    const result = await updatePersonField(personId, updateData);
    
    if (result.success) {
      // Remove loading state
      setPeople(ps => ps.map(p => {
        if (p.id !== personId) return p;
        const handles = [...p.handles[platformId]];
        const { _updating, ...cleanHandle } = handles[handleIndex];
        handles[handleIndex] = cleanHandle;
        return { ...p, handles: { ...p.handles, [platformId]: handles } };
      }));
      // Log status changes
      if (originalHandle.status !== newHandle.status) {
        postLog(
          personId,
          platformId,
          handleIndex === 0 ? 'main' : 'second',
          newHandle.status,
          newHandle.merged || null,
        );
      }
      onToast('✓ Handle updated successfully');
    } else {
      // Revert to original state and show error
      setPeople(ps => ps.map(p => {
        if (p.id !== personId) return p;
        const handles = [...p.handles[platformId]];
        handles[handleIndex] = originalHandle;
        return { ...p, handles: { ...p.handles, [platformId]: handles } };
      }));
      onToast(`❌ Failed to update handle: ${result.error}`);
    }
  };

  const updateProfile = async (personId, key, mutator) => {
    const originalPerson = people.find(p => p.id === personId);
    if (!originalPerson) return;
    
    const originalProfile = originalPerson.profile[key];
    let newProfile = mutator(originalProfile);
    
    // Auto-set to trusted if tool, mc, and selected all match
    const { sports: tool, panel: mc, merged: selected } = newProfile;
    if (tool && mc && selected && tool === mc && mc === selected) {
      newProfile = { ...newProfile, status: 'trusted' };
    } else if (newProfile.status === 'trusted' && !(tool === mc && mc === selected)) {
      // If it was trusted but values no longer match, reset to unverified
      newProfile = { ...newProfile, status: 'unverified' };
    }
    
    // Check if anything actually changed
    const hasChanges = originalProfile.status !== newProfile.status || originalProfile.merged !== newProfile.merged;
    if (!hasChanges) {
      // Update local state only (no API call needed)
      setPeople(ps => ps.map(p => {
        if (p.id !== personId) return p;
        const next = { ...p.profile, [key]: newProfile };
        return { ...p, profile: next, [key]: next[key].merged };
      }));
      return;
    }

    // Show loading state and update optimistically
    setPeople(ps => ps.map(p => {
      if (p.id !== personId) return p;
      const next = { ...p.profile, [key]: { ...newProfile, _updating: true } };
      return { ...p, profile: next, [key]: next[key].merged };
    }));
    
    const updateData = {
      profile: {
        field: key,
        selected: newProfile.merged || '',
        status: newProfile.status
      }
    };
    
    const result = await updatePersonField(personId, updateData);
    
    if (result.success) {
      // Remove loading state
      setPeople(ps => ps.map(p => {
        if (p.id !== personId) return p;
        const { _updating, ...cleanProfile } = p.profile[key];
        const next = { ...p.profile, [key]: cleanProfile };
        return { ...p, profile: next, [key]: next[key].merged };
      }));
      // Log status changes
      if (originalProfile.status !== newProfile.status) {
        postLog(
          personId,
          key,
          '',
          newProfile.status,
          newProfile.merged || null,
        );
      }
      onToast(`✓ ${key.charAt(0).toUpperCase() + key.slice(1)} updated successfully`);
    } else {
      // Revert to original state and show error
      setPeople(ps => ps.map(p => {
        if (p.id !== personId) return p;
        const next = { ...p.profile, [key]: originalProfile };
        return { ...p, profile: next, [key]: next[key].merged };
      }));
      onToast(`❌ Failed to update ${key}: ${result.error}`);
    }
  };

  // Save person data to API
  const savePerson = async (personId) => {
    const person = people.find(p => p.id === personId);
    if (!person) {
      onToast('❌ Person not found');
      return false;
    }

    try {
      // Build the update payload
      const payload = {
        handle_updates: [],
        handle_additions: [],
        profile_updates: []
      };

      // Add profile updates (country and category)
      ['country', 'category'].forEach(field => {
        const profileField = person.profile[field];
        if (profileField && profileField.merged) {
          payload.profile_updates.push({
            field: field,
            selected: profileField.merged,
            status: profileField.status === 'qc' ? 'verified' : profileField.status
          });
        }
      });

      // Add handle updates and additions
      PLATFORMS.forEach(platform => {
        const handles = person.handles[platform.id];
        const handlesArray = Array.isArray(handles) ? handles : [handles];
        
        handlesArray.forEach(handle => {
          if (handle.merged) {
            // Check if this is an update (has original tool_handle or es_handle) or addition
            const hasOriginal = handle.sports || handle.panel;
            
            if (hasOriginal) {
              // This is an update to existing handle
              payload.handle_updates.push({
                platform: platform.id,
                tool_handle: handle.sports || '', 
                es_handle: handle.panel || '',
                selected: handle.merged,
                status: handle.status === 'qc' ? 'verified' : handle.status
              });
            } else {
              // This is a new handle addition
              payload.handle_additions.push({
                platform: platform.id,
                selected: handle.merged,
                status: handle.status === 'unverified' ? 'unverified' : handle.status
              });
            }
          }
        });
      });

      console.log('Saving person:', personId, 'payload:', payload);

      const response = await makeAuthenticatedRequest(`${API_URL}/people/${personId}/update`, {
        method: 'POST',
        body: JSON.stringify(payload),
      });

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }

      const result = await response.json();
      console.log('Save response:', result);
      
      onToast('✅ Changes saved successfully');
      return true;
    } catch (err) {
      console.error('Save error:', err);
      onToast(`❌ Save failed: ${err.message}`);
      return false;
    }
  };

  // Match Dashboard row sequence so Review queue keeps All records order.
  const allRecordsOrdered = useMemoA(() => {
    if (!Array.isArray(people)) return [];
    let rows = people.map(p => ({
      p,
      counts: computeCounts(p, PLATFORMS),
      profCounts: computeProfileCounts(p),
    }));

    if (filters.q) {
      const q = filters.q.toLowerCase();
      rows = rows.filter(({ p }) =>
        (p.name || '').toLowerCase().includes(q) ||
        (p.category || '').toLowerCase().includes(q) ||
        (p.country || '').toLowerCase().includes(q)
      );
    }

    if (filters.status !== 'all') {
      rows = rows.filter(({ counts, profCounts }) => {
        const profPending = profCounts.unverified > 0 || profCounts.verified > 0;
        const profDone = profCounts.qc === profCounts.total;
        if (filters.status === 'complete') return counts.complete && profDone;
        if (filters.status === 'review') return counts.unverified > 0 || counts.missing > 0 || profCounts.unverified > 0;
        if (filters.status === 'qc') return (counts.verified > 0 || profCounts.verified > 0) && !(counts.complete && profDone);
        if (filters.status === 'attrs') return profPending;
        return true;
      });
    }

    if (filters.source !== 'all') {
      rows = rows.filter(({ p }) => p.source === filters.source);
    }

    return rows.map(({ p }) => p);
  }, [people, filters]);

  // Queue: people with work pending, preserving All records order.
  const queue = useMemoA(() => {
    if (!Array.isArray(allRecordsOrdered)) return [];
    return allRecordsOrdered
      .map(p => ({ p, c: computeCounts(p, PLATFORMS) }))
      .filter(({c}) => !c.complete)
      .map(({p}) => p);
  }, [allRecordsOrdered]);

  const currentPerson = Array.isArray(people) ? people.find(p => p.id === route.personId) : null;

  const goNext = () => {
    const list = queue.length ? queue : allRecordsOrdered;
    if (!Array.isArray(list) || list.length === 0) return;
    const idx = list.findIndex(p => p.id === route.personId);

    // Prefer the next unlocked record.
    for (let step = 1; step <= list.length; step++) {
      const candidate = list[(idx + step + list.length) % list.length];
      if (!candidate) continue;
      if (!locks[String(candidate.id)]) {
        tryOpen(candidate.id);
        return;
      }
    }

    // Fallback: if all are currently locked, keep previous behavior.
    const nxt = list[(idx + 1 + list.length) % list.length];
    if (nxt) tryOpen(nxt.id);
  };
  const goPrev = () => {
    const list = queue.length ? queue : allRecordsOrdered;
    const idx = list.findIndex(p => p.id === route.personId);
    const prv = list[(idx - 1 + list.length) % list.length];
    if (prv) tryOpen(prv.id);
  };

  // Global stats for sidebar
  const sideCounts = useMemoA(() => {
    const basePeople = (Array.isArray(peopleForCounts) && peopleForCounts.length > 0) ? peopleForCounts : people;
    if (!Array.isArray(basePeople)) return { review: 0, qc: 0 };
    let review = 0, qc = 0;
    for (const p of basePeople) {
      const c = computeCounts(p, PLATFORMS);
      if (c.unverified > 0) review++;
      if (c.verified > 0) qc += c.verified;
      for (const attrKey of ['country', 'category']) {
        const attr = p.profile?.[attrKey];
        if (attr && attr.status === 'verified') qc++;
      }
    }
    return { review, qc };
  }, [people, peopleForCounts]);

  const openDetail = (id) => setRoute({ view: 'detail', personId: id });
  const backToDashboard = () => setRoute({ view: 'dashboard', personId: null });

  // Soft-collision check: if someone else is on this person, ask first.
  // Bypassed when navigating between people you're already in (Next/Prev still warn).
  const tryOpen = async (id) => {
    let activeLocks = locks;
    const latestActivity = await fetchTeamActivity({ updateState: true });
    if (Array.isArray(latestActivity)) {
      activeLocks = getActiveLocks(latestActivity, currentUser);
    }

    const lock = activeLocks[String(id)];
    const person = Array.isArray(people) ? people.find(p => p.id === id) : null;
    if (lock && person) setCollide({ person, lock });
     else {
       openDetail(id);
       // Fetch latest person data from API
       fetchPersonDetail(id);
     }
  };
  const dismissCollide = () => setCollide(null);
  const proceedCollide = () => {
    if (collide) openDetail(collide.person.id);
     if (collide) fetchPersonDetail(collide.person.id);
    setCollide(null);
  };
  const skipCollide = () => {
    if (!collide) return;
    // Find next queue item that isn't locked by someone else; fall back to next regardless.
    const list = queue.length ? queue : allRecordsOrdered;
    const startIdx = list.findIndex(p => p.id === collide.person.id);
    const ordered = [...list.slice(startIdx + 1), ...list.slice(0, startIdx)];
    const free = ordered.find(p => !locks[p.id]) || ordered[0];
    setCollide(null);
     if (free) {
       openDetail(free.id);
       fetchPersonDetail(free.id);
     }
  };

  return (
    <div className="app">
      {/* Show login form if not authenticated */}
      {!isAuthenticated && (
        <LoginForm 
          onLogin={handleLogin}
          loading={loginLoading}
          error={loginError}
        />
      )}
      
      {/* Main app content - only show when authenticated */}
      {isAuthenticated && (
        <>
          {/* Sidebar */}
          <aside className="sidebar">
        <div className="sb-brand">
          <img src="favicon.svg?v=1" alt="SOPHI" style={{width: 27, height: 27, flexShrink: 0, alignSelf: 'center'}} />
          <div style={{display:'flex', flexDirection:'column', minWidth:0}}>
            <div style={{fontSize:13, fontWeight:600, letterSpacing:'0.05em'}}>SOPHI</div>
            <div style={{fontSize:9, fontWeight:400, color:'var(--muted)', letterSpacing:'0.02em', lineHeight:1}}>Social Profile Handle Identifier</div>
          </div>
        </div>

        <div className="sb-section">Overview</div>
        <div className={`sb-item ${route.view === 'guide' ? 'active' : ''}`} onClick={() => setRoute({view:'guide', personId:null})}>
          <span className="sb-icon"><Icon name="help" size={14}/></span> Guide
        </div>
        <div className={`sb-item ${route.view === 'report' ? 'active' : ''}`} onClick={() => setRoute({view: 'report', personId: null})}>
          <span className="sb-icon"><Icon name="bolt" size={14}/></span> Dashboards
        </div>

        <div className="sb-section">Workspace</div>
        <div className={`sb-item ${route.view === 'dashboard' ? 'active' : ''}`} onClick={backToDashboard}>
          <span className="sb-icon"><Icon name="home" size={14}/></span> All records
          <span className="sb-badge">{loading ? '...' : peopleTotal}</span>
        </div>
        <div className={`sb-item ${route.view === 'detail' ? 'active' : ''}`} onClick={() => {
          if (queue[0]) openDetail(queue[0].id);
        }}>
          <span className="sb-icon"><Icon name="inbox" size={14}/></span> Review queue
          <span className="sb-badge">{sideCounts.review}</span>
        </div>
        <div className={`sb-item ${route.view === 'qc' ? 'active' : ''}`} onClick={() => setRoute({view: 'qc', personId: null})}>
          <span className="sb-icon"><Icon name="lock" size={14}/></span> QC queue
          {tweaks.qcBadge === 'on' && <span className="sb-badge">{sideCounts.qc}</span>}
        </div>

        <div className="sb-section">Data</div>
        <div className={`sb-item ${route.view === 'activity' ? 'active' : ''}`} onClick={() => setRoute({view:'activity', personId:null})}>
          <span className="sb-icon"><Icon name="clock" size={14}/></span> Activity log
        </div>
        <div className={`sb-item ${route.view === 'source' ? 'active' : ''}`} onClick={() => setRoute({view:'source', personId:null})}>
          <span className="sb-icon"><Icon name="bolt" size={14}/></span> Source quality
        </div>
        <div className="sb-item" onClick={() => setShowExport(true)}>
          <span className="sb-icon"><Icon name="export" size={14}/></span> Export
        </div>
        <div className="sb-item" onClick={() => setTweaksOpen(v => !v)}>
          <span className="sb-icon"><Icon name="settings" size={14}/></span> Appearance
        </div>

        <div className="sb-section" style={{display:'flex', alignItems:'center', gap:6}}>
          Team activity
          <span className="live-dot" title="Live"/>
        </div>
        <div className="team-log">
          {teamActivity.length === 0 ? (
            <div style={{padding: '8px 12px', color: 'var(--muted)', fontSize: 12}}>No activity data</div>
          ) : teamActivity.map(t => {
            const initials = t.name ? t.name.split(' ').map(n => n.charAt(0)).join('').toUpperCase().slice(0, 2) : '?';
            const targetPersonId = t.current_person_id || t.personId || t.last_viewed_person?.id;
            const target = targetPersonId && Array.isArray(people) ? people.find(p => p.id === targetPersonId) : null;
            return (
              <div
                key={t.id || t.email}
                className={`team-row ${t.status}`}
                onClick={() => target && openDetail(target.id)}
                title={target ? `Open ${target.name}` : ''}
                style={{cursor: target ? 'pointer' : 'default'}}
              >
                <div className="team-av">
                  <span className="avatar xs">{initials}</span>
                  <span className={`presence ${t.status}`}/>
                </div>
                <div style={{minWidth: 0, flex: 1}}>
                  <div className="team-name">{t.name} <span className="team-role">{t.role}</span></div>
                  <div className="team-act">
                    {t.status === 'offline' ? (
                      <span style={{color:'var(--muted)'}}>Offline · last seen {t.since || 'unknown'}</span>
                    ) : target ? (
                      <>
                        <span className={`team-verb ${t.activity}`}>{t.activity === 'qc' ? 'QC' : 'Review'}</span>
                        <span className="team-target">{target.name}</span>
                        {t.since && <span style={{color:'var(--muted)'}}>· {t.since}</span>}
                      </>
                    ) : (
                      <span style={{color:'var(--muted)'}}>{t.since || ''}</span>
                    )}
                  </div>
                </div>
              </div>
            );
          })}
        </div>

        <div style={{marginTop: 'auto'}}></div>
        <div className="user-profile">
          <div className="avatar">{currentUser?.name ? currentUser.name.charAt(0).toUpperCase() : 'U'}</div>
          <div style={{fontSize: 12, lineHeight: 1.2}}>
            <div style={{fontWeight: 500, color: 'var(--ink)'}}>{currentUser?.name || 'User'}</div>
            <div style={{color: 'var(--muted)', fontSize: 11}}>Authenticated</div>
          </div>
        </div>
        <div className="sb-item" onClick={handleLogout}>
          <span className="sb-icon"><Icon name="logout" size={14}/></span> Sign out
        </div>
      </aside>

      {/* Main */}
      <div className="main">
        {loading ? (
          <div style={{padding: '80px 40px', textAlign: 'center'}}>
            <div style={{fontSize: 24, color: 'var(--muted)', marginBottom: 16}}>Loading data...</div>
            <div style={{color: 'var(--muted)', fontSize: 14}}>Fetching people data from API</div>
          </div>
        ) : error && (!Array.isArray(people) || people.length === 0) ? (
          <div style={{padding: '80px 40px', textAlign: 'center'}}>
            <div style={{fontSize: 24, color: 'var(--red)', marginBottom: 16}}>⚠️ Failed to load data</div>
            <div style={{color: 'var(--muted)', fontSize: 14, marginBottom: 20}}>{error}</div>
            <button className="btn" onClick={() => window.location.reload()}>
              Retry
            </button>
          </div>
        ) : (
          <>
        <div className="topbar">
          {route.view === 'dashboard' && <>
            <h1>All records</h1>
            <span className="crumb">Quality layer for SportsTool + CultureTool social handles</span>
          </>}
          {route.view === 'detail' && currentPerson && <>
            <span className="crumb" style={{cursor:'pointer'}} onClick={backToDashboard}>All records</span>
            <span className="crumb">/</span>
            <h1>{currentPerson.name}</h1>
          </>}
          {route.view === 'qc' && <h1>QC queue</h1>}
          {route.view === 'guide' && <>
            <h1>Guide</h1>
            <span className="crumb">How to use the tool well — and keep data quality high</span>
          </>}
          {route.view === 'activity' && <>
            <h1>Activity log</h1>
            <span className="crumb">Who did what</span>
          </>}
          {route.view === 'source' && <>
            <h1>Source quality</h1>
            <span className="crumb">Scorecard for SportsTool + CultureTool</span>
          </>}
          {route.view === 'report' && <>
            <h1>Dashboards</h1>
            <span className="crumb">Workflow → how much left to go · Quality → what we achieved</span>
          </>}
        </div>

        {route.view === 'dashboard' && (
          <Dashboard
            people={people}
            statsPeople={peopleForCounts.length ? peopleForCounts : people}
            filters={filters}
            setFilters={setFilters}
            onOpen={tryOpen}
            onExport={() => setShowExport(true)}
            locks={locks}
            loading={loading}
            pagination={{ page: peoplePage, pageSize: PEOPLE_PAGE_SIZE, total: peopleTotal }}
            onPageChange={setPeoplePage}
          />
        )}

        {route.view === 'detail' && currentPerson && (
          <PersonDetail
            person={currentPerson}
            queue={queue}
            onSelect={tryOpen}
            onUpdate={updateHandle}
            onUpdateProfile={updateProfile}
            onClose={backToDashboard}
            onNextPerson={goNext}
            onPrevPerson={goPrev}
            onToast={onToast}
            onSave={savePerson}
            locks={locks}
            currentUser={currentUser}
          />
        )}

        {route.view === 'qc' && <QcInbox people={people} onOpen={tryOpen} currentUser={currentUser} onUpdate={updateHandle} onUpdateProfile={updateProfile} locks={locks}/>}
        {route.view === 'report' && <ReportView people={people}/>}
        {route.view === 'activity' && <ActivityLogView teamActivity={teamActivity} teamStats={teamStats} fetchLogs={fetchLogs} onOpen={tryOpen}/>}
        {route.view === 'source' && <SourceQualityView people={people}/>}
        {route.view === 'guide' && <GuideView onOpen={tryOpen}/>}
          </>
        )}
      </div>
      </>
    )}

      {showExport && <ExportModal people={people} filters={filters} teamStats={teamStats} fetchLogs={fetchLogs} onClose={() => setShowExport(false)} onToast={onToast}/>}
      {tweaksOpen && <TweaksPanel tweaks={tweaks} setTweaks={setTweaks} onClose={() => setTweaksOpen(false)}/>}
      {toast && <div className="toast"><Icon name="check" size={13}/> {toast}</div>}
      {collide && (
        <div className="modal-bg" onClick={dismissCollide}>
          <div className="modal collide" onClick={(e) => e.stopPropagation()}>
            <div className="collide-head">
              <div className="avatar lg">{collide.lock.initials}</div>
              <div>
                <div className="collide-title">{collide.lock.name} recently opened this record</div>
                <div className="collide-sub">
                  <span className={`presence ${collide.lock.status}`} style={{position:'static', display:'inline-block', marginRight: 6}}/>
                  {collide.lock.role} · {collide.lock.activity === 'qc' ? 'QC' : 'reviewing'} <b>{collide.person.name}</b> · {collide.lock.since}
                </div>
              </div>
            </div>
            <p className="collide-body">
              Someone else opened this person in the last 5 minutes. To avoid parallel edits, we'd suggest skipping ahead. You can still open it if you need to.
            </p>
            <div className="collide-actions">
              <button className="btn ghost" onClick={dismissCollide}>Cancel</button>
              <button className="btn" onClick={proceedCollide}>Open anyway</button>
              <button className="btn primary" onClick={skipCollide}>
                Next free in queue <Icon name="chevR" size={13}/>
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App/>);
