/*
 * MIT License
 *
 * Copyright (c) 2018-2019 Daniel Cortes
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package danielcortes.xyz.models.calculo_fondo;

import danielcortes.xyz.data.ConnectionHolder;
import danielcortes.xyz.data.DAOManager;
import danielcortes.xyz.data.SQLiteConnectionHolder;
import danielcortes.xyz.models.caja.Caja;
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 SQLiteCalculoFondoDAO implements CalculoFondoDAO {
  private static final Logger log = LogManager.getLogger(SQLiteCalculoFondoDAO.class);
  private ConnectionHolder connectionHolder;

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

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

  @Override
  public List<CalculoFondo> getAll() {
    log.debug("Se intentara conseguir todos los CalculosFondo");
    List<CalculoFondo> calculoFondoList = new ArrayList<>();
    String query = "select * from calculo_fondo";
    try (Connection conn = connectionHolder.getConnection()) {
      try (PreparedStatement ps = conn.prepareStatement(query)) {
        try (ResultSet rs = ps.executeQuery()) {
          while (rs.next()) {
            //Es seguro que exista una caja con ese id, lo dice la base de datos.
            @SuppressWarnings("OptionalGetWithoutIsPresent")
            Caja caja = DAOManager.getCajaDAO().getById(rs.getInt("caja_id")).get();
            CalculoFondo calculoFondo = new CalculoFondo();

            calculoFondo.setId(rs.getInt("id"));
            calculoFondo.setValor(rs.getInt("valor"));
            calculoFondo.setDescripcion(rs.getString("descripcion"));
            calculoFondo.setCaja(caja);
            calculoFondoList.add(calculoFondo);
          }
        }
      }
    } catch (SQLException e) {
      log.error("Error al intentar conseguir todos los CalculoFondo", e);
    }
    log.debug("Se encontraron " + calculoFondoList.size() + " CalculosFondo");
    return calculoFondoList;
  }

  @Override
  public List<CalculoFondo> getByCaja(Caja caja) {
    log.debug("Se intentara conseguir todos los calculos fondo de la caja " + caja);
    List<CalculoFondo> calculoFondoList = new ArrayList<>();
    if (Caja.EMPTY == caja) {
      return calculoFondoList;
    }

    String query = "select * from calculo_fondo where caja_id = ?";
    try (Connection conn = connectionHolder.getConnection()) {
      try (PreparedStatement ps = conn.prepareStatement(query)) {
        ps.setInt(1, caja.getId());
        try (ResultSet rs = ps.executeQuery()) {
          while (rs.next()) {
            CalculoFondo calculoFondo = new CalculoFondo();

            calculoFondo.setId(rs.getInt("id"));
            calculoFondo.setValor(rs.getInt("valor"));
            calculoFondo.setDescripcion(rs.getString("descripcion"));
            calculoFondo.setCaja(caja);

            calculoFondoList.add(calculoFondo);
          }
        }
      }
    } catch (SQLException e) {
      log.error("Error al intentar conseguir los CalculoFondo de la caja " + caja, e);
    }
    log.debug("Se consiguieron " + calculoFondoList.size() + "CalculoFondo pertencientes a la caja " + caja);
    return calculoFondoList;
  }

  @Override
  public Optional<CalculoFondo> getById(int id) {
    log.debug("Se intentara conseguir un CalculoFondo con id " + id);
    CalculoFondo calculoFondo = null;
    String query = "select * from calculo_fondo where id = ?";
    try (Connection conn = connectionHolder.getConnection()) {
      try (PreparedStatement ps = conn.prepareStatement(query)) {
        ps.setInt(1, id);
        try (ResultSet rs = ps.executeQuery()) {
          if (rs.next()) {
            //Es seguro que exista una caja con ese id, confio en la base de datos.
            @SuppressWarnings("OptionalGetWithoutIsPresent")
            Caja caja = DAOManager.getCajaDAO().getById(rs.getInt("caja_id")).get();
            calculoFondo = new CalculoFondo();
            calculoFondo.setId(rs.getInt("id"));
            calculoFondo.setValor(rs.getInt("valor"));
            calculoFondo.setDescripcion(rs.getString("descripcion"));
            calculoFondo.setCaja(caja);
          }
        }
      }
    } catch (SQLException e) {
      log.error("Error al intentar conseguir un CalculoFondo por su id " + id, e);
    }
    log.debug("El calculoFondo que se consiguio es " + calculoFondo);
    return Optional.ofNullable(calculoFondo);
  }

  @Override
  public int getTotalCalculoFondo(Caja caja) {
    log.debug("Se intentara conseguir la suma de los valores de los CalculosFondo de la caja " + caja);
    int sum = 0;

    if (Caja.EMPTY == caja) {
      log.debug("La caja que se entrego era Caja.EMPTY");
      return sum;
    }

    String query = "select sum(valor) from calculo_fondo where caja_id = ?";
    try (Connection conn = connectionHolder.getConnection()) {
      try (PreparedStatement ps = conn.prepareStatement(query)) {
        ps.setInt(1, caja.getId());
        try (ResultSet rs = ps.executeQuery()) {
          if (rs.next()) {
            sum = rs.getInt(1);
          }
        }
      }
    } catch (SQLException e) {
      log.error("Error al intentar conseguir el total de calculo fondo de la caja " + caja, e);
    }

    log.debug("La suma conseguida de los CalculoFondo de la caja " + caja + " es " + sum);
    return sum;
  }

  @Override
  public void insert(CalculoFondo calculoFondo) {
    log.debug("Se intentara insertar el calculoFondo " + calculoFondo);

    if(calculoFondo.getCaja() == Caja.EMPTY){
      log.error("El calculo fondo tiene una caja EMPTY, no se insertara");
      return;
    }

    String query = "insert into calculo_fondo (valor, descripcion, caja_id) values (?, ?, ?)";
    try (Connection conn = connectionHolder.getConnection()) {
      try (PreparedStatement ps = conn.prepareStatement(query)) {
        ps.setInt(1, calculoFondo.getValor());
        ps.setString(2, calculoFondo.getDescripcion());
        ps.setInt(3, calculoFondo.getCaja().getId());
        ps.executeUpdate();
      }

      try (PreparedStatement ps = conn.prepareStatement("select last_insert_rowid()")) {
        try (ResultSet rs = ps.executeQuery()) {
          rs.next();
          calculoFondo.setId(rs.getInt(1));
        }
      }
    } catch (SQLException e) {
      log.error("Error al intentar insertar el CalculoFondo " + calculoFondo, e);
    }

    log.debug("Se inserto el calculoFondo " + calculoFondo);
  }

  @Override
  public void update(CalculoFondo calculoFondo) {
    log.debug("Se intentara actualizar el CalculoFondo " + calculoFondo);

    if (calculoFondo.getCaja() == Caja.EMPTY) {
      log.error("El calculo fondo tiene una caja EMPTY, no se actualizara");
      return;
    }

    String query = "update calculo_fondo set valor = ?, descripcion = ?, caja_id = ?  where id = ?";
    try (Connection conn = connectionHolder.getConnection()) {
      try (PreparedStatement ps = conn.prepareStatement(query)) {
        ps.setInt(1, calculoFondo.getValor());
        ps.setString(2, calculoFondo.getDescripcion());
        ps.setInt(3, calculoFondo.getCaja().getId());
        ps.setInt(4, calculoFondo.getId());

        ps.executeUpdate();
      }
    } catch (SQLException e) {
      log.error("Error al intentar actualizar el CalculoFondo " + calculoFondo, e);
    }
    log.debug("Se actualizo el CalculoFondo " + calculoFondo);
  }

  @Override
  public void delete(CalculoFondo calculoFondo) {
    log.debug("Se intentara eliminar el CalculoFondo" + calculoFondo);
    String query = "delete from calculo_fondo where id = ?";
    try (Connection conn = connectionHolder.getConnection()) {
      try (PreparedStatement ps = conn.prepareStatement(query)) {
        ps.setInt(1, calculoFondo.getId());
        ps.executeUpdate();
      }
    } catch (SQLException e) {
      log.error("Error al intentar eliminar el CalculoFondo " + calculoFondo, e);
    }
    log.debug("El CalculoFondo " + calculoFondo + " fue eliminado de la base de datos");
  }
}
