package danielcortes.xyz.models.caja;

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.version.SQLiteVersionDAO;
import danielcortes.xyz.utils.RandomLocalDate;
import java.io.File;
import java.util.List;
import java.util.Optional;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

class SQLiteCajaDAOTest {

  static private int databaseVersion = 2;
  static private SQLiteVersionDAO versionDAO;
  static private ConnectionHolder connectionHolder;
  static private Faker faker;
  private SQLiteCajaDAO cajaDAO;

  @BeforeAll
  static void setAll() {
    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.cajaDAO = new SQLiteCajaDAO(connectionHolder);
  }

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

  @Test
  void getAll() {
    Caja c1 = giveRandomCaja();
    Caja c2 = giveRandomCaja();

    this.cajaDAO.insert(c1);
    this.cajaDAO.insert(c2);

    List<Caja> list = this.cajaDAO.getAll();

    assertThat(list)
        .hasSize(2)
        .containsExactlyInAnyOrder(c1, c2);
  }

  @Test
  void getById() {
    Caja c1 = giveRandomCaja();
    Caja c2 = giveRandomCaja();

    this.cajaDAO.insert(c1);
    this.cajaDAO.insert(c2);

    Optional<Caja> o1 = this.cajaDAO.getById(c1.getId());
    Optional<Caja> o2 = this.cajaDAO.getById(c2.getId());

    assertThat(o1)
        .isPresent()
        .contains(c1);

    assertThat(o2)
        .isPresent()
        .contains(c2);
  }

  @Test
  void getByFecha() {
    Caja c1 = giveRandomCaja();
    Caja c2 = giveRandomCaja();

    this.cajaDAO.insert(c1);
    this.cajaDAO.insert(c2);

    Optional<Caja> o1 = this.cajaDAO.getByFecha(c1.getFecha());
    Optional<Caja> o2 = this.cajaDAO.getByFecha(c2.getFecha());

    assertThat(o1)
        .isPresent()
        .contains(c1);

    assertThat(o2)
        .isPresent()
        .contains(c2);
  }

  @Test
  void insert() {
    Caja c1 = giveRandomCaja();
    Caja c2 = giveRandomCaja();

    assertThat(0)
        .isEqualTo(c1.getId())
        .isEqualTo(c2.getId());

    this.cajaDAO.insert(c1);
    this.cajaDAO.insert(c2);

    assertThat(0)
        .isNotEqualTo(c1.getId())
        .isNotEqualTo(c2.getId());

    List<Caja> l = this.cajaDAO.getAll();
    assertThat(l)
        .hasSize(2)
        .containsExactlyInAnyOrder(c1, c2);
  }

  @Test
  void update() {
    Caja c1 = giveRandomCaja();
    Caja c2 = giveRandomCaja();

    this.cajaDAO.insert(c1);
    this.cajaDAO.insert(c2);

    Caja u1 = giveRandomCaja(c1.getId());
    Caja u2 = giveRandomCaja(c2.getId());

    this.cajaDAO.update(c1);
    this.cajaDAO.update(c2);

    List<Caja> l = this.cajaDAO.getAll();

    assertThat(l)
        .hasSize(2)
        .containsExactlyInAnyOrder(c1, c2);
  }

  @Test
  void shouldNotInsertCajaEMPTY(){
    this.cajaDAO.insert(Caja.EMPTY);
    List<Caja> l = this.cajaDAO.getAll();

    assertThat(l).hasSize(0);
  }

  Caja giveRandomCaja() {
    Caja caja = new Caja();
    caja.setFondo(faker.number().numberBetween(0, 10000000));
    caja.setFecha(RandomLocalDate.random());
    return caja;
  }

  Caja giveRandomCaja(int id) {
    Caja caja = new Caja();
    caja.setId(id);
    caja.setFondo(faker.number().numberBetween(0, 10000000));
    caja.setFecha(RandomLocalDate.random());
    return caja;
  }
}