package org.mte.numecoeval.calculs.infrastructure.repository;

import lombok.extern.slf4j.Slf4j;
import org.mte.numecoeval.calculs.domain.exception.DatabaseException;
import org.mte.numecoeval.common.utils.ResultSetUtils;
import org.mte.numecoeval.topic.data.DataCenterDTO;
import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

@Component
@Slf4j
public class EquipementPhysiqueRepository {

    @Autowired
    private DataSource dataSource;

    private static final String COLUMN_NAME_NOM_COURT_DATACENTER = "nom_court_datacenter";

    public List<EquipementPhysiqueDTO> findEquipementPhysiqueDTOs(List<Long> ids) {
        List<EquipementPhysiqueDTO> result = new ArrayList<>();

        try (Connection conn = dataSource.getConnection()) {
            try (var ps = conn.prepareStatement("""
                       SELECT eqp.*,
                          dc.id as dc_id,
                          dc.date_creation as dc_date_creation,
                          dc.date_update as dc_date_update,
                          dc.localisation as dc_localisation,
                          dc.nom_long_datacenter as dc_nom_long_datacenter,
                          dc.pue as dc_pue,
                          dc.nom_entite as dc_nom_entite,
                          dc.qualite as dc_qualite
                        FROM en_equipement_physique eqp
                        LEFT JOIN en_data_center dc ON dc.nom_lot = eqp.nom_lot and dc.nom_court_datacenter = eqp.nom_court_datacenter
                        WHERE eqp.id = ANY (?)
                    """)) {

                ps.setArray(1, conn.createArrayOf("long", ids.toArray(new Long[0])));

                var rs = ps.executeQuery();
                while (rs.next()) {
                    result.add(EquipementPhysiqueDTO.builder()
                            .id(rs.getLong("id"))
                            .nomLot(rs.getString("nom_lot"))
                            .dateLot(ResultSetUtils.getLocalDate(rs, "date_lot"))
                            .nomOrganisation(rs.getString("nom_organisation"))
                            .nomEntite(rs.getString("nom_entite"))
                            .nomEquipementPhysique(rs.getString("nom_equipement_physique"))
                            .consoElecAnnuelle(ResultSetUtils.getDouble(rs, "conso_elec_annuelle"))
                            .dateAchat(ResultSetUtils.getLocalDate(rs, "date_achat"))
                            .dateRetrait(ResultSetUtils.getLocalDate(rs, "date_retrait"))
                            .dureeUsageInterne(ResultSetUtils.getDouble(rs, "duree_usage_interne"))
                            .dureeUsageAmont(ResultSetUtils.getDouble(rs, "duree_usage_amont"))
                            .dureeUsageAval(ResultSetUtils.getDouble(rs, "duree_usage_aval"))
                            .goTelecharge(ResultSetUtils.getFloat(rs, "go_telecharge"))
                            .modele(rs.getString("modele"))
                            .nbCoeur(rs.getString("nb_coeur"))
                            .paysDUtilisation(rs.getString("pays_utilisation"))
                            .quantite(ResultSetUtils.getDouble(rs, "quantite"))
                            .serveur(rs.getBoolean("serveur"))
                            .statut(rs.getString("statut"))
                            .type(rs.getString("type"))
                            .utilisateur(rs.getString("utilisateur"))
                            .nomCourtDatacenter(rs.getString(COLUMN_NAME_NOM_COURT_DATACENTER))
                            .nomCourtDatacenter(rs.getString(COLUMN_NAME_NOM_COURT_DATACENTER))
                            .nomSourceDonnee(rs.getString("nom_source_donnee"))
                            .modeUtilisation(rs.getString("mode_utilisation"))
                            .tauxUtilisation(ResultSetUtils.getDouble(rs, "taux_utilisation"))
                            .qualite(rs.getString("qualite"))
                            .dataCenter(
                                    DataCenterDTO.builder()
                                            .id(rs.getLong("dc_id"))
                                            .localisation(rs.getString("dc_localisation"))
                                            .nomLongDatacenter(rs.getString("dc_nom_long_datacenter"))
                                            .pue(ResultSetUtils.getDouble(rs, "dc_pue"))
                                            .nomCourtDatacenter(rs.getString(COLUMN_NAME_NOM_COURT_DATACENTER))
                                            .nomEntite(rs.getString("dc_nom_entite"))
                                            .nomOrganisation(rs.getString("nom_organisation"))
                                            .dateLot(ResultSetUtils.getLocalDate(rs, "date_lot"))
                                            .qualite(rs.getString("dc_qualite"))
                                            .build()
                            )
                            .build());
                }
            }
        } catch (SQLException e) {
            log.error("Une erreur s'est produite lors de la selection dans PostgreSQL. Exception: ", e);
            throw new DatabaseException(e);
        }

        return result;
    }

    public void setStatutToTraite(Long id) {
        try (Connection conn = dataSource.getConnection()) {
            try (var ps = conn.prepareStatement("""
                    UPDATE en_equipement_physique
                    SET statut_traitement = 'TRAITE', date_update = now()
                    WHERE id = ?
                    """)) {
                ps.setLong(1, id);
                ps.execute();
            }
        } catch (SQLException e) {
            log.error("Une erreur s'est produite lors de la selection dans PostgreSQL. Exception: ", e);
            throw new DatabaseException(e);
        }
    }
}
