const { pool } = require('../database')
const { matiereSysteme } = require('../function/System')

/**
 * Function to insert notes into the database
 * @param {Object} formData - The form data containing subject names and values
 * @param {number} etudiant_id - The student ID
 * @param {string} etudiant_niveau - The student level
 * @returns {Promise} - Promise resolving to the database response or an error
 */
async function insertNote(etudiant_id, etudiant_niveau, mention_id, formData, annee_scolaire) {
  const matiere_id = Object.keys(formData)
  const values = Object.values(formData)

  const insertNoteSQL = `
    INSERT INTO notes (etudiant_id, matiere_id, etudiant_niveau, mention_id, note, annee_scolaire)
    VALUES (?, ?, ?, ?, ?, ?)
  `

  const insertRepechSQL = `
    INSERT INTO notesrepech (etudiant_id, matiere_id, etudiant_niveau, mention_id, note, annee_scolaire)
    VALUES (?, ?, ?, ?, ?, ?)
  `

  const connection = await pool.getConnection()
  let newMatiereId = []

  try {
    await connection.beginTransaction()

    // Insert into notes table
    for (let j = 0; j < matiere_id.length; j++) {
      const noteValue = parseFloat(values[j].replace(',', '.')) || 0
      if (noteValue < 10) {
        newMatiereId.push(matiere_id[j])
      }

      await connection.execute(insertNoteSQL, [
        etudiant_id,
        matiere_id[j],
        etudiant_niveau,
        mention_id,
        noteValue,
        annee_scolaire
      ])
    }

    // Insert into notesrepech with note = 0
    for (let j = 0; j < newMatiereId.length; j++) {
      await connection.execute(insertRepechSQL, [
        etudiant_id,
        newMatiereId[j],
        etudiant_niveau,
        mention_id,
        0,
        annee_scolaire
      ])
    }

    await connection.commit()
    return { success: true }
  } catch (error) {
    await connection.rollback()
    console.error('Error inserting notes:', error)
    return { error: error.message }
  } finally {
    connection.release()
  }
}

/**
 *
 * @returns promise
 */
async function getNoteOnline() {
  const sql = 'SELECT notes.* FROM notes '

  try {
    let [rows] = await pool.query(sql)

    return rows
  } catch (error) {
    return error
  }
}

/**
 *
 * @returns promise
 */
async function getNote(id, niveau, mention_id) {
  // let semestre = await matiereSysteme(niveau)

  const query = database.prepare(
    'SELECT notes.*, matieres.* FROM notes JOIN matieres ON (notes.matiere_id = matieres.id) WHERE notes.etudiant_id = ? AND notes.etudiant_niveau = ?'
  )
  // const matiereQuery = database.prepare(`
  //   SELECT DISTINCT m.*
  //   FROM matieres m
  //   JOIN matiere_semestre ms ON m.id = ms.matiere_id
  //   JOIN semestres s ON ms.semestre_id = s.id
  //   WHERE (s.nom LIKE ? OR s.nom LIKE ?)
  //     AND ms.mention_id = ?
  // `)

  // let res = await matiereQuery.all(`%${semestre[0]}%`, `%${semestre[1]}%`, mention_id)

  let response = await query.all(id, niveau)
  // const infoEtudiants = database.prepare('SELECT * FROM etudiants WHERE id = ?')
  // let etudiant = await infoEtudiants.get(id)

  let arrayResponseIdMatiere = []
  for (let index = 0; index < response.length; index++) {
    arrayResponseIdMatiere.push(response[index].matiere_id)
  }

  // const filteredIds = res
  //   .filter((matiere) => !arrayResponseIdMatiere.includes(matiere.id))
  //   .map((matiere) => matiere.id)

  // const json = filteredIds.reduce((acc, id) => {
  //   acc[id] = '0'
  //   return acc
  // }, {})

  const query2 = database.prepare(
    'SELECT notes.*, matieres.* FROM notes JOIN matieres ON (notes.matiere_id = matieres.id) WHERE notes.etudiant_id = ? AND notes.etudiant_niveau = ?'
  )

  try {
    let response2 = query2.all(id, niveau)
    return response2
  } catch (error) {
    console.error('Error in query2:', error)
    return error
  }
}

/**
 * Verify if a student has notes
 * @returns {Promise<Array>} - Promise resolving to an array of notes or an empty array
 */
async function verifyEtudiantIfHeHasNotes() {
  try {
    // Prepare the query to filter by etudiant_id and etudiant_niveau
    const query = database.prepare('SELECT DISTINCT etudiant_id, etudiant_niveau FROM notes')

    // Execute the query with the provided parameters
    const response = query.all()

    // Return the response
    return response
  } catch (error) {
    console.error('Error verifying student notes:', error)
    throw error
  }
}

/**
 * function to show moyenne in screen
 *
 * @returns promise
 */
async function showMoyen(niveau, scolaire) {
  const query = database.prepare(
    `SELECT DISTINCT etudiant_id FROM notes WHERE etudiant_niveau = ? AND annee_scolaire = ?`
  )

  let etudiantWithNotes = await query.all(niveau, scolaire)

  let allEtudiantWithNotes = []

  const query2 = database.prepare(
    'SELECT notes.*, etudiants.*, matieres.id, matieres.nom AS nomMat, matieres.credit FROM notes INNER JOIN etudiants ON (notes.etudiant_id = etudiants.id) INNER JOIN matieres ON (notes.matiere_id = matieres.id) WHERE notes.etudiant_id = ?'
  )

  try {
    for (let index = 0; index < etudiantWithNotes.length; index++) {
      allEtudiantWithNotes.push(query2.all(etudiantWithNotes[index].etudiant_id))
    }

    return allEtudiantWithNotes
  } catch (error) {
    return error
  }
}

/**
 * function used when updating note
 * @param {Object} formData - The form data containing subject names and values
 * @param {string} niveau - The student level
 * @returns {Promise} - Promise resolving to the database response or an error
 */
async function updateNote(formData, niveau, id, mention_id, annee_scolaire) {
  // Extract keys and values dynamically
  const matiere_id = Object.keys(formData)
  const values = Object.values(formData)

  const query = database.prepare(
    'UPDATE notes SET note= ? WHERE etudiant_id = ? AND etudiant_niveau = ? AND matiere_id = ?'
  )

  const clearFromRepech = database.prepare(
    'DELETE FROM notesrepech WHERE etudiant_id = ? AND etudiant_niveau = ? AND matiere_id = ?'
  )
  const insertRepechQuery = database.prepare(
    `INSERT INTO notesrepech (etudiant_id, matiere_id, etudiant_niveau, mention_id, note, annee_scolaire) VALUES (?, ?, ?, ?, ?, ?)`
  )

  const checkRepechQuery = database.prepare(
    'SELECT * FROM notesrepech WHERE etudiant_id = ? AND matiere_id = ? AND etudiant_niveau = ?'
  )

  try {
    let response

    for (let index = 0; index < matiere_id.length; index++) {
      let data = values[index]
      if (typeof data === 'string') {
        data = parseFloat(data.replace(',', '.'))
      } else {
        data = parseFloat(String(data).replace(',', '.'))
      }
      let check = await checkRepechQuery.get(id, matiere_id[index], niveau)
      if (data < 10) {
        if (!check) {
          insertRepechQuery.run(id, matiere_id[index], niveau, mention_id, 0, annee_scolaire)
        }
        response = await query.run(data, id, niveau, matiere_id[index])
      } else {
        clearFromRepech.run(id, niveau, matiere_id[index])
        response = await query.run(data, id, niveau, matiere_id[index])
      }
    }

    return response
  } catch (error) {
    return error
  }
}

async function blockShowMoyene() {
  const query = database.prepare(
    'SELECT DISTINCT etudiant_niveau, annee_scolaire FROM notes ORDER BY annee_scolaire DESC'
  )

  const queryMention = database.prepare('SELECT * FROM mentions')

  try {
    let response = await query.all()
    let mention = await queryMention.all()
    let niveau = response.map((item) => item.etudiant_niveau)
    let annee_scolaire = response.map((item) => item.annee_scolaire)
    const query2 = database.prepare(
      `SELECT notes.*, etudiants.id AS etudiantsId, etudiants.mention_id AS mentionId, etudiants.niveau, matieres.* FROM notes INNER JOIN etudiants ON (notes.etudiant_id = etudiants.id) INNER JOIN matieres ON (notes.matiere_id = matieres.id) WHERE notes.etudiant_niveau = ? AND notes.annee_scolaire = ?`
    )

    let allData = []

    for (let index = 0; index < niveau.length; index++) {
      allData.push(await query2.all(niveau[index], annee_scolaire[index]))
    }

    return { response, allData, mention }
  } catch (error) {
    return error
  }
}

/**
 * get all note with matiere for single student
 * @param {*} id
 * @param {*} niveau
 * @param {*} annee_scolaire
 * @returns promise
 */
async function getMatiereAndNote(id, niveau, annee_scolaire) {
  const query = database.prepare(
    'SELECT * FROM notes INNER JOIN matieres ON (notes.matiere_id = matieres.id) WHERE notes.etudiant_id = ? AND notes.etudiant_niveau = ? AND notes.annee_scolaire = ?'
  )

  try {
    let response = await query.all(id, niveau, annee_scolaire)

    return response
  } catch (error) {
    return error
  }
}

async function getNotesWithRepechToDisplay(id, anneescolaire, niveau) {
  const queryNoteNormal = database.prepare(
    'SELECT * FROM notes INNER JOIN matieres ON (notes.matiere_id = matieres.id) WHERE notes.etudiant_id = ? AND notes.annee_scolaire = ? AND notes.etudiant_niveau = ?'
  )
  let noteNormal = await queryNoteNormal.all(id, anneescolaire, niveau)

  const queryNoteRepech = database.prepare(
    'SELECT * FROM notesrepech INNER JOIN matieres ON (notesrepech.matiere_id = matieres.id) WHERE notesrepech.etudiant_id = ? AND notesrepech.annee_scolaire = ? AND notesrepech.etudiant_niveau = ?'
  )
  let noteRepech = await queryNoteRepech.all(id, anneescolaire, niveau)

  const semestreQuery = database.prepare(
    'SELECT * FROM semestres INNER JOIN matiere_semestre ON(semestres.id = matiere_semestre.semestre_id)'
  )
  let semestre = await semestreQuery.all()

  return { noteNormal, noteRepech, semestre }
}

module.exports = {
  insertNote,
  getNote,
  showMoyen,
  getNoteOnline,
  verifyEtudiantIfHeHasNotes,
  updateNote,
  blockShowMoyene,
  getMatiereAndNote,
  getNotesWithRepechToDisplay
}
