Code viewer for World: Sentiment Analysis
// Quamdeen: Initializes the Sentiment Analysis Dashboard and sets up configurations
function sentimentDashboard() {
  // =======================
  // ==== API CONFIGURATIONS
  // =======================

  const apiConfigs = {
    MeaningCloud: {
      key: '', // Will be set via input
      url: 'https://api.meaningcloud.com/sentiment-2.1'
    },
    Twinword: {
      key: '', // Will be set via input
      url: 'https://twinword-sentiment-analysis.p.rapidapi.com/analyze/'
    },
    SentimentAPI: {
      key: '', // Will be set via input
      url: 'https://sentiment-api3.p.rapidapi.com/sentiment_analysis' // Fixed URL
    }
  };

  // Mapping API names to checkbox IDs
  const apiIdMapping = {
    MeaningCloud: 'meaningcloud-checkbox',
    Twinword: 'twinword-checkbox',
    SentimentAPI: 'sentimentapi-checkbox'
  };

  // Variables to store API keys
  let MeaningCloudAPIKey = '';
  let TwinwordAPIKey = '';
  let SentimentAPIKey = '';

  // =======================
  // ==== LOAD EXTERNAL SCRIPTS
  // =======================

  // Patrick: Dynamically loads external JavaScript scripts
  function loadScript(url, callback) {
    const script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = url;
    script.onload = callback;
    script.onerror = function () {
      console.error(`Failed to load script ${url}`);
      displayError(`Failed to load necessary script: ${url}`);
    };
    document.head.appendChild(script);
  }

  // Load Chart.js and then create the UI
  loadScript('https://cdn.jsdelivr.net/npm/chart.js', createUI);

  // =======================
  // ==== UI CREATION FUNCTION
  // =======================

  // Quamdeen: Creates the user interface for the dashboard
  function createUI() {
    console.log('Creating UI...');

    // Create container
    const container = document.createElement('div');
    container.id = 'sentiment-dashboard';
    container.style.maxWidth = '900px';
    container.style.margin = '40px auto';
    container.style.background = '#fff';
    container.style.padding = '30px';
    container.style.borderRadius = '8px';
    container.style.boxShadow = '0 0 15px rgba(0,0,0,0.2)';
    container.style.fontFamily = 'Arial, sans-serif';

    // Create title
    const title = document.createElement('h1');
    title.innerText = 'Enhanced Sentiment Analysis Dashboard';
    title.style.textAlign = 'center';
    title.style.color = '#2c3e50';
    container.appendChild(title);

    // Create input section
    const inputSection = document.createElement('div');
    inputSection.style.marginTop = '20px';

    // Textarea for input
    const textarea = document.createElement('textarea');
    textarea.id = 'text-input';
    textarea.placeholder = 'Enter text for sentiment analysis...';
    textarea.style.width = '100%';
    textarea.style.height = '150px';
    textarea.style.padding = '12px';
    textarea.style.marginBottom = '15px';
    textarea.style.border = '1px solid #bdc3c7';
    textarea.style.borderRadius = '4px';
    textarea.style.fontSize = '16px';
    textarea.style.resize = 'vertical';
    textarea.setAttribute('aria-label', 'Text input for sentiment analysis');
    inputSection.appendChild(textarea);

    // Language selector
    const langLabel = document.createElement('label');
    langLabel.innerText = 'Select Language: ';
    langLabel.setAttribute('for', 'language-select');
    langLabel.style.marginRight = '10px';
    inputSection.appendChild(langLabel);

    const langSelect = document.createElement('select');
    langSelect.id = 'language-select';
    langSelect.style.padding = '8px';
    langSelect.style.border = '1px solid #bdc3c7';
    langSelect.style.borderRadius = '4px';
    ['en', 'es', 'fr', 'de'].forEach((lang) => {
      const option = document.createElement('option');
      option.value = lang;
      option.innerText = lang.toUpperCase();
      langSelect.appendChild(option);
    });
    inputSection.appendChild(langSelect);

    // API Keys Section
    const apiKeysSection = document.createElement('div');
    apiKeysSection.style.marginTop = '20px';
    apiKeysSection.style.padding = '15px';
    apiKeysSection.style.border = '1px solid #bdc3c7';
    apiKeysSection.style.borderRadius = '6px';
    apiKeysSection.style.backgroundColor = '#f9f9f9';

    const apiKeysTitle = document.createElement('h4');
    apiKeysTitle.innerText = 'Enter Your API Keys';
    apiKeysTitle.style.color = '#34495e';
    apiKeysSection.appendChild(apiKeysTitle);

    // Patrick: Creates API key input fields
    function createApiKeyInput(apiName) {
      const apiKeyLabel = document.createElement('label');
      apiKeyLabel.innerText = `${apiName} API Key`;
      apiKeyLabel.setAttribute('for', `${apiName.toLowerCase()}ApiKey`);
      apiKeyLabel.style.display = 'block';
      apiKeyLabel.style.marginTop = '10px';

      const apiKeyInput = document.createElement('input');
      apiKeyInput.type = 'password';
      apiKeyInput.id = `${apiName.toLowerCase()}ApiKey`;
      apiKeyInput.className = 'form-control';
      apiKeyInput.placeholder = `Enter your ${apiName} API key`;
      apiKeyInput.style.width = '100%';
      apiKeyInput.style.padding = '8px';
      apiKeyInput.style.border = '1px solid #bdc3c7';
      apiKeyInput.style.borderRadius = '4px';
      apiKeyInput.style.marginTop = '5px';

      apiKeysSection.appendChild(apiKeyLabel);
      apiKeysSection.appendChild(apiKeyInput);
    }

    // Create API key inputs for each API
    Object.keys(apiConfigs).forEach((apiName) => {
      createApiKeyInput(apiName);
    });

    // Save API Keys button
    const saveApiKeysButton = document.createElement('button');
    saveApiKeysButton.innerText = 'Save API Keys';
    saveApiKeysButton.className = 'btn btn-primary';
    saveApiKeysButton.style.marginTop = '15px';
    saveApiKeysButton.onclick = saveApiKeys;
    apiKeysSection.appendChild(saveApiKeysButton);

    const apiMessage = document.createElement('p');
    apiMessage.id = 'apiMessage';
    apiMessage.style.marginTop = '10px';
    apiKeysSection.appendChild(apiMessage);

    inputSection.appendChild(apiKeysSection);

    // API selection checkboxes
    const apiSelection = document.createElement('div');
    apiSelection.style.marginTop = '20px';
    apiSelection.style.display = 'flex';
    apiSelection.style.flexWrap = 'wrap';
    apiSelection.style.gap = '15px';

    Object.keys(apiConfigs).forEach((apiName) => {
      const label = document.createElement('label');
      label.style.display = 'flex';
      label.style.alignItems = 'center';
      label.style.gap = '5px';

      const checkbox = document.createElement('input');
      checkbox.type = 'checkbox';
      checkbox.id = apiIdMapping[apiName];
      checkbox.checked = true;

      label.appendChild(checkbox);
      label.appendChild(document.createTextNode(apiName));

      apiSelection.appendChild(label);
      console.log(`Checkbox created for ${apiName} with ID ${checkbox.id}`);
    });

    inputSection.appendChild(apiSelection);

    // This is for the Analyze sentiment button
    const button = document.createElement('button');
    button.innerText = 'Analyze Sentiment';
    button.style.padding = '12px 25px';
    button.style.backgroundColor = '#2980b9';
    button.style.border = 'none';
    button.style.color = '#fff';
    button.style.borderRadius = '4px';
    button.style.cursor = 'pointer';
    button.style.fontSize = '16px';
    button.style.marginTop = '20px';
    button.style.display = 'block';
    button.style.marginLeft = 'auto';
    button.style.marginRight = 'auto';
    button.onclick = analyzeSentiment;

    button.onmouseover = function () {
      button.style.backgroundColor = '#1f618d';
    };
    button.onmouseout = function () {
      button.style.backgroundColor = '#2980b9';
    };
    inputSection.appendChild(button);

    // Append input section to container
    container.appendChild(inputSection);

    // Results section
    const results = document.createElement('div');
    results.id = 'results';
    results.style.display = 'flex';
    results.style.flexWrap = 'wrap';
    results.style.marginTop = '30px';
    results.style.gap = '20px';

    // Patrick: Creates result display boxes for each API
    function createResultBox(id, titleText) {
      const resultBox = document.createElement('div');
      resultBox.className = 'result-box';
      resultBox.style.flex = '1 1 220px';
      resultBox.style.background = '#ecf0f1';
      resultBox.style.padding = '15px';
      resultBox.style.borderRadius = '6px';
      resultBox.style.boxShadow = '0 2px 5px rgba(0,0,0,0.1)';
      resultBox.style.position = 'relative';

      const resultTitle = document.createElement('h2');
      resultTitle.innerText = titleText;
      resultTitle.style.marginTop = '0';
      resultTitle.style.fontSize = '18px';
      resultTitle.style.color = '#34495e';
      resultBox.appendChild(resultTitle);

      const sentimentDiv = document.createElement('div');
      sentimentDiv.id = id;
      sentimentDiv.className = 'sentiment';
      sentimentDiv.innerText = 'No data';
      sentimentDiv.style.fontSize = '24px';
      sentimentDiv.style.fontWeight = 'bold';
      sentimentDiv.style.textAlign = 'center';
      sentimentDiv.style.padding = '10px';
      sentimentDiv.style.borderRadius = '4px';
      sentimentDiv.style.color = '#fff';
      sentimentDiv.style.marginBottom = '10px';
      resultBox.appendChild(sentimentDiv);

      // Details button
      const detailsButton = document.createElement('button');
      detailsButton.innerText = 'View Details';
      detailsButton.style.padding = '6px 12px';
      detailsButton.style.backgroundColor = '#8e44ad';
      detailsButton.style.border = 'none';
      detailsButton.style.color = '#fff';
      detailsButton.style.borderRadius = '4px';
      detailsButton.style.cursor = 'pointer';
      detailsButton.style.fontSize = '14px';
      detailsButton.onclick = () => showDetails(titleText, sentimentDiv.dataset.raw);
      resultBox.appendChild(detailsButton);

      return resultBox;
    }

    // Create Result Boxes for APIs
    Object.keys(apiConfigs).forEach((apiName) => {
      const apiResultBox = createResultBox(`${apiName.toLowerCase()}-sentiment`, apiName);
      results.appendChild(apiResultBox);
    });

    // Final Aggregated Sentiment
    const finalSentimentDiv = document.createElement('div');
    finalSentimentDiv.id = 'final-sentiment';
    finalSentimentDiv.style.width = '100%';
    finalSentimentDiv.style.padding = '15px';
    finalSentimentDiv.style.borderRadius = '6px';
    finalSentimentDiv.style.background = '#bdc3c7'; // Grey during loading
    finalSentimentDiv.style.textAlign = 'center';
    finalSentimentDiv.style.fontSize = '20px';
    finalSentimentDiv.style.fontWeight = 'bold';
    finalSentimentDiv.innerText = 'Aggregated Sentiment: N/A';
    results.appendChild(finalSentimentDiv);

    // This is the Bar Chart for visual comparison
    const chartContainer = document.createElement('div');
    chartContainer.style.width = '100%';
    chartContainer.style.marginTop = '30px';
    chartContainer.style.textAlign = 'center';

    const chartTitle = document.createElement('h2');
    chartTitle.innerText = 'Sentiment Scores Comparison';
    chartTitle.style.color = '#2c3e50';
    chartContainer.appendChild(chartTitle);

    const chartCanvas = document.createElement('canvas');
    chartCanvas.id = 'sentimentChart';
    chartCanvas.width = 800;
    chartCanvas.height = 400;
    chartContainer.appendChild(chartCanvas);

    container.appendChild(results);
    container.appendChild(chartContainer);

    // Modal for detailed API responses
    const modal = document.createElement('div');
    modal.id = 'apiModal';
    modal.className = 'modal';
    modal.style.display = 'none'; // Hidden by default
    modal.style.position = 'fixed';
    modal.style.zIndex = '1000';
    modal.style.left = '0';
    modal.style.top = '0';
    modal.style.width = '100%';
    modal.style.height = '100%';
    modal.style.overflow = 'auto';
    modal.style.backgroundColor = 'rgba(0,0,0,0.4)';

    const modalContent = document.createElement('div');
    modalContent.className = 'modal-content';
    modalContent.style.backgroundColor = '#fefefe';
    modalContent.style.margin = '10% auto';
    modalContent.style.padding = '20px';
    modalContent.style.border = '1px solid #888';
    modalContent.style.width = '80%';
    modalContent.style.borderRadius = '8px';

    const closeSpan = document.createElement('span');
    closeSpan.className = 'close';
    closeSpan.innerHTML = '×';
    closeSpan.style.color = '#aaa';
    closeSpan.style.float = 'right';
    closeSpan.style.fontSize = '28px';
    closeSpan.style.fontWeight = 'bold';
    closeSpan.style.cursor = 'pointer';
    closeSpan.onclick = function () {
      modal.style.display = 'none';
    };
    modalContent.appendChild(closeSpan);

    const modalHeader = document.createElement('h2');
    modalHeader.id = 'modal-title';
    modalHeader.innerText = 'API Details';
    modalContent.appendChild(modalHeader);

    const modalBody = document.createElement('pre');
    modalBody.id = 'modal-body';
    modalBody.style.whiteSpace = 'pre-wrap';
    modalBody.style.wordWrap = 'break-word';
    modalContent.appendChild(modalBody);

    modal.appendChild(modalContent);
    container.appendChild(modal);

    // Loading Indicator
    const loadingIndicator = document.createElement('div');
    loadingIndicator.id = 'loading-indicator';
    loadingIndicator.innerText = 'Analyzing sentiment...';
    loadingIndicator.style.display = 'none';
    loadingIndicator.style.textAlign = 'center';
    loadingIndicator.style.marginTop = '20px';
    loadingIndicator.style.fontSize = '18px';
    loadingIndicator.style.color = '#2980b9';
    container.appendChild(loadingIndicator);

    // Append container to body
    document.body.appendChild(container);
  }

  // =======================
  // ==== DISPLAY ERROR FUNCTION
  // =======================

  // Patrick: Displays error messages to the user
  function displayError(message) {
    const apiMessage = document.getElementById('apiMessage');
    if (apiMessage) {
      apiMessage.textContent = message;
      apiMessage.style.color = 'red';
    }
  }

  // =======================
  // ==== SUCCESS MESSAGE FUNCTION
  // =======================

  // Quamdeen: Displays success messages to the user
  function displaySuccess(message) {
    const apiMessage = document.getElementById('apiMessage');
    if (apiMessage) {
      apiMessage.textContent = message;
      apiMessage.style.color = 'green';
    }
  }

  // =======================
  // ==== SAVE API KEYS FUNCTION
  // =======================

  // Patrick: Saves the API keys entered by the user
  function saveApiKeys() {
    const meaningCloudKey = document.getElementById('meaningcloudApiKey').value.trim();
    const twinwordKey = document.getElementById('twinwordApiKey').value.trim();
    const sentimentAPIKey = document.getElementById('sentimentapiApiKey').value.trim();
    const apiMessage = document.getElementById('apiMessage');

    if (!meaningCloudKey && !twinwordKey && !sentimentAPIKey) {
      displayError('At least one API key is required!');
      return;
    }

    MeaningCloudAPIKey = meaningCloudKey;
    TwinwordAPIKey = twinwordKey;
    SentimentAPIKey = sentimentAPIKey;

    apiConfigs.MeaningCloud.key = meaningCloudKey;
    apiConfigs.Twinword.key = twinwordKey;
    apiConfigs.SentimentAPI.key = SentimentAPIKey;
    // apiConfigs.SentimentAPI.url = SentimentAPIURL; // Fixed URL remains unchanged

    displaySuccess('API keys saved successfully!');
  }

  // =======================
  // ==== SHOW DETAILS FUNCTION
  // =======================

  // Quamdeen: Displays detailed API response data in a modal
  function showDetails(apiName, rawData) {
    const modal = document.getElementById('apiModal');
    const modalTitle = document.getElementById('modal-title');
    const modalBody = document.getElementById('modal-body');

    modalTitle.innerText = `${apiName} - Raw Response`;
    modalBody.innerText = rawData ? rawData : 'No data available.';

    modal.style.display = 'block';
  }

  // =======================
  // ==== GET SENTIMENT LABEL FUNCTION
  // =======================

  // Patrick: Determines the sentiment label and corresponding CSS class based on API response
  function getSentimentLabel(sentiment, source) {
    let label = '';
    let className = '';

    if (source === 'MeaningCloud') {
      switch (sentiment) {
        case 'p+':
        case 'p':
          label = 'Positive';
          className = 'positive';
          break;
        case 'neu':
          label = 'Neutral';
          className = 'neutral';
          break;
        case 'n':
        case 'n+':
          label = 'Negative';
          className = 'negative';
          break;
        default:
          label = 'None';
          className = 'neutral';
      }
    } else if (source === 'Twinword') {
      switch (sentiment) {
        case 'positive':
          label = 'Positive';
          className = 'positive';
          break;
        case 'neutral':
          label = 'Neutral';
          className = 'neutral';
          break;
        case 'negative':
          label = 'Negative';
          className = 'negative';
          break;
        default:
          label = 'None';
          className = 'neutral';
      }
    } else if (source === 'SentimentAPI') {
      switch (sentiment) {
        case 'positive':
          label = 'Positive';
          className = 'positive';
          break;
        case 'neutral':
          label = 'Neutral';
          className = 'neutral';
          break;
        case 'negative':
          label = 'Negative';
          className = 'negative';
          break;
        default:
          label = 'None';
          className = 'neutral';
      }
    }

    return { label, className };
  }

  // =======================
  // ==== CAPITALIZE FUNCTION
  // =======================

  // Quamdeen: Capitalizes the first letter of a given string
  // Parameters:
  // - string (String): The input string to capitalize
  // Returns:
  // - (String): The input witht the first letter capitalized
  function capitalizeFirstLetter(string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
  }

  // =======================
  // ==== RESET RESULTS FUNCTION
  // =======================

  // Patrick: Resets previous sentiment analysis results before a new analysis
  function resetResults() {
    Object.keys(apiConfigs).forEach((apiName) => {
      const sentimentDiv = document.getElementById(`${apiName.toLowerCase()}-sentiment`);
      if (sentimentDiv) {
        sentimentDiv.innerText = 'Loading...';
        sentimentDiv.className = 'sentiment neutral'; // Reset classes
        sentimentDiv.style.backgroundColor = '#bdc3c7'; // Set to grey during loading
        sentimentDiv.dataset.raw = '';
      }
    });
    const finalSentimentDiv = document.getElementById('final-sentiment');
    if (finalSentimentDiv) {
      finalSentimentDiv.innerText = 'Aggregated Sentiment: N/A';
      finalSentimentDiv.style.backgroundColor = '#bdc3c7'; // Reset to grey
    }

    // Safely destroy existing chart if it exists
    if (window.sentimentChart && typeof window.sentimentChart.destroy === 'function') {
      window.sentimentChart.destroy();
      window.sentimentChart = null; // Reset to null after destruction
      console.log('Existing chart destroyed.');
    } else {
      console.warn('No existing Chart instance to destroy.');
    }

    // Clear any existing error or success messages
    const apiMessage = document.getElementById('apiMessage');
    if (apiMessage) {
      apiMessage.textContent = '';
    }
  }

  // =======================
  // ==== DISPLAY RESULTS FUNCTION
  // =======================

  // Quamdeen: Displays the sentiment analysis results from each API
  function displayResults(apiResults) {
    Object.keys(apiResults).forEach((apiName) => {
      const result = apiResults[apiName];
      const sentimentDiv = document.getElementById(`${apiName.toLowerCase()}-sentiment`);
      if (sentimentDiv) {
        sentimentDiv.innerText = result.label;

        // Reset className to include only 'sentiment' and current class
        sentimentDiv.className = `sentiment ${result.className}`;

        // Apply background color based on className
        sentimentDiv.style.backgroundColor =
          result.className === 'positive' ? '#27ae60' :       // Green for Positive
          result.className === 'negative' ? '#c0392b' :       // Red for Negative
          '#f39c12';                                         // Orange for Neutral

        sentimentDiv.dataset.raw = JSON.stringify(result.raw, null, 2);
      }
    });

    // Aggregate sentiments
    const finalSentiment = aggregateSentiments(apiResults);
    const finalSentimentDiv = document.getElementById('final-sentiment');
    if (finalSentimentDiv) {
      finalSentimentDiv.innerText = `Aggregated Sentiment: ${finalSentiment}`;

      // Change background color based on finalSentiment
      switch (finalSentiment) {
        case 'Positive':
          finalSentimentDiv.style.backgroundColor = '#27ae60'; // Green
          break;
        case 'Negative':
          finalSentimentDiv.style.backgroundColor = '#c0392b'; // Red
          break;
        case 'Neutral':
          finalSentimentDiv.style.backgroundColor = '#f39c12'; // Orange
          break;
        default:
          finalSentimentDiv.style.backgroundColor = '#bdc3c7'; // Grey (Default)
      }
    }

    // Update chart
    updateChart(apiResults);
  }

  // =======================
  // ==== AGGREGATE SENTIMENTS FUNCTION
  // =======================

  // Patrick: Aggregates individual sentiments to determine overall sentiment
  function aggregateSentiments(apiResults) {
    let sentimentCount = { Positive: 0, Neutral: 0, Negative: 0 };
    for (let api in apiResults) {
      const label = apiResults[api].label;
      if (sentimentCount[label] !== undefined) {
        sentimentCount[label]++;
      }
    }
    // Determine majority sentiment
    let finalSentiment = 'Neutral'; // Default
    if (sentimentCount.Positive > sentimentCount.Negative && sentimentCount.Positive > sentimentCount.Neutral) {
      finalSentiment = 'Positive';
    } else if (sentimentCount.Negative > sentimentCount.Positive && sentimentCount.Negative > sentimentCount.Neutral) {
      finalSentiment = 'Negative';
    }
    return finalSentiment;
  }

  // =======================
  // ==== UPDATE CHART FUNCTION
  // =======================

  // Quamdeen: Updates the Chart.js bar chart with the latest sentiment scores
  function updateChart(apiResults) {
    // Ensure Chart.js is loaded
    if (typeof Chart === 'undefined') {
      console.error('Chart.js is not loaded.');
      displayError('Chart.js failed to load. Sentiment scores will not be displayed as a chart.');
      return;
    }

    const labels = Object.keys(apiResults);
    const data = labels.map((api) => {
      const result = apiResults[api];
      if (result.score !== undefined) return result.score;
      if (result.confidence !== undefined) return result.confidence;
      return 0; // Default
    });

    const backgroundColors = labels.map((api) => {
      const sentiment = apiResults[api].label;
      if (sentiment === 'Positive') return 'rgba(39, 174, 96, 0.6)'; // Green
      if (sentiment === 'Negative') return 'rgba(192, 57, 43, 0.6)'; // Red
      return 'rgba(243, 156, 18, 0.6)'; // Orange for Neutral
    });

    const borderColors = labels.map((api) => {
      const sentiment = apiResults[api].label;
      if (sentiment === 'Positive') return 'rgba(39, 174, 96, 1)'; // Green
      if (sentiment === 'Negative') return 'rgba(192, 57, 43, 1)'; // Red
      return 'rgba(243, 156, 18, 1)'; // Orange Border for Neutral
    });

    const ctx = document.getElementById('sentimentChart').getContext('2d');

    // Safely destroy existing chart if it's a valid Chart.js instance
    if (window.sentimentChart && typeof window.sentimentChart.destroy === 'function') {
      window.sentimentChart.destroy();
      window.sentimentChart = null; // Reset to null after destruction
      console.log('Existing chart destroyed before creating a new one.');
    }

    // Create a new chart
    try {
      window.sentimentChart = new Chart(ctx, {
        type: 'bar',
        data: {
          labels: labels,
          datasets: [
            {
              label: 'Sentiment Score',
              data: data,
              backgroundColor: backgroundColors,
              borderColor: borderColors,
              borderWidth: 1
            }
          ]
        },
        options: {
          responsive: true,
          scales: {
            y: {
              beginAtZero: true
            }
          },
          plugins: {
            legend: {
              display: false
            },
            tooltip: {
              callbacks: {
                label: function (context) {
                  return `Score: ${context.parsed.y}`;
                }
              }
            }
          }
        }
      });
      console.log('Chart.js chart created successfully.');
    } catch (error) {
      console.error('Error creating Chart.js chart:', error);
      displayError('An error occurred while creating the sentiment chart.');
    }
  }
  
   // // Quamdeen: Function to update Chart.js chart with standardized sentiment scores. So I added this part just for visual representation, if you would like to see the results of the analysis when all the scores are standardised
// function updateChart(apiResults) {
//   // Ensure Chart.js is loaded
//   if (typeof Chart === 'undefined') {
//     console.error('Chart.js is not loaded.');
//     alert('Chart.js failed to load. Sentiment scores will not be displayed as a chart.');
//     return;
//   }

//   const labels = Object.keys(apiResults);
//   const data = labels.map(api => {
//     const result = apiResults[api];
//     let score;

//     // Normalize the scores based on API-specific logic
//     if (api === 'MeaningCloud' && result.confidence !== undefined) {
//       score = result.confidence; // this stays the same as we are trying to normalise the others to 100
//     } else if ((api === 'Twinword' || api === 'SentimentAPI') && result.confidence !== undefined) {
//       score = result.confidence * 100; // Convert Twinword/SentimentAPI (0-1) to 0-100
//     } else if (api === 'Google' && result.score !== undefined) {
//       score = result.score * 100; // Assuming Google score (0-1), convert to 0-100
//     } else {
//       score = 0; // Default to 0 if no score is available
//     }

//     return score;
//   });

//   const backgroundColors = labels.map(api => {
//     const sentiment = apiResults[api].label;
//     if (sentiment === 'Positive') return 'rgba(46, 204, 113, 0.6)'; // Green
//     if (sentiment === 'Negative') return 'rgba(231, 76, 60, 0.6)';   // Red
//     return 'rgba(255, 165, 0, 0.6)'; // Neutral Orange (Replaced Grey)
//   });

//   const borderColors = labels.map(api => {
//     const sentiment = apiResults[api].label;
//     if (sentiment === 'Positive') return 'rgba(46, 204, 113, 1)'; // Green
//     if (sentiment === 'Negative') return 'rgba(231, 76, 60, 1)';   // Red
//     return 'rgba(255, 165, 0, 1)'; // Neutral Orange Border (Replaced Grey)
//   });

//   const ctx = document.getElementById('sentimentChart').getContext('2d');

//   // Safely destroy existing chart if it's a valid Chart.js instance
//   if (window.sentimentChart && typeof window.sentimentChart.destroy === 'function') {
//     window.sentimentChart.destroy();
//     window.sentimentChart = null; // Reset to null after destruction
//     console.log('Existing chart destroyed before creating a new one.');
//   }

//   // Create a new Chart.js bar chart
//   try {
//     window.sentimentChart = new Chart(ctx, {
//       type: 'bar',
//       data: {
//         labels: labels,
//         datasets: [{
//           label: 'Sentiment Score (Normalized)',
//           data: data,
//           backgroundColor: backgroundColors,
//           borderColor: borderColors,
//           borderWidth: 1
//         }]
//       },
//       options: {
//         responsive: true,
//         scales: {
//           y: {
//             beginAtZero: true,
//             max: 100 // Scale the Y-axis to 100 for standardized scores
//           }
//         },
//         plugins: {
//           legend: {
//             display: false // Hide the legend for clarity
//           },
//           tooltip: {
//             callbacks: {
//               label: function(context) {
//                 return `Score: ${context.parsed.y}`;
//               }
//             }
//           }
//         }
//       }
//     });
//     console.log('Chart.js normalized chart created successfully.');
//   } catch (error) {
//     console.error('Error creating Chart.js normalized chart:', error);
//     alert('An error occurred while creating the sentiment chart.');
//   }
// }

  // =======================
  // ==== API CALL FUNCTIONS
  // =======================

  // Patrick: Calls the MeaningCloud API for sentiment analysis
  async function fetchMeaningCloud(text, lang) {
    const startTime = Date.now();
    try {
        // Sending a POST request to MeaningCloud API with necessary parameters
      const response = await fetch(apiConfigs.MeaningCloud.url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
        body: new URLSearchParams({
          key: apiConfigs.MeaningCloud.key,
          txt: text,
          lang: lang
        })
      });

      const responseTime = Date.now() - startTime;
      if (!response.ok) throw new Error('MeaningCloud API Error');

      const data = await response.json();
      const sentiment = data.score_tag; // Extracting the sentiment tag from response
      const confidence = parseFloat(data.confidence); // Extracting confidence score
      const result = getSentimentLabel(sentiment.toLowerCase(), 'MeaningCloud'); // Mapping to label and class
      result.raw = data; // Storing raw API response
      result.confidence = confidence; // Storing confidence score
      result.responseTime = responseTime; // Storing response time
      console.log('MeaningCloud Sentiment Analysis Result:', result);
      return result;
    } catch (error) {
      console.error('MeaningCloud Sentiment Analysis Error:', error);
      // Returning an error object to handle it gracefully in the UI
      return { label: 'Error', className: 'neutral', raw: error.message };
    }
  }

  // Quamdeen: Calls the Twinword API for sentiment analysis
  async function fetchTwinword(text, lang) {
    const startTime = Date.now();
    try {
        // Sending a POST request to Twinword API with the input text
      const response = await fetch(apiConfigs.Twinword.url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
          'X-RapidAPI-Key': apiConfigs.Twinword.key,
          'X-RapidAPI-Host': 'twinword-sentiment-analysis.p.rapidapi.com'
        },
        body: new URLSearchParams({ text })
      });

      const responseTime = Date.now() - startTime;
      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(`Twinword API Error: ${errorData.message || response.statusText}`);
      }

      const data = await response.json();
      const sentiment = data.type;
      const confidence = data.score;
      const result = getSentimentLabel(sentiment.toLowerCase(), 'Twinword'); // Ensure lowercase
      result.raw = data; // Storing raw API response
      result.confidence = confidence; // Storing confidence score
      result.responseTime = responseTime; // Storing response time
      console.log('Twinword Sentiment Analysis Result:', result);
      return result;
    } catch (error) {
      console.error('Twinword Sentiment Analysis Error:', error);
      // Returning an error object to handle it gracefully in the UI
      return { label: 'Error', className: 'neutral', raw: error.message };
    }
  }

  // Quamdeen: Calls the SentimentAPI for sentiment analysis
  async function fetchSentimentAPI(text, lang) {
    const startTime = Date.now();
    try {
        // Sending a POST request to SentimentAPI with the input text
      const response = await fetch(apiConfigs.SentimentAPI.url, {
        method: 'POST',
        headers: {
          'x-rapidapi-key': apiConfigs.SentimentAPI.key,
          'x-rapidapi-host': 'sentiment-api3.p.rapidapi.com',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          input_text: text
        })
      });

      const responseTime = Date.now() - startTime;
      if (!response.ok) {
        let errorMessage = `SentimentAPI Error: ${response.status} ${response.statusText}`;
        try {
          const errorData = await response.json();
          errorMessage = `SentimentAPI Error: ${errorData.message || response.statusText}`;
        } catch (e) {
          // If response is not JSON
        }
        throw new Error(errorMessage);
      }

      const data = await response.json();
      const sentiment = data.overall_sentiment ? data.overall_sentiment.toLowerCase() : 'none';
      // Use 'confidence_score' from the response or fallback to 'sentiment_score'
      const confidence = data.confidence_score !== undefined ? data.confidence_score : data.sentiment_score;
      const result = getSentimentLabel(sentiment, 'SentimentAPI');
      result.raw = data; // Storing raw API response
      result.confidence = confidence; // Storing response time
      result.responseTime = responseTime;
      console.log('SentimentAPI Sentiment Analysis Result:', result);
      return result;
    } catch (error) {
      console.error('SentimentAPI Sentiment Analysis Error:', error);
      // Returning an error object to handle it gracefully in the UI
      return { label: 'Error', className: 'neutral', raw: error.message };
    }
  }

  // =======================
  // ==== SENTIMENT ANALYSIS FUNCTION
  // =======================

  // Quamdeen: Orchestrates the sentiment analysis process using selected APIs
  async function analyzeSentiment() {
    const text = document.getElementById('text-input').value.trim();
    const selectedLang = document.getElementById('language-select').value;
    const apiMessage = document.getElementById('apiMessage');

    if (!text) {
      displayError('Please enter some text for analysis.');
      return;
    }

    console.log('Starting sentiment analysis...');

    // Reset previous results
    resetResults();

    // Show loading indicator
    const loadingIndicator = document.getElementById('loading-indicator');
    if (loadingIndicator) {
      loadingIndicator.style.display = 'block';
    }

    // Gather selected APIs using the correct IDs
    const selectedAPIs = [];
    if (document.getElementById(apiIdMapping.MeaningCloud).checked) selectedAPIs.push('MeaningCloud');
    if (document.getElementById(apiIdMapping.Twinword).checked) selectedAPIs.push('Twinword');
    if (document.getElementById(apiIdMapping.SentimentAPI).checked) selectedAPIs.push('SentimentAPI');

    console.log('Selected APIs:', selectedAPIs);

    if (selectedAPIs.length === 0) {
      displayError('Please select at least one API for analysis.');
      if (loadingIndicator) {
        loadingIndicator.style.display = 'none'; // Hide loading indicator
      }
      return;
    }

    // Validate that API keys are provided
    for (let api of selectedAPIs) {
      if (!apiConfigs[api].key) {
        displayError(`Please enter the API key for ${api}.`);
        if (loadingIndicator) {
          loadingIndicator.style.display = 'none';
        }
        return;
      }
      // Ther is no need to validate service URL for RapidAPI-hosted APIs as they don't use service urls and their urls are fixed so they don't require user input.
    }

    // Perform parallel API calls
    const apiPromises = selectedAPIs.map((api) => {
      if (api === 'MeaningCloud') return fetchMeaningCloud(text, selectedLang);
      if (api === 'Twinword') return fetchTwinword(text, selectedLang);
      if (api === 'SentimentAPI') return fetchSentimentAPI(text, selectedLang);
    });

    try {
      const apiResultsArray = await Promise.all(apiPromises);
      const apiResults = {};
      selectedAPIs.forEach((api, index) => {
        apiResults[api] = apiResultsArray[index];
      });

      console.log('API Results:', apiResults);

      // Check for any errors in API results
      const hasError = Object.values(apiResults).some(result => result.label === 'Error');
      if (hasError) {
        displayError('One or more APIs failed to process the sentiment analysis. Please check the console for details.');
      } else {
        // Display results
        displayResults(apiResults);
        displaySuccess('Sentiment analysis completed successfully!');
      }
    } catch (error) {
      console.error('Error in sentiment analysis:', error);
      displayError('An unexpected error occurred during sentiment analysis. Please try again.');
    } finally {
      // Hide loading indicator
      if (loadingIndicator) {
        loadingIndicator.style.display = 'none';
      }
    }
  }

  // =======================
  // ==== MODAL FUNCTIONALITY
  // =======================
  // Patrick: Closes the modal when clicking outside of it
  window.onclick = function (event) {
    const modal = document.getElementById('apiModal');
    if (event.target == modal) {
      modal.style.display = 'none';
    }
  };
}

// Initialize the Sentiment Dashboard
sentimentDashboard();