package danielcortes.xyz.models.detalle;

import static org.assertj.core.api.Assertions.assertThat;

import com.github.javafaker.Faker;
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.estado_resultado.EstadoResultadoDAO;
import danielcortes.xyz.models.tipo_detalle.TipoDetalle;
import danielcortes.xyz.models.tipo_detalle.TipoDetalleDAO;
import danielcortes.xyz.models.version.SQLiteVersionDAO;
import danielcortes.xyz.models.version.VersionDAO;
import danielcortes.xyz.utils.RandomLocalDate;
import java.io.File;
import java.time.YearMonth;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

class SQLiteDetalleDAOTest {
  private static final int databaseVersion = 3;

  private static Faker faker;
  private static VersionDAO versionDAO;
  private DetalleDAO detalleDAO;
  private EstadoResultadoDAO estadoResultadoDAO;
  private TipoDetalleDAO tipoDetalleDAO;


  @BeforeAll
  static void setAll() {
    ConnectionHolder connectionHolder = new SQLiteConnectionHolder("jdbc:sqlite:/tmp/tmp.sqlite");
    DAOManager.setup(connectionHolder);
    versionDAO = new SQLiteVersionDAO(connectionHolder);
    faker = new Faker();
  }

  @BeforeEach
  void setUp() {
    versionDAO.updateTo(databaseVersion);
    this.tipoDetalleDAO = DAOManager.getTipoDetalleDAO();
    this.estadoResultadoDAO = DAOManager.getEstadoResultadoDAO();
    this.detalleDAO = DAOManager.getDetalleDAO();
  }

  @AfterEach
  void tearDown() {
    //noinspection ResultOfMethodCallIgnored
    new File("/tmp/tmp.sqlite").delete();
  }

  @ParameterizedTest
  @ValueSource(ints={1, 5, 10})
  void getAll(int size) {
    //La base de datos al crearse genera un tipoDetalle con id 1 entre otros
    @SuppressWarnings("OptionalGetWithoutIsPresent")
    TipoDetalle tipoDetalle = this.tipoDetalleDAO.getById(1).get();

    List<EstadoResultado> e = new ArrayList<>(size);
    for(int i = 0; i < size; i++){
      EstadoResultado estadoResultado = giveEstadoResultado();

      this.estadoResultadoDAO.insert(estadoResultado);
      e.add(estadoResultado);
    }

    List<Detalle> d1 = new ArrayList<>(size);
    for(EstadoResultado estadoResultado: e){
      Detalle detalle = giveDetalle(tipoDetalle, estadoResultado);
      this.detalleDAO.insert(detalle);
      d1.add(detalle);
    }

    List<Detalle> d2 = this.detalleDAO.getAll();
    assertThat(d2)
        .hasSize(size)
        .containsAll(d1);
  }

  @Test
  void getByTipoDetalle() {
  }

  @Test
  void getById() {
  }

  @Test
  void getByEstadoResultado() {
  }

  @Test
  void insert() {
  }

  @Test
  void update() {
  }

  @Test
  void delete() {
  }

  Detalle giveDetalle(TipoDetalle tipoDetalle, EstadoResultado estadoResultado) {
    Detalle detalle = new Detalle();
    detalle.setValor(faker.number().numberBetween(0, 10000000));
    detalle.setDescripcion(faker.lorem().sentence());
    detalle.setTipoDetalle(tipoDetalle);
    detalle.setEstadoResultado(estadoResultado);

    return detalle;
  }

  EstadoResultado giveEstadoResultado() {
    EstadoResultado estadoResultado = new EstadoResultado();
    estadoResultado.setMes(YearMonth.from(RandomLocalDate.random()));
    estadoResultado.setCostoVenta(faker.number().numberBetween(0, 10000000));
    estadoResultado.setCuentaCorrienteFactura(faker.number().numberBetween(0, 10000000));
    estadoResultado.setCuentaCorrienteBoleta(faker.number().numberBetween(0, 10000000));
    estadoResultado.setCuentaCorrienteSinRespaldo(faker.number().numberBetween(0, 10000000));
    estadoResultado.setRemuneraciones(faker.number().numberBetween(0, 10000000));
    estadoResultado.setFiniquitos(faker.number().numberBetween(0, 10000000));
    estadoResultado.setAguinaldo(faker.number().numberBetween(0, 10000000) );
    estadoResultado.setBonosPersonal(faker.number().numberBetween(0, 10000000));
    estadoResultado.setHonorariosContador(faker.number().numberBetween(0, 10000000));
    estadoResultado.setArriendo(faker.number().numberBetween(0, 10000000));
    estadoResultado.setAgua(faker.number().numberBetween(0, 10000000));
    estadoResultado.setLuz(faker.number().numberBetween(0, 10000000));
    estadoResultado.setGas(faker.number().numberBetween(0, 10000000));
    estadoResultado.setTelefono(faker.number().numberBetween(0, 10000000));
    estadoResultado.setOtroServicio(faker.number().numberBetween(0, 10000000));
    estadoResultado.setPpm(faker.number().randomDouble(2,0,100));
    estadoResultado.setIvaFavor(faker.number().numberBetween(0, 10000000));
    return estadoResultado;
  }
}
