// controllers/scoresController.js

const axios = require("axios");
const cache = require("../utils/cache"); // Import the cache
const Score = require("../models/Score"); // Import the Score model

/**
 * Fetches live scores for various leagues and stores them in the database.
 * Route: GET /scores
 */
async function scoresController(req, res) {
  try {
    // Check if live scores are cached
    const cachedScores = cache.get("liveScores");
    if (cachedScores) {
      console.log("Serving cached live scores");
      return res.status(200).json(cachedScores);
    }

    const apiUrl = "https://api.football-data.org/v4/matches";
    const response = await axios.get(apiUrl, {
      headers: {
        "X-Auth-Token": process.env.API_FOOTBALL_KEY,
      },
      params: {
        dateFrom: new Date(Date.now() - 24 * 60 * 60 * 1000)
          .toISOString()
          .split("T")[0],
        dateTo: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
          .toISOString()
          .split("T")[0],
      },
    });

    const leagueIds = {
      2014: "La Liga",
      2021: "Premier League",
      2002: "Bundesliga",
      2019: "Serie A",
      2015: "Ligue 1",
      2001: "UEFA Champions League",
      2146: "UEFA Europa League",
    };

    // Map and transform the data
    const filteredMatches = response.data.matches.map((match) => {
      const leagueName = leagueIds[match.competition.id] || "Other";

      // Map home and away team details
      const homeTeam = {
        id: match.homeTeam.id,
        name: match.homeTeam.name,
        shortName: match.homeTeam.shortName || "",
        tla: match.homeTeam.tla || "",
        crest: match.homeTeam.crest || "",
      };

      const awayTeam = {
        id: match.awayTeam.id,
        name: match.awayTeam.name,
        shortName: match.awayTeam.shortName || "",
        tla: match.awayTeam.tla || "",
        crest: match.awayTeam.crest || "",
      };

      // Map score details
      const score = {
        winner: match.score.winner,
        duration: match.score.duration
          ? match.score.duration.toUpperCase()
          : "REGULAR",
        fullTime: {
          home: match.score.fullTime?.home || null,
          away: match.score.fullTime?.away || null,
        },
        halfTime: {
          home: match.score.halfTime?.home || null,
          away: match.score.halfTime?.away || null,
        },
      };

      return {
        id: match.id,
        utcDate: new Date(match.utcDate),
        status: match.status.toUpperCase(),
        league: leagueName,
        homeTeam: homeTeam,
        awayTeam: awayTeam,
        score: score,
        odds: parseFloat(Math.random().toFixed(2)),
        avgP: parseFloat((Math.random() * 100).toFixed(2)),
        avgG: parseFloat((Math.random() * 5).toFixed(2)),
        cG: Math.floor(Math.random() * 10),
        BTS: Math.random() > 0.5 ? "Yes" : "No",
        FTS: Math.random() > 0.5 ? "Yes" : "No",
        cOver25: Math.random() > 0.5 ? "Yes" : "No",
      };
    });

    // Save matches to the database
    await saveMatches(filteredMatches);

    // Group matches by league for caching and response
    const groupedMatches = filteredMatches.reduce((acc, match) => {
      if (!acc[match.league]) {
        acc[match.league] = [];
      }
      acc[match.league].push(match);
      return acc;
    }, {});

    // Cache the live scores with a shorter TTL (e.g., 2 minutes)
    cache.set("liveScores", groupedMatches, 120);

    console.log("Fetched and cached live scores, and saved to DB");

    res.status(200).json(groupedMatches);
  } catch (error) {
    console.error("Error fetching live scores:", error.message);
    res.status(500).json({
      message: "Unable to retrieve live scores. Please try again later.",
    });
  }
}

/**
 * Saves matches to the database using upsert to avoid duplicates.
 * @param {Array} matches - Array of match objects to save.
 */
async function saveMatches(matches) {
  try {
    const bulkOps = matches.map((match) => ({
      updateOne: {
        filter: { id: match.id }, // Unique identifier
        update: { $set: match },
        upsert: true,
      },
    }));

    const result = await Score.bulkWrite(bulkOps);
    console.log(
      `${result.upsertedCount} matches inserted, ${result.modifiedCount} matches updated.`
    );
  } catch (error) {
    console.error("Error saving matches with upsert:", error);
    // Depending on your requirements, you might want to throw the error to be caught in the main controller
    throw error;
  }
}

module.exports = scoresController;

// models/score.js

const mongoose = require("mongoose");

const TeamSchema = new mongoose.Schema(
  {
    id: {
      type: Number,
      required: true,
    },
    name: {
      type: String,
      required: true,
    },
    shortName: {
      type: String,
      required: true,
    },
    tla: {
      type: String,
      required: true,
      uppercase: true,
      minlength: 3,
      maxlength: 3,
    },
    crest: {
      type: String,
      required: true,
      match: /^https?:\/\/.+\.(png|jpg|jpeg|svg)$/,
    },
  },
  { _id: false }
);

const ScoreSchema = new mongoose.Schema(
  {
    id: {
      type: Number,
      required: true,
      unique: true,
    },
    utcDate: {
      type: Date,
      required: true,
    },
    status: {
      type: String,
      required: true,
      enum: [
        "SCHEDULED",
        "LIVE",
        "INPLAY",
        "FINISHED",
        "PAUSED",
        "CANCELLED",
        "POSTPONED",
        "TIMED",
      ],
    },
    league: {
      type: String,
      required: true,
      default: "Other",
    },
    homeTeam: {
      type: TeamSchema,
      required: true,
    },
    awayTeam: {
      type: TeamSchema,
      required: true,
    },
    score: {
      winner: {
        type: String,
        enum: ["HOME_TEAM", "AWAY_TEAM", "DRAW", null],
        default: null,
      },
      duration: {
        type: String,
        required: true,
        enum: ["REGULAR", "EXTRA_TIME", "PENALTY"],
      },
      fullTime: {
        home: { type: Number, default: null },
        away: { type: Number, default: null },
      },
      halfTime: {
        home: { type: Number, default: null },
        away: { type: Number, default: null },
      },
    },
    odds: {
      type: Number,
      min: 0,
      required: true,
    },
    avgP: {
      type: Number,
      min: 0,
      max: 100,
      required: true,
    },
    avgG: {
      type: Number,
      min: 0,
      required: true,
    },
    cG: {
      type: Number,
      min: 0,
      required: true,
    },
    BTS: {
      type: String,
      enum: ["Yes", "No"],
      required: true,
    },
    FTS: {
      type: String,
      enum: ["Yes", "No"],
      required: true,
    },
    cOver25: {
      type: String,
      enum: ["Yes", "No"],
      required: true,
    },
  },
  {
    timestamps: true,
  }
);

// Indexes for optimized queries
ScoreSchema.index({ id: 1 });
ScoreSchema.index({ league: 1, status: 1 });

// Export the model
module.exports = mongoose.model("Score", ScoreSchema);

const cron = require("node-cron");
const axios = require("axios");

// Function to fetch live scores
const fetchLiveScores = async () => {
  try {
    const response = await axios.get(
      "https://api.football-data.org/v4/matches",
      {
        headers: { "X-Auth-Token": process.env.API_FOOTBALL_KEY },
      }
    );
    console.log("Live scores fetched:", response.data);
  } catch (error) {
    console.error("Error fetching live scores:", error);
  }
};

// Function to start the cron job (run every 1 minutes)
const start = () => {
  cron.schedule("*/5 * * * *", async () => {
    console.log("Fetching live scores...");
    await fetchLiveScores();
  });
  console.log("Cron job started: Fetching live scores every 2 minutes");
};

module.exports = { start };
// taskQueueWorker.js
const { fetchLiveScores } = require("./services/apiService");
const { start } = require("./taskQueue/matchUpdateQueue");
// Initialize cron job worker to start fetching live scores every 5 minutes
start();

// You can add other workers or background tasks here as needed
// utils/cache.js

const NodeCache = require("node-cache");

// Initialize cache with a default TTL of 5 minutes (300 seconds)
const cache = new NodeCache({ stdTTL: 300, checkperiod: 320 });

// Optional: Listen for expired keys (useful for logging or debugging)
cache.on("expired", (key, value) => {
  console.log(`Cache expired for key: ${key}`);
});

module.exports = cache;
// utils/cacheHelper.js

const cache = require("./cache");

/**
 * Retrieves data from the cache or fetches it using the provided fetch function.
 *
 * @param {string} key - The cache key.
 * @param {Function} fetchFn - The function to fetch data if not in cache.
 * @returns {Promise<any>} - The cached or fetched data.
 */
async function getCachedData(key, fetchFn) {
  const cachedData = cache.get(key);
  if (cachedData) {
    console.log(`Cache hit for key: ${key}`);
    return cachedData;
  }

  console.log(`Cache miss for key: ${key}. Fetching data...`);
  const data = await fetchFn();
  cache.set(key, data);
  console.log(`Data cached for key: ${key}`);
  return data;
}

module.exports = { getCachedData };
So In this I have uploading data to backend now what I want is that I want to use that data to front end like when requesting data localhost:5000/api/scores it should fetch data from db 
and other thing is that I'm fetching data every minute so after only upto 5 data are stored in db let's say it takes x mb in one score data chunk so I only want to store till 5x then delete from backward like pop the data from db make changes to these files I think it can be done in these files only no need to make logger.js or anything . Can you think of it ?