Source: js/politician-dashboard.js

/**
 * @module IndividualIntelligence/PoliticianProfiling
 * @category Intelligence Analysis - Individual Politician Risk Assessment & Career Analytics
 * 
 * @description
 * **Individual Politician Career Analytics & Risk Intelligence Dashboard**
 * 
 * Advanced intelligence profiling platform providing **micro-level politician assessment**
 * across 349 Swedish members of parliament. Implements comprehensive risk scoring, 
 * influence hierarchy measurement, behavioral pattern analysis, and career trajectory 
 * forecasting using Chart.js and D3.js visualization. Monitors individual politician 
 * performance, behavioral anomalies, and career risk factors.
 * 
 * ## Intelligence Methodology
 * 
 * This module implements **individual-level political intelligence profiling**:
 * - **Target Population**: 349 Swedish parliamentarians (Riksdagen members)
 * - **Analysis Dimensions**: Risk, influence, behavioral patterns, career trajectory
 * - **Temporal Coverage**: Full parliamentary career from first election to present
 * - **Granularity**: Individual-level assessment with peer comparison context
 * 
 * ## Individual Politician Intelligence Framework
 * 
 * **Five-Dimensional Analysis Taxonomy**:
 * 
 * 1. **Risk Assessment** (Individual Threat Profile)
 *    - Ethics violations and conduct concerns
 *    - Electoral vulnerability and reelection risk
 *    - Political isolation and coalition weakness
 *    - Career stability and burnout indicators
 *    - Personal scandal and reputation exposure
 * 
 * 2. **Influence Measurement** (Individual Power Assessment)
 *    - Committee assignments and leadership roles
 *    - Speaking frequency and discourse leadership
 *    - Coalition-building capability and ally networks
 *    - Media prominence and public visibility
 *    - Decision-making authority in party structures
 * 
 * 3. **Behavioral Pattern Analysis** (Anomaly Detection)
 *    - Voting deviation from party discipline
 *    - Attendance and participation consistency
 *    - Speech content and rhetoric evolution
 *    - Committee engagement and activity levels
 *    - Coalition alliance volatility and shifts
 * 
 * 4. **Career Trajectory** (Professional Development)
 *    - Years of service and experience levels
 *    - Role progression (backbencher → committee → leadership)
 *    - Electoral performance trends
 *    - Party assignments and responsibilities
 *    - Generational cohort and peer advancement
 * 
 * 5. **Influence Bucket Classification** (Politician Tiers)
 *    - Leadership tier (party leaders, cabinet ministers)
 *    - Influential tier (committee chairs, opinion leaders)
 *    - Standard tier (regular parliamentarians)
 *    - New/junior tier (first-term or new assignments)
 * 
 * ## Data Sources (CIA Platform)
 * 
 * **Primary Intelligence Feeds**:
 * - `view_politician_risk_summary_sample.csv`
 *   * Fields: politician_id, name, party, risk_score (0-10), risk_level, risk_categories
 *   * Scope: Risk assessment for 349 individual MPs
 *   * Use: Risk profiling, threat identification, risk-based sorting
 * 
 * - `view_riksdagen_politician_influence_metrics_sample.csv`
 *   * Fields: politician_id, name, influence_score (0-100), leadership_roles, speech_frequency
 *   * Scope: Individual influence measurement with component breakdown
 *   * Use: Influence hierarchy visualization, power assessment
 * 
 * - `view_politician_behavioral_trends_sample.csv`
 *   * Fields: politician_id, year, voting_deviation_pct, attendance_rate, speech_sentiment
 *   * Scope: Annual behavioral metrics for anomaly detection
 *   * Use: Behavioral pattern recognition, consistency assessment
 * 
 * - `distribution_experience_levels.csv`
 *   * Fields: politician_id, years_service, parliament_term_count, experience_level, avg_roles
 *   * Scope: Career experience and tenure statistics
 *   * Use: Experience profiling, junior/senior categorization
 * 
 * - `distribution_influence_buckets.csv`
 *   * Fields: politician_id, influence_bucket (leadership/influential/standard/junior), bucket_rank
 *   * Scope: Categorization of 349 MPs into influence tiers
 *   * Use: Tier-based analysis, leadership pipeline tracking
 * 
 * - `distribution_assignment_roles.csv`
 *   * Fields: politician_id, role_type, role_count, committee_assignments, leadership_count
 *   * Scope: Individual role assignments and responsibilities
 *   * Use: Role trajectory tracking, responsibility assessment
 * 
 * ## OSINT Collection Strategy
 * 
 * **Multi-Layer Individual Intelligence**:
 * 1. **Parliamentary Records**: Voting records, speeches, committee participation
 * 2. **Media Monitoring**: Coverage volume, sentiment, scandal tracking
 * 3. **Social Media**: Engagement metrics, online presence, supporter networks
 * 4. **Personal Background**: Declared conflicts, financial interests, organizational affiliations
 * 5. **Electoral History**: Campaign performance, vote trends, constituency dynamics
 * 6. **Network Analysis**: Coalition patterns, ally/rival relationships, influence circles
 * 7. **Behavioral Metrics**: Speech analysis, consistency assessment, sentiment tracking
 * 
 * ## Visualization Intelligence
 * 
 * **Chart.js Risk Summary** (Primary):
 * - **Risk Distribution Chart**: Population-wide risk distribution
 *   * Histogram showing risk score distribution across 349 MPs
 *   * Color-coded risk levels (green/yellow/orange/red)
 *   * Shows critical/high-risk outliers
 * 
 * **Chart.js Influence Metrics** (Power Assessment):
 * - **Influence Ranking Chart**: Top 50 most influential politicians
 *   * Horizontal bar chart ranked by influence score
 *   * Color segments for influence dimensions
 *   * Identifies power concentration vs. distributed influence
 * 
 * **Chart.js Behavioral Trends** (Anomaly Detection):
 * - **Behavioral Pattern Timeline**: Individual politician behavior over time
 *   * Multi-line chart showing voting deviation and participation trends
 *   * Identifies consistency, volatility, or anomalies
 *   * Flags behavioral changes and pattern breaks
 * 
 * **Chart.js Experience Distribution** (Career):
 * - **Experience Levels**: Distribution across experience categories
 *   * Grouped bar chart showing tenure statistics
 *   * Identifies junior/senior ratios and generational balance
 *   * Shows parliamentary turnover rates
 * 
 * **Chart.js Role Distribution** (Responsibility):
 * - **Assignment Roles**: Distribution of parliamentary roles
 *   * Stacked bar showing committee, leadership, and regular roles
 *   * Highlights responsibility concentration
 *   * Shows role progression paths
 * 
 * ## Intelligence Analysis Frameworks Applied
 * 
 * @intelligence
 * - **Individual Risk Profiling**: Multi-factor individual threat assessment
 * - **Behavioral Deviation Analysis**: Voting discipline and participation consistency
 * - **Network Analysis**: Alliance patterns and influence circle mapping
 * - **Career Trajectory Modeling**: Role progression and seniority assessment
 * - **Anomaly Detection**: Unusual behavior and pattern deviation identification
 * 
 * @osint
 * - **Speech Analysis**: Rhetoric patterns and sentiment evolution tracking
 * - **Voting Pattern Recognition**: Party discipline and coalition deviation detection
 * - **Media Intelligence**: Coverage patterns and scandal accumulation
 * - **Network Intelligence**: Influence propagation and coalition networks
 * 
 * @risk
 * - **Individual Vulnerability**: Reelection risk and scandal exposure
 * - **Behavioral Anomalies**: Voting deviations and coalition instability
 * - **Career Discontinuity**: Sudden role changes or influence loss
 * - **Network Risk**: Contagion through ally networks and coalition vulnerability
 * 
 * ## GDPR Compliance
 * 
 * @gdpr Individual politician assessment uses only public information (Article 9(2)(e)):
 * - Parliamentary voting records (public official acts)
 * - Committee participation and role assignments (public record)
 * - Speeches and public statements (public domain)
 * - Media coverage (published information)
 * - Electoral results (public official data)
 * No private personal data, health information, or family details.
 * No processing of political beliefs beyond official voting records.
 * No predictive profiling for targeting or manipulation.
 * 
 * ## Security Architecture
 * 
 * @security Chart.js rendering with XSS-safe data binding
 * @security No individual-level personal data exposure
 * @security CSV data validation with type checking and range enforcement
 * @security Risk assessment algorithm assumptions disclosed transparently
 * @security No authentication required; all data is public record
 * @risk Medium - Individual risk scores may be used to identify "political risks"
 * 
 * ## Performance Characteristics
 * 
 * - **Data Volume**: 349 politicians × 5-10 data attributes = ~2,000 data points
 * - **Risk Assessment**: 349 individual risk profiles with score distribution
 * - **Influence Metrics**: 349 individual influence measurements with component breakdown
 * - **Behavioral Trends**: 349 × 5-10 years = ~3,500+ behavioral data points
 * - **Memory**: <3MB for complete politician intelligence dataset
 * - **Rendering**: Chart.js with 5-6 separate visualizations
 * 
 * ## Data Transformation Pipeline
 * 
 * **Load Strategy**:
 * 1. Attempt local cache load (`cia-data/politician/`)
 * 2. Parse CSV files into politician-centric structure
 * 3. Fallback to remote GitHub repository if local unavailable
 * 4. Consolidate multiple sources by politician_id
 * 5. Cache results with 24-hour expiry
 * 6. Render visualizations with aggregated/transformed data
 * 
 * **Data Aggregation**:
 * - Risk: Single score from risk_summary source
 * - Influence: Normalize component scores and aggregate (0-100 scale)
 * - Behavioral: Time-series aggregation by politician per year
 * - Experience: Tenure calculation from election history
 * - Roles: Count and categorize assignments by type
 * 
 * @author Hack23 AB - Individual Intelligence Team
 * @license Apache-2.0
 * @version 1.0.0
 * @since 2024
 * 
 * @see {@link https://github.com/Hack23/cia|CIA Platform Data Source}
 * @see {@link https://www.riksdagen.se|Riksdag Official Site}
 * @see {@link ./THREAT_MODEL.md|Threat Model Documentation}
 * @see {@link ./SECURITY_ARCHITECTURE.md|Security Architecture}
 */

// Data source base paths
const LOCAL_DATA_BASE = 'cia-data';
const CIA_DATA_BASE_URL = 'https://raw.githubusercontent.com/Hack23/cia/master/service.data.impl/sample-data';

const DATA_SOURCES = {
  riskSummary: [
    `${LOCAL_DATA_BASE}/politician/view_politician_risk_summary_sample.csv`,
    `${CIA_DATA_BASE_URL}/politician/view_politician_risk_summary_sample.csv`
  ],
  influenceMetrics: [
    `${LOCAL_DATA_BASE}/politician/view_riksdagen_politician_influence_metrics_sample.csv`,
    `${CIA_DATA_BASE_URL}/politician/view_riksdagen_politician_influence_metrics_sample.csv`
  ],
  behavioralTrends: [
    `${LOCAL_DATA_BASE}/politician/view_politician_behavioral_trends_sample.csv`,
    `${CIA_DATA_BASE_URL}/politician/view_politician_behavioral_trends_sample.csv`
  ],
  experienceLevels: [
    `${LOCAL_DATA_BASE}/politician/distribution_experience_levels.csv`,
    `${CIA_DATA_BASE_URL}/politician/distribution_experience_levels.csv`
  ],
  influenceBuckets: [
    `${LOCAL_DATA_BASE}/politician/distribution_influence_buckets.csv`,
    `${CIA_DATA_BASE_URL}/politician/distribution_influence_buckets.csv`
  ],
  assignmentRoles: [
    `${LOCAL_DATA_BASE}/politician/distribution_assignment_roles.csv`,
    `${CIA_DATA_BASE_URL}/politician/distribution_assignment_roles.csv`
  ]
};

// Data cache
const dataCache = {
  riskSummary: null,
  influenceMetrics: null,
  behavioralTrends: null,
  experienceLevels: null,
  influenceBuckets: null,
  assignmentRoles: null
};

/**
 * Fetch CSV data with local-first, remote-fallback strategy
 * @param {string[]} urls - Array of [localUrl, remoteUrl]
 * @returns {Promise<Array>} Parsed CSV data
 */
async function fetchCIAData(urls) {
  const urlList = Array.isArray(urls) ? urls : [urls];
  let lastError = null;

  for (const url of urlList) {
    try {
      const response = await fetch(url);
      if (!response.ok) {
        throw new Error(`Failed to fetch ${url}: ${response.statusText}`);
      }
      const text = await response.text();
      const data = parseCSV(text);
      if (data.length > 0) return data;
    } catch (error) {
      lastError = error;
      console.warn(`Fetch failed for ${url}, trying next source...`);
    }
  }

  console.error('All data sources failed:', lastError);
  return [];
}

/**
 * Parse CSV text to array of objects
 * @param {string} csvText - CSV text content
 * @returns {Array<Object>} Parsed data
 */
function parseCSV(csvText) {
  const lines = csvText.trim().split('\n');
  if (lines.length < 2) return [];
  
  const rawHeaders = parseCSVLine(lines[0]);
  const headers = rawHeaders.map(h =>
    h.trim().replace(/^\uFEFF?"/, '').replace(/"$/, '')
  );
  const data = [];
  
  for (let i = 1; i < lines.length; i++) {
    const values = parseCSVLine(lines[i]);
    if (values.length !== headers.length) continue;
    
    const row = {};
    headers.forEach((header, index) => {
      row[header] = values[index];
    });
    data.push(row);
  }
  
  return data;
}

/**
 * Parse a single CSV line handling quoted fields
 * @param {string} line - CSV line
 * @returns {Array<string>} Parsed values
 */
function parseCSVLine(line) {
  const values = [];
  let current = '';
  let inQuotes = false;
  
  for (let i = 0; i < line.length; i++) {
    const char = line[i];
    const nextChar = line[i + 1];
    
    if (char === '"') {
      if (inQuotes && nextChar === '"') {
        current += '"';
        i++;
      } else {
        inQuotes = !inQuotes;
      }
    } else if (char === ',' && !inQuotes) {
      values.push(current.trim());
      current = '';
    } else {
      current += char;
    }
  }
  values.push(current.trim());
  
  return values;
}

/**
 * Render Top 10 list
 * @param {string} containerId - Container element ID
 * @param {Array} data - Top 10 data
 * @param {string} scoreLabel - Label for score column
 */
function renderTop10List(containerId, data, scoreLabel = 'Score') {
  const container = document.getElementById(containerId);
  if (!container) return;
  
  if (!data || data.length === 0) {
    container.textContent = '';
    const errorElement = document.createElement('div');
    errorElement.className = 'error-message';
    errorElement.textContent = 'No data available';
    container.appendChild(errorElement);
    return;
  }
  
  const ul = document.createElement('ul');
  ul.className = 'top10-list';
  ul.setAttribute('role', 'list');
  
  data.slice(0, 10).forEach((item, index) => {
    const li = document.createElement('li');
    li.setAttribute('role', 'listitem');
    
    const rank = document.createElement('span');
    rank.className = 'rank';
    rank.textContent = `${index + 1}`;
    rank.setAttribute('aria-label', `Rank ${index + 1}`);
    
    const name = document.createElement('span');
    name.className = 'name';
    name.textContent = item.name || item.politician || 'Unknown';
    
    const party = document.createElement('span');
    party.className = 'party';
    party.textContent = item.party || '';
    
    const score = document.createElement('span');
    score.className = 'score';
    score.textContent = item.score || item.value || '0';
    score.setAttribute('aria-label', `${scoreLabel}: ${item.score || item.value || '0'}`);
    
    li.appendChild(rank);
    li.appendChild(name);
    if (item.party) li.appendChild(party);
    li.appendChild(score);
    
    ul.appendChild(li);
  });
  
  container.innerHTML = '';
  container.appendChild(ul);
}

/**
 * Create career trajectory line chart from behavioral trends data
 * Shows attendance, effectiveness, and discipline trends over time
 * @param {Array} data - Behavioral trends data from CIA CSV
 */
function createCareerTrajectoryChart(data) {
  const canvas = document.getElementById('career-trajectory-chart');
  if (!canvas) return;

  const ctx = canvas.getContext('2d');

  let chartData;
  if (data && data.length > 0) {
    // Group data by time_bucket and compute averages
    const byPeriod = {};
    data.forEach(row => {
      const period = (row.time_bucket || row.period_start || '').substring(0, 7); // YYYY-MM
      if (!period) return;
      if (!byPeriod[period]) {
        byPeriod[period] = { absence: [], winRate: [], rebelRate: [], count: 0 };
      }
      byPeriod[period].absence.push(parseFloat(row.avg_absence_rate) || 0);
      byPeriod[period].winRate.push(parseFloat(row.avg_win_rate) || 0);
      byPeriod[period].rebelRate.push(parseFloat(row.avg_rebel_rate) || 0);
      byPeriod[period].count++;
    });

    const periods = Object.keys(byPeriod).sort();
    const avg = arr => arr.length ? arr.reduce((a, b) => a + b, 0) / arr.length : 0;

    chartData = {
      labels: periods,
      datasets: [
        {
          label: 'Avg Win Rate (%)',
          data: periods.map(p => avg(byPeriod[p].winRate).toFixed(1)),
          borderColor: '#00d9ff',
          backgroundColor: 'rgba(0, 217, 255, 0.1)',
          tension: 0.4,
          fill: true
        },
        {
          label: 'Avg Absence Rate (%)',
          data: periods.map(p => avg(byPeriod[p].absence).toFixed(1)),
          borderColor: '#ff006e',
          backgroundColor: 'rgba(255, 0, 110, 0.1)',
          tension: 0.4,
          fill: true
        },
        {
          label: 'Avg Rebel Rate (%)',
          data: periods.map(p => avg(byPeriod[p].rebelRate).toFixed(1)),
          borderColor: '#ffbe0b',
          backgroundColor: 'rgba(255, 190, 11, 0.1)',
          tension: 0.4,
          fill: true
        }
      ]
    };
  } else {
    // Fallback with empty state
    chartData = {
      labels: ['No Data'],
      datasets: [{
        label: 'No behavioral data available',
        data: [0],
        borderColor: '#00d9ff',
        backgroundColor: 'rgba(0, 217, 255, 0.1)'
      }]
    };
  }

  new Chart(ctx, {
    type: 'line',
    data: chartData,
    options: {
      responsive: true,
      maintainAspectRatio: false,
      plugins: {
        legend: {
          display: true,
          labels: {
            color: '#e0e0e0',
            font: {
              family: "'Inter', sans-serif"
            }
          }
        },
        title: {
          display: false
        },
        tooltip: {
          backgroundColor: 'rgba(26, 30, 61, 0.95)',
          titleColor: '#00d9ff',
          bodyColor: '#e0e0e0',
          borderColor: '#00d9ff',
          borderWidth: 1
        }
      },
      scales: {
        x: {
          ticks: {
            color: '#e0e0e0',
            font: {
              family: "'Inter', sans-serif"
            }
          },
          grid: {
            color: 'rgba(0, 217, 255, 0.1)'
          }
        },
        y: {
          ticks: {
            color: '#e0e0e0',
            font: {
              family: "'Inter', sans-serif"
            }
          },
          grid: {
            color: 'rgba(0, 217, 255, 0.1)'
          }
        }
      }
    }
  });
}

/**
 * Create productivity vs influence scatter chart from real CIA data
 * Uses risk_summary (productivity proxy via documents/votes) and influence_metrics
 * @param {Array} riskData - Risk summary data with vote counts and documents
 * @param {Array} influenceData - Influence metrics with network connections
 */
function createProductivityInfluenceChart(riskData, influenceData) {
  const canvas = document.getElementById('productivity-influence-chart');
  if (!canvas) return;

  const ctx = canvas.getContext('2d');

  let chartData;
  if (riskData && riskData.length > 0 && influenceData && influenceData.length > 0) {
    // Build influence lookup by person_id
    const influenceLookup = {};
    influenceData.forEach(row => {
      influenceLookup[row.person_id] = {
        connections: parseInt(row.network_connections) || 0,
        classification: row.influence_classification || 'UNKNOWN'
      };
    });

    // Color by party
    const partyColors = {
      'S': 'rgba(237, 28, 36, 0.6)',
      'M': 'rgba(0, 106, 179, 0.6)',
      'SD': 'rgba(221, 221, 0, 0.6)',
      'C': 'rgba(0, 153, 68, 0.6)',
      'V': 'rgba(218, 41, 28, 0.6)',
      'KD': 'rgba(0, 95, 164, 0.6)',
      'L': 'rgba(0, 106, 180, 0.6)',
      'MP': 'rgba(83, 160, 39, 0.6)'
    };

    // Group data by party for datasets
    const byParty = {};
    riskData.forEach(row => {
      if (row.status !== 'Tjänstgörande riksdagsledamot') return;
      const party = row.party || 'Unknown';
      const influence = influenceLookup[row.person_id];
      const productivity = parseInt(row.annual_vote_count) || 0;
      const connections = influence ? influence.connections : 0;
      const riskScore = parseFloat(row.risk_score) || 10;

      if (!byParty[party]) byParty[party] = [];
      byParty[party].push({
        x: productivity,
        y: connections,
        r: Math.max(3, riskScore / 5),
        name: `${row.first_name} ${row.last_name}`,
        party: party,
        riskLevel: row.risk_level
      });
    });

    chartData = {
      datasets: Object.entries(byParty).map(([party, points]) => ({
        label: party,
        data: points,
        backgroundColor: partyColors[party] || 'rgba(128, 128, 128, 0.5)',
        borderColor: (partyColors[party] || 'rgba(128,128,128,0.5)').replace('0.6', '1'),
        borderWidth: 1
      }))
    };
  } else {
    // Fallback with empty state
    chartData = {
      datasets: [{
        label: 'No data available',
        data: [{ x: 0, y: 0, r: 5 }],
        backgroundColor: 'rgba(0, 217, 255, 0.5)',
        borderColor: '#00d9ff',
        borderWidth: 1
      }]
    };
  }

  new Chart(ctx, {
    type: 'bubble',
    data: chartData,
    options: {
      responsive: true,
      maintainAspectRatio: false,
      plugins: {
        legend: {
          display: true,
          labels: {
            color: '#e0e0e0',
            font: { family: "'Inter', sans-serif" }
          }
        },
        tooltip: {
          backgroundColor: 'rgba(26, 30, 61, 0.95)',
          titleColor: '#00d9ff',
          bodyColor: '#e0e0e0',
          borderColor: '#00d9ff',
          borderWidth: 1,
          callbacks: {
            label: function(context) {
              const raw = context.raw;
              return [
                raw.name ? `${raw.name} (${raw.party})` : '',
                `Votes: ${context.parsed.x}`,
                `Connections: ${context.parsed.y}`,
                raw.riskLevel ? `Risk: ${raw.riskLevel}` : ''
              ].filter(Boolean);
            }
          }
        }
      },
      scales: {
        x: {
          title: {
            display: true,
            text: 'Annual Vote Count',
            color: '#e0e0e0',
            font: { family: "'Inter', sans-serif" }
          },
          ticks: { color: '#e0e0e0', font: { family: "'Inter', sans-serif" } },
          grid: { color: 'rgba(0, 217, 255, 0.1)' }
        },
        y: {
          title: {
            display: true,
            text: 'Network Connections',
            color: '#e0e0e0',
            font: { family: "'Inter', sans-serif" }
          },
          ticks: { color: '#e0e0e0', font: { family: "'Inter', sans-serif" } },
          grid: { color: 'rgba(0, 217, 255, 0.1)' }
        }
      }
    }
  });
}

/**
 * Create experience distribution bar chart from real CIA data
 * @param {Array} data - Experience distribution data from distribution_experience_levels.csv
 */
function createExperienceDistributionChart(data) {
  const canvas = document.getElementById('experience-distribution-chart');
  if (!canvas) return;

  const ctx = canvas.getContext('2d');

  let labels, counts;
  if (data && data.length > 0) {
    // Format labels nicely from CSV values like ACTIVE_COMMITTEES → Active Committees
    const formatLabel = (s) => s.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase()).toLowerCase().replace(/^\w/, c => c.toUpperCase());
    labels = data.map(row => formatLabel(row.experience_level || ''));
    counts = data.map(row => parseInt(row.politician_count) || 0);
  } else {
    labels = ['No Data'];
    counts = [0];
  }

  const colors = [
    'rgba(0, 217, 255, 0.7)',
    'rgba(0, 217, 255, 0.6)',
    'rgba(0, 217, 255, 0.5)',
    'rgba(255, 190, 11, 0.6)',
    'rgba(255, 0, 110, 0.5)',
    'rgba(255, 0, 110, 0.6)',
    'rgba(255, 0, 110, 0.7)'
  ];
  const borderColors = [
    '#00d9ff', '#00d9ff', '#00d9ff',
    '#ffbe0b',
    '#ff006e', '#ff006e', '#ff006e'
  ];

  const chartData = {
    labels: labels,
    datasets: [{
      label: 'Number of Politicians',
      data: counts,
      backgroundColor: labels.map((_, i) => colors[i % colors.length]),
      borderColor: labels.map((_, i) => borderColors[i % borderColors.length]),
      borderWidth: 2
    }]
  };

  new Chart(ctx, {
    type: 'bar',
    data: chartData,
    options: {
      responsive: true,
      maintainAspectRatio: false,
      plugins: {
        legend: {
          display: false
        },
        tooltip: {
          backgroundColor: 'rgba(26, 30, 61, 0.95)',
          titleColor: '#00d9ff',
          bodyColor: '#e0e0e0',
          borderColor: '#00d9ff',
          borderWidth: 1
        }
      },
      scales: {
        x: {
          ticks: {
            color: '#e0e0e0',
            font: { family: "'Inter', sans-serif" },
            maxRotation: 45
          },
          grid: { color: 'rgba(0, 217, 255, 0.1)' }
        },
        y: {
          ticks: {
            color: '#e0e0e0',
            font: { family: "'Inter', sans-serif" }
          },
          grid: { color: 'rgba(0, 217, 255, 0.1)' }
        }
      }
    }
  });
}

/**
 * Load all dashboard data from real CIA CSV files
 * Uses local-first with remote-fallback for each data source
 */
async function loadDashboardData() {
  try {
    // Fetch all data sources in parallel
    const [riskData, influenceData, behavioralData, experienceData] = await Promise.all([
      fetchCIAData(DATA_SOURCES.riskSummary),
      fetchCIAData(DATA_SOURCES.influenceMetrics),
      fetchCIAData(DATA_SOURCES.behavioralTrends),
      fetchCIAData(DATA_SOURCES.experienceLevels)
    ]);

    // Cache data
    dataCache.riskSummary = riskData;
    dataCache.influenceMetrics = influenceData;
    dataCache.behavioralTrends = behavioralData;
    dataCache.experienceLevels = experienceData;

    // --- Top 10 Most Productive (by annual_vote_count) ---
    const activeRiskData = riskData.filter(r => r.status === 'Tjänstgörande riksdagsledamot');
    const top10Productive = [...activeRiskData]
      .sort((a, b) => (parseInt(b.annual_vote_count) || 0) - (parseInt(a.annual_vote_count) || 0))
      .slice(0, 10)
      .map(r => ({
        name: `${r.first_name} ${r.last_name}`,
        party: r.party,
        score: r.annual_vote_count || '0'
      }));

    // --- Top 10 Most Influential (by network_connections) ---
    const top10Influential = [...influenceData]
      .sort((a, b) => (parseInt(b.network_connections) || 0) - (parseInt(a.network_connections) || 0))
      .slice(0, 10)
      .map(r => ({
        name: `${r.first_name} ${r.last_name}`,
        party: r.party,
        score: r.network_connections || '0'
      }));

    // --- Top 10 Rising Stars (lowest risk among active - new effective MPs) ---
    const top10RisingStars = [...activeRiskData]
      .filter(r => parseInt(r.annual_vote_count) > 0)
      .sort((a, b) => {
        // Best combination: low risk score + high vote count
        const scoreA = (parseFloat(a.risk_score) || 50) - ((parseInt(a.annual_vote_count) || 0) / 100);
        const scoreB = (parseFloat(b.risk_score) || 50) - ((parseInt(b.annual_vote_count) || 0) / 100);
        return scoreA - scoreB;
      })
      .slice(0, 10)
      .map(r => ({
        name: `${r.first_name} ${r.last_name}`,
        party: r.party,
        score: r.risk_score || '0'
      }));

    // --- Top 10 Controversial (highest risk_score) ---
    const top10Controversial = [...activeRiskData]
      .sort((a, b) => (parseFloat(b.risk_score) || 0) - (parseFloat(a.risk_score) || 0))
      .slice(0, 10)
      .map(r => ({
        name: `${r.first_name} ${r.last_name}`,
        party: r.party,
        score: r.risk_score || '0'
      }));

    // Render Top 10 lists with real data
    renderTop10List('top10-productive-container', top10Productive, 'Votes');
    renderTop10List('top10-influential-container', top10Influential, 'Connections');
    renderTop10List('top10-rising-stars-container', top10RisingStars, 'Risk Score');
    renderTop10List('top10-controversial-container', top10Controversial, 'Risk Score');

    // Create charts with real data
    createCareerTrajectoryChart(behavioralData);
    createProductivityInfluenceChart(riskData, influenceData);
    createExperienceDistributionChart(experienceData);

  } catch (error) {
    console.error('Error loading dashboard data:', error);
    showError('Failed to load dashboard data. Please try again later.');
  }
}

/**
 * Show error message
 * @param {string} message - Error message
 */
function showError(message) {
  const containers = [
    'top10-productive-container',
    'top10-influential-container',
    'top10-rising-stars-container',
    'top10-controversial-container'
  ];
  
  containers.forEach(id => {
    const container = document.getElementById(id);
    if (container) {
      // Clear existing content safely
      container.textContent = '';

      // Create error message element with safe text insertion
      const errorElement = document.createElement('div');
      errorElement.className = 'error-message';
      errorElement.textContent = message;

      container.appendChild(errorElement);
    }
  });
}

// Initialize dashboard when DOM is ready
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', loadDashboardData);
} else {
  loadDashboardData();
}