package danielcortes.xyz.models.detalle;

import danielcortes.xyz.data.ConnectionHolder;
import danielcortes.xyz.data.DAOManager;
import danielcortes.xyz.data.SQLiteConnectionHolder;
import danielcortes.xyz.models.estado_resultado.EstadoResultado;
import danielcortes.xyz.models.tipo_detalle.TipoDetalle;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class SQLiteDetalleDAO implements DetalleDAO{
  private static final Logger log = LogManager.getLogger(SQLiteDetalleDAO.class);
  private ConnectionHolder connectionHolder;

  public SQLiteDetalleDAO() {
    this.connectionHolder = new SQLiteConnectionHolder();
  }

  public SQLiteDetalleDAO(ConnectionHolder connectionHolder) {
    this.connectionHolder = connectionHolder;
  }

  @Override
  public List<Detalle> getAll() {
    log.debug("Se intentaran conseguir todos los Detalle");
    List<Detalle> detalleList = new ArrayList<>();
    String query = "select * from detalles";
    try (Connection conn = connectionHolder.getConnection()) {
      try (PreparedStatement ps = conn.prepareStatement(query)) {
        try (ResultSet rs = ps.executeQuery()) {
          while (rs.next()) {
            //Confio en que la base de datos mapeo correctamente el estado_resultado_id
            @SuppressWarnings("OptionalGetWithoutIsPresent")
            EstadoResultado estadoResultado= DAOManager.getEstadoResultadoDAO().getById(rs.getInt("estado_resultado_id")).get();
            //Confio en que la base de datos mapeo correctamente el tipo_detalle_id
            @SuppressWarnings("OptionalGetWithoutIsPresent")
            TipoDetalle tipoDetalle = DAOManager.getTipoDetalleDAO().getById(rs.getInt("tipo_detalle_id")).get();

            Detalle detalle = new Detalle();
            detalle.setId(rs.getInt("id"));
            detalle.setDescripcion(rs.getString("descripcion"));
            detalle.setValor(rs.getInt("valor"));
            detalle.setEstadoResultado(estadoResultado);
            detalle.setTipoDetalle(tipoDetalle);
            detalleList.add(detalle);
          }
        }
      }
    } catch (SQLException e) {
      log.error("Error al intentar conseguir todos los Detalles de la base de datos", e);
    }
    log.debug("Se consiguieron " + detalleList.size() + " Detalles");
    return detalleList;
  }

  @Override
  public List<Detalle> getByTipoDetalle(TipoDetalle tipoDetalle) {
    log.debug("Se intentaran conseguir los detalle pertenecientes al tipo detalle " + tipoDetalle);
    List<Detalle> detalleList = new ArrayList<>();

    if(tipoDetalle == TipoDetalle.EMPTY){
      log.debug("El tipo detalle entregado era EMPTY");
      return new ArrayList<>();
    }

    String query = "select * from detalles where tipo_detalle_id = ?";
    try (Connection conn = connectionHolder.getConnection()) {
      try (PreparedStatement ps = conn.prepareStatement(query)){
        ps.setInt(1, tipoDetalle.getId());
        try(ResultSet rs = ps.executeQuery()){
          while(rs.next()){
            //Confio en que la base de datos mapeo correctamente el estado_resultado_id
            @SuppressWarnings("OptionalGetWithoutIsPresent")
            EstadoResultado estadoResultado= DAOManager.getEstadoResultadoDAO().getById(rs.getInt("estado_resultado_id")).get();

            Detalle detalle = new Detalle();
            detalle.setId(rs.getInt("id"));
            detalle.setDescripcion(rs.getString("descripcion"));
            detalle.setValor(rs.getInt("valor"));
            detalle.setEstadoResultado(estadoResultado);
            detalle.setTipoDetalle(tipoDetalle);
          }
        }
      }
    }catch (SQLException e) {
      log.error("Error al intentar conseguir los Detalles de la base de datos", e);
    }
    log.debug("Se consiguieron " + detalleList.size() + "Detalles");
    return detalleList;
  }

  @Override
  public Optional<Detalle> getById(int id) {
    log.debug("Se intentaran conseguir el detalle con id " + id);
    String query = "select * from detalles where id = ?";
    Detalle detalle = null;
    try (Connection conn = connectionHolder.getConnection()) {
      try (PreparedStatement ps = conn.prepareStatement(query)){
        ps.setInt(1, id);
        try(ResultSet rs = ps.executeQuery()){
          while(rs.next()){
            //Confio en que la base de datos mapeo correctamente el estado_resultado_id
            @SuppressWarnings("OptionalGetWithoutIsPresent")
            EstadoResultado estadoResultado= DAOManager.getEstadoResultadoDAO().getById(rs.getInt("estado_resultado_id")).get();
            //Confio en que la base de datos mapeo correctamente el tipo_detalle_id
            @SuppressWarnings("OptionalGetWithoutIsPresent")
            TipoDetalle tipoDetalle = DAOManager.getTipoDetalleDAO().getById(rs.getInt("tipo_detalle_id")).get();

            detalle = new Detalle();
            detalle.setId(id);
            detalle.setDescripcion(rs.getString("descripcion"));
            detalle.setValor(rs.getInt("valor"));
            detalle.setEstadoResultado(estadoResultado);
            detalle.setTipoDetalle(tipoDetalle);
          }
        }
      }
    }catch (SQLException e) {
      log.error("Error al intentar conseguir el detalle con id " + id, e);
    }
    log.debug("Se consiguieron el detalle " + detalle);
    return Optional.ofNullable(detalle);
  }

  @Override
  public Optional<Detalle> getByEstadoResultado(EstadoResultado estadoResultado) {
    log.debug("Se intentaran conseguir el detalle del estado resultado " + estadoResultado);

    if(estadoResultado == estadoResultado.EMPTY){
      log.debug("El estado resultado entregado era empty");
      return  Optional.empty();
    }

    String query = "select * from detalles where id = ?";
    Detalle detalle = null;
    try (Connection conn = connectionHolder.getConnection()) {
      try (PreparedStatement ps = conn.prepareStatement(query)){
        ps.setInt(1, estadoResultado.getId());
        try(ResultSet rs = ps.executeQuery()){
          while(rs.next()){
            //Confio en que la base de datos mapeo correctamente el tipo_detalle_id
            @SuppressWarnings("OptionalGetWithoutIsPresent")
            TipoDetalle tipoDetalle = DAOManager.getTipoDetalleDAO().getById(rs.getInt("tipo_detalle_id")).get();

            detalle = new Detalle();
            detalle.setId(rs.getInt("id"));
            detalle.setDescripcion(rs.getString("descripcion"));
            detalle.setValor(rs.getInt("valor"));
            detalle.setEstadoResultado(estadoResultado);
            detalle.setTipoDetalle(tipoDetalle);
          }
        }
      }
    }catch (SQLException e) {
      log.error("Error al intentar conseguir el detalle del estado resultado " + estadoResultado, e);
    }
    log.debug("Se consiguieron el detalle " + detalle);
    return Optional.ofNullable(detalle);
  }

  @Override
  public void insert(Detalle detalle) {
    log.debug("Se intentara insertar un nuevo detalle" + detalle);
    String query = "insert into detalles (valor, descripcion, tipo_detalle_id, estado_resultado_id) values (?, ?, ?, ?)";
    try (Connection conn = connectionHolder.getConnection()) {
      try (PreparedStatement ps = conn.prepareStatement(query)) {
        ps.setInt(1, detalle.getValor());
        ps.setString(2, detalle.getDescripcion());
        ps.setInt(3, detalle.getTipoDetalle().getId());
        ps.setInt(4, detalle.getEstadoResultado().getId());
        ps.executeUpdate();
      }

      try (PreparedStatement ps = conn.prepareStatement("select last_insert_rowid()")) {
        try (ResultSet rs = ps.executeQuery()) {
          rs.next();
          detalle.setId(rs.getInt(1));
        }
      }

    } catch (SQLException e) {
      log.error("Error al intentar insertar el detalle " + detalle);
    }
    log.debug("Se inserto el detalle " + detalle);
  }

  @Override
  public void update(Detalle detalle) {
    log.debug("Se intentara actualizar el detalle" + detalle);
    String query = "update detalles set valor = ?, descripcion = ?, tipo_detalle_id = ?, estado_resultado_id = ? where id = ?";
    try (Connection conn = connectionHolder.getConnection()) {
      try (PreparedStatement ps = conn.prepareStatement(query)) {
        ps.setInt(1, detalle.getValor());
        ps.setString(2, detalle.getDescripcion());
        ps.setInt(3, detalle.getTipoDetalle().getId());
        ps.setInt(4, detalle.getEstadoResultado().getId());
        ps.setInt(4, detalle.getId());
        ps.executeUpdate();
      }
    } catch (SQLException e) {
      log.error("Error al actualizar el detalle " + detalle, e);
    }
    log.debug("Se actualizo el detalle " + detalle);
  }

  @Override
  public void delete(Detalle detalle) {
    log.debug("Se intentara eliminar el detalle " + detalle);
    String query = "delete from detalles where id = ?";
    try (Connection conn = connectionHolder.getConnection()) {
      try (PreparedStatement ps = conn.prepareStatement(query)) {
        ps.setInt(1, detalle.getId());
        ps.execute();
      }
    } catch (SQLException e) {
      log.error("Error al eliminar el detalle" + detalle, e);
    }
    log.debug("Se elimino el detalle " + detalle);
  }
}
