Code viewer for World: Stock Recommendation System
// Made by Abhishek Malaviya
// Leave this trail here if you clone it

// Update v1.0:
// 1) Stock Data Fetching (Retrieves real-time stock prices, market cap, volume, etc. from Yahoo Finance API)
// 2) Analyst Recommendations (Displays stock recommendations based on analyst ratings)
// 3) Handles errors gracefully with clear messages (Error handling when data fetching fails)
// 4) Added real-time stock symbol input and fetching mechanism

// Update v1.1:
// 1) Improved Error Handling (Enhanced error prevention for missing data and failed requests)
// 2) Improved UI Layout (Background Colour, Aligned display of stock data and news for better user experience)
// 3) Refined Stock Symbol Input (Now accepts user input for any stock symbol, automatically converts to uppercase)
// 4) Console Logs for Debugging (Added logs to help track responses from APIs and data flow)

// Future v2.0 Plans:
// 1) Latest News Fetching (Fetches latest news related to the stock using the Investing News API)
// 2) Add Interactive Charts (To visually represent stock trends over time)
// 3) Improve Recommendation Logic (Use more complex analysis to provide buy/sell recommendations)
// 4) Extend News Fetching to Multiple Sources (Integrate more news APIs for diverse updates)
// 5) Redesign UI for better user experience and visualization of stock trends
// 6) Optimize API Fetching Logic for faster response times and better data accuracy

// Disclaimer: I have used Inspect Element’s AI tools and other debugging methods for understanding and improving the code,
// but the entire code is not made by AI. All code has been manually implemented and adjusted for the project’s needs.


// API KEY CONFIGURATION
const apiKey = "8e4cfa683cmshe2485f38a519a4bp1dd3afjsna53e1e493c72"; // Yahoo Finance API Key
const newsApiUrl = "https://investing11.p.rapidapi.com/get_news?news_type=latest&page=1"; // News API URL

// Bg styling config
document.write(`
  <style>
    body {
      margin: 0;
      padding: 0;
      height: 100vh;
      background: linear-gradient(45deg, blue, purple);
      background-size: 200% 200%;
      animation: gradientAnimation 15s ease infinite;
      font-family: Arial, sans-serif;
      display: flex;
      justify-content: center;
      align-items: center;
      z-index: -1;
      position: relative;
    }
    @keyframes gradientAnimation {
      0% { background-position: 0% 50%; }
      50% { background-position: 100% 50%; }
      100% { background-position: 0% 50%; }
    }
    .content {
      text-align: center;
      color: white;
      z-index: 1;
      position: relative;
    }
    button {
      margin-top: 10px;
      padding: 10px;
      cursor: pointer;
      background-color: #3498db;
      color: #fff;
      border-radius: 5px;
      border: none;
      font-size: 1rem;
    }
    #stockDataDisplay {
      background: inherit;
      padding: 20px;
      border-radius: 10px;
      font-size: 1.5rem;
      color: white;
      margin-top: 20px;
      font-weight: bold;
    }
    input {
      width: 50vw;
      padding: 10px;
      font-size: 1rem;
      margin-top: 10px;
      border-radius: 5px;
      border: none;
      background-color: rgba(255, 255, 255, 0.8);
    }
    #errorDisplay {
      color: red;
      font-size: 1.2rem;
      font-weight: bold;
      margin-top: 20px;
    }
  </style>
`);

// HTML Structure
document.write(`
  <div class="content">
    <h1>Stock Recommendation System</h1>
    <h3>Enter a stock ticker symbol to get the latest stock price and news sentiment.</h3>
    <div id="generated-quiz">
      <p id="generationText">Generation takes around 5 seconds...</p>
      <input id="stockTicker" placeholder="Enter Ticker" value="MSFT">
      <button onclick="fetchStockData();">Get Stock Data & News</button>
      <div id="stockDataDisplay"></div>
      <div id="errorDisplay"></div>
    </div>
  </div>
`);

// Function to Fetch Stock Data
async function fetchStockData() {
  const stockSymbol = document.getElementById("stockTicker").value.toUpperCase();
  const stockUrl = `https://yahoo-finance15.p.rapidapi.com/api/v1/markets/stock/quotes?ticker=${stockSymbol}&region=US`;

  try {
    const response = await fetch(stockUrl, {
      method: 'GET',
      headers: {
        'x-rapidapi-key': apiKey,
        'x-rapidapi-host': 'yahoo-finance15.p.rapidapi.com',
      },
    });

    const data = await response.json();
    console.log("Stock Data:", data);
    
    // MH edit
    console.log ( "Yahoo response:");
    console.log ( data.body[0] );
    

    if (data && data.body && data.body.length > 0) {
      const stockData = data.body[0];
      const output = `
        Stock Symbol: ${stockData.symbol}<br>
        Price: $${stockData.regularMarketPrice}<br>
        Market Cap: ${stockData.marketCap}<br>
        Volume: ${stockData.regularMarketVolume}<br>
        Recommendation: ${getRecommendation(stockData.averageAnalystRating)}
      `;
      document.getElementById("stockDataDisplay").innerHTML = output;
    } else {
      handleError("Unable to fetch stock data. Please try again later.");
    }
  } catch (error) {
    console.log("Fetch Stock Data Error:", error);
    handleError("Error fetching stock data: " + error.message);
  }
}

// Get Recommendation Based on Analyst Rating
function getRecommendation(analystRating) {
  if (!analystRating) return "Neutral.";
  if (analystRating.includes("Strong Buy")) return "Buy!";
  if (analystRating.includes("Buy")) return "Consider Buying.";
  if (analystRating.includes("Sell")) return "Sell.";
  return "Neutral.";
}

// Function to Fetch News Data
function fetchNewsData(stockSymbol) {
    
    // MH edit 
    console.log ("calling fetchNewsData");
    
    
  const xhr = new XMLHttpRequest();
  xhr.withCredentials = true;

  xhr.onreadystatechange = function () {
    if (xhr.readyState === XMLHttpRequest.DONE) {
      try {
        const response = JSON.parse(xhr.responseText);
        console.log("News Response:", response);

        if (response && response.data && Array.isArray(response.data)) {
          const newsArticles = response.data.map(
            (news) => news.headline || "No headline available"
          );
          displayNews(newsArticles);
        } else {
          document.getElementById("stockDataDisplay").innerHTML +=
            "<br>No relevant news found.";
        }
      } catch (error) {
        console.log("Fetch News Data Error:", error);
        handleError("Error processing news response: " + error.message);
      }
    }
  };

  xhr.open("GET", newsApiUrl);
  xhr.setRequestHeader("x-rapidapi-key", apiKey);
  xhr.setRequestHeader("x-rapidapi-host", "investing11.p.rapidapi.com");
  xhr.send();
}

// Display News Articles
function displayNews(newsArticles) {
  const newsContent = `
    <br>Latest News:<br>
    ${newsArticles.map((article, index) => `${index + 1}. ${article}<br>`).join("")}
  `;
  document.getElementById("stockDataDisplay").innerHTML += newsContent;
}

// Handle Errors
function handleError(message) {
  document.getElementById("errorDisplay").textContent = message;
}