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) {
  let connection
  try {
    connection = await pool.getConnection()

    // 1. Get all notes joined with matieres
    const [response] = await connection.execute(
      `
      SELECT notes.*, matieres.*
      FROM notes
      JOIN matieres ON notes.matiere_id = matieres.id
      WHERE notes.etudiant_id = ? AND notes.etudiant_niveau = ?
      `,
      [id, niveau]
    )

    // 2. Optional: Build list of matiere_id (not used here but kept from original)
    const arrayResponseIdMatiere = response.map((note) => note.matiere_id)

    // 3. Same query again (as in your original) — this is redundant unless changed
    const [response2] = await connection.execute(
      `
      SELECT notes.*, matieres.*
      FROM notes
      JOIN matieres ON notes.matiere_id = matieres.id
      WHERE notes.etudiant_id = ? AND notes.etudiant_niveau = ?
      `,
      [id, niveau]
    )

    return response2
  } catch (error) {
    console.error('Error in getNote:', error)
    return { error: error.message }
  } finally {
    if (connection) connection.release()
  }
}

/**
 * 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 sql = 'SELECT DISTINCT etudiant_id, etudiant_niveau FROM notes'

    // Execute the query with the provided parameters
    const [rows] = await pool.query(sql)

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

/**
 * function to show moyenne in screen
 *
 * @returns promise
 */
async function showMoyen(niveau, scolaire) {
  try {
    // 1. Get distinct student IDs
    const [etudiantWithNotes] = await pool.query(
      `SELECT DISTINCT etudiant_id FROM notes WHERE etudiant_niveau = ? AND annee_scolaire = ?`,
      [niveau, scolaire]
    )

    let allEtudiantWithNotes = []

    // 2. Prepare the second query
    const query2 = `
      SELECT notes.*, etudiants.*, matieres.id AS matiere_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 = ?
    `

    // 3. Loop over each student and fetch their notes
    for (let index = 0; index < etudiantWithNotes.length; index++) {
      const etudiantId = etudiantWithNotes[index].etudiant_id
      const [rows] = await pool.query(query2, [etudiantId])
      allEtudiantWithNotes.push(rows) // push just the rows, not [rows, fields]
    }

    return allEtudiantWithNotes
  } catch (error) {
    console.error('Error in showMoyen:', error)
    return { error: error.message }
  }
}
/**
 * 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) {
  const matiere_id = Object.keys(formData)
  const values = Object.values(formData)

  try {
    let response

    for (let index = 0; index < matiere_id.length; index++) {
      let data = values[index]

      // Convert string to float safely
      if (typeof data === 'string') {
        data = parseFloat(data.replace(',', '.'))
      } else {
        data = parseFloat(String(data).replace(',', '.'))
      }

      // 1. Check if already in notesrepech
      const [check] = await pool.query(
        'SELECT * FROM notesrepech WHERE etudiant_id = ? AND matiere_id = ? AND etudiant_niveau = ?',
        [id, matiere_id[index], niveau]
      )

      if (data < 10) {
        // 2. If not already present, insert into notesrepech
        if (check.length === 0) {
          await pool.query(
            `INSERT INTO notesrepech (etudiant_id, matiere_id, etudiant_niveau, mention_id, note, annee_scolaire)
             VALUES (?, ?, ?, ?, ?, ?)`,
            [id, matiere_id[index], niveau, mention_id, 0, annee_scolaire]
          )
        }

        // 3. Update main note anyway
        ;[response] = await pool.query(
          'UPDATE notes SET note = ? WHERE etudiant_id = ? AND etudiant_niveau = ? AND matiere_id = ?',
          [data, id, niveau, matiere_id[index]]
        )
      } else {
        // 4. Remove from notesrepech if note >= 10
        await pool.query(
          'DELETE FROM notesrepech WHERE etudiant_id = ? AND etudiant_niveau = ? AND matiere_id = ?',
          [id, niveau, matiere_id[index]]
        )

        // 5. Update main note
        ;[response] = await pool.query(
          'UPDATE notes SET note = ? WHERE etudiant_id = ? AND etudiant_niveau = ? AND matiere_id = ?',
          [data, id, niveau, matiere_id[index]]
        )
      }
    }

    return response
  } catch (error) {
    console.error('Error updating note:', error)
    return error
  }
}

async function blockShowMoyene() {
  const query =
    'SELECT DISTINCT etudiant_niveau, annee_scolaire FROM notes ORDER BY annee_scolaire DESC'
  const queryMention = 'SELECT * FROM mentions'
  const query2 = `
    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 = ?
  `

  try {
    const [response] = await pool.query(query)
    const [mention] = await pool.query(queryMention)

    const niveau = response.map((item) => item.etudiant_niveau)
    const annee_scolaire = response.map((item) => item.annee_scolaire)

    let allData = []

    for (let i = 0; i < niveau.length; i++) {
      const [rows] = await pool.query(query2, [niveau[i], annee_scolaire[i]])
      allData.push(rows)
    }

    return { response, allData, mention }
  } catch (error) {
    console.error(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 = `
    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 {
    const [rows] = await pool.query(query, [id, niveau, annee_scolaire])
    return rows
  } catch (error) {
    return error
  }
}

async function getNotesWithRepechToDisplay(id, anneescolaire, niveau) {
  try {
    // Query for normal notes
    const [noteNormal] = await pool.query(
      `SELECT *
       FROM notes
       INNER JOIN matieres ON notes.matiere_id = matieres.id
       WHERE notes.etudiant_id = ?
         AND notes.annee_scolaire = ?
         AND notes.etudiant_niveau = ?`,
      [id, anneescolaire, niveau]
    )

    // Query for repechage notes
    const [noteRepech] = await pool.query(
      `SELECT *
       FROM notesrepech
       INNER JOIN matieres ON notesrepech.matiere_id = matieres.id
       WHERE notesrepech.etudiant_id = ?
         AND notesrepech.annee_scolaire = ?
         AND notesrepech.etudiant_niveau = ?`,
      [id, anneescolaire, niveau]
    )

    // Query for semesters and matiere-semestre mapping
    const [semestre] = await pool.query(
      `SELECT *
       FROM semestres
       INNER JOIN matiere_semestre ON semestres.id = matiere_semestre.semestre_id`
    )

    return { noteNormal, noteRepech, semestre }
  } catch (error) {
    return error
  }
}

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