const express = require('express')
const app = express()
const port = 9700

const web3operatorAddress = "http://vps.playpoolstudios.com:2015/"
const apiAddress = "https://vps.playpoolstudios.com/metahunt/api/"

app.get('/', (req, res) => {
  res.send('Validator is validating')
})

app.listen(port, () => {
  console.log(`Mhunt Validator is listening on port ${port}`)
})

app.get('/validateSession', async (req, res) => {
  const { tournamentId, address } = req.query;

  if (!tournamentId || !address) { res.send("invalid params"); return; }
  let tournament = GetTournamentById(tournamentId);
  if (tournament == null) {
    await CheckForStartedTourneys();
    tournament = GetTournamentById(tournamentId);
  }
  if (tournament == null) {
    console.log(`tourney id:${tournamentId} is not available`);
    //res.send("This tournament is not either started or valid");
    // return;
  }

  tournament.displayDetails();
  const found = tournament.participents.some(participant => participant == address);

  if (found) {
    return res.send("0");
  } else {
    return res.send("-1");
  }

})

app.post('/updateBlock', async (req, res) => {
  const jsonData = req.body;
  
  const tournamentBlock = new TournamentBlockData(jsonData);
  tournamentBlocks.push(tournamentBlock);

  console.log(tournamentBlocks);

  res.sendStatus(200);
});


/* ------------------------------------------------------------------------------- */

let tournamentsList ;
let startedTournaments;
let tournamentBlocks = [];

/* ------------------------------------------------------------------------------- */

CheckForStartedTourneys();
setInterval(async () => {
  CheckForStartedTourneys();
}, 60000)

async function CheckForStartedTourneys() {
  const tournamentsResponse = await fetch(apiAddress + "get_tournaments_raw.php");
  const tournaments = await tournamentsResponse.json();

  tournamentsList = [];
  startedTournaments = [];
  const now = new Date();
  const tenMinutesAgo = new Date(now.getTime() - 10 * 60000); // 10 minutes ago from now

  tournaments.forEach(async tournament => {
    const tournamentDate = new Date(tournament.start_date); // Converts the string date to a Date object

    // Create a new TournamentData instance using the tournament JSON data
    const newTournament = new TournamentData(
      tournament.id,
      tournament.name,
      tournament.start_date,
      tournament.game_mode,
      tournament.reward,
      tournament.php_reward,
      tournament.is_test,
      tournament.ticket_count,
      tournament.owner_id
    );

    if (tournamentDate >= tenMinutesAgo && tournamentDate <= now || true) {
      console.log(`Tournament "${tournament.name}" started within the last 10 minutes.`);

      const participentsUrl = web3operatorAddress + "getTournamentParticipants?id=" + newTournament.id;
      const participentsResponse = await fetch(participentsUrl);
      const participentsJson = await participentsResponse.json();
      const participents = participentsJson["wallets"].split(',');
      try {
        participents.forEach(participent => {
          newTournament.participents.push(participent);
        })

        newTournament.displayDetails();
      } catch {
        console.log(`tourneyId:${newTournament.id} has no participents. ${JSON.stringify(participents)}`)
      }


      startedTournaments.push(newTournament);
    } else if (tournamentDate > now) {
      console.log(`Tournament "${tournament.name}" is yet to come`)
    } else {
      //  console.log(`Tournament "${tournament.name}" is expired`)
    }
    // newTournament.displayDetails();
    // Push the new tournament instance into tournamentsList
    tournamentsList.push(newTournament);
  });
}

/* ------------------------------------------------------------------------------- */

setInterval(async () => {
  ScanBlocks();
}, 60000)

function ScanBlocks(){
  for(let i=0; i < tournamentBlocks.length; i++){
    let isValid = true;
    for(let j=0; j < startedTournaments.length; j++){
      if(startedTournaments[j].id == tournamentBlocks[i].tournamentId){
        //Found the matching tourney for this block
        if(!startedTournaments[j].participents.include(tournamentBlocks[i].owner)){
          // isValid=false;
          console.log("***Block was sent by non-participent. Allowing this for now.");
        }
        break;
      }
    }

  }
}


/* ----------------------------------METHODS----------------------------------- */

function GetTournamentById(tournamentId) {
  const tournament = startedTournaments.find(tournament => tournament.id == tournamentId);
  return tournament;
}
/* ------------------------------------------------------------------------------- */







/* ------------------------------CUSTOM CLASSES------------------------------------ */


class TournamentData {
  constructor(id, name, start_date, game_mode, reward, php_reward, is_test, ticket_count, owner_id) {
    this.id = id;
    this.name = name;
    this.start_date = start_date;
    this.game_mode = game_mode;
    this.reward = reward;
    this.php_reward = php_reward;
    this.is_test = is_test;
    this.ticket_count = ticket_count;
    this.owner_id = owner_id;
    this.participents = [];
  }

  // Method to display tournament details
  displayDetails() {
    console.log(`Tournament ID: ${this.id}`);
    console.log(`Name: ${this.name}`);
    console.log(`Date: ${this.start_date}`);
    console.log(`Game Mode: ${this.game_mode}`);
    console.log(`Reward: ${this.reward}`);
    console.log(`PHP Reward: ${this.php_reward}`);
    console.log(`Test Tournament: ${this.is_test ? "Yes" : "No"}`);
    console.log(`Ticket Count: ${this.ticket_count}`);
    console.log(`Owner ID: ${this.owner_id}`);
    console.log(`Participents: ${this.participents}`);

  }
}


// Define a dictionary to store tournament leaderboards after validation
const confirmedLeaderboards = {};

// Function to scan and analyze blocks
function ScanBlocks() {
  const blockValidationCounts = {};

  // First, validate each block and count valid ones for each tournament
  for (let i = 0; i < tournamentBlocks.length; i++) {
    let isValid = true;

    // Loop through the started tournaments to validate the block
    for (let j = 0; j < startedTournaments.length; j++) {
      if (startedTournaments[j].id === tournamentBlocks[i].tournamentId) {
        // Found the matching tournament for this block
        if (!startedTournaments[j].participants.includes(tournamentBlocks[i].owner)) {
          console.log("***Block was sent by non-participant. Allowing this for now.");
          isValid = false;
          break;
        }

        // Compare blocks with the same tournamentId and minute number
        for (let k = 0; k < tournamentBlocks.length; k++) {
          if (
            k !== i && 
            tournamentBlocks[k].tournamentId === tournamentBlocks[i].tournamentId &&
            tournamentBlocks[k].minute === tournamentBlocks[i].minute
          ) {
            // Found another block with the same tournamentId and minute
            if (JSON.stringify(tournamentBlocks[k].leaderboard) !== JSON.stringify(tournamentBlocks[i].leaderboard)) {
              console.log(`***Mismatch detected in leaderboard for tournament ${tournamentBlocks[i].tournamentId} at minute ${tournamentBlocks[i].minute}`);
              isValid = false;
              break;
            }
          }
        }
      }
    }

    if (isValid) {
      console.log(`Block ${i + 1} is valid.`);
      
      // Track the valid blocks per tournament
      const tournamentId = tournamentBlocks[i].tournamentId;
      if (!blockValidationCounts[tournamentId]) {
        blockValidationCounts[tournamentId] = { count: 0, total: 0 };
      }
      blockValidationCounts[tournamentId].count++;
    } else {
      console.log(`Block ${i + 1} is invalid.`);
    }

    // Track total blocks per tournament for comparison later
    const tournamentId = tournamentBlocks[i].tournamentId;
    if (!blockValidationCounts[tournamentId]) {
      blockValidationCounts[tournamentId] = { count: 0, total: 0 };
    }
    blockValidationCounts[tournamentId].total++;
  }

  // After validation, confirm tournaments with more than 50% valid blocks
  for (const tournamentId in blockValidationCounts) {
    const { count, total } = blockValidationCounts[tournamentId];
    if (count > total / 2) {
      // More than 50% of blocks are valid, store the leaderboard
      const validBlock = tournamentBlocks.find(block => block.tournamentId === parseInt(tournamentId));
      if (validBlock) {
        confirmedLeaderboards[tournamentId] = validBlock.leaderboard;
        console.log(`*** Tournament ${tournamentId} confirmed with a valid leaderboard.`);
      }
    } else {
      console.log(`*** Tournament ${tournamentId} did not meet the 50% valid block requirement.`);
    }
  }
}