package danielcortes.xyz.informes;

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.BorderExtent;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CreationHelper;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.PropertyTemplate;

public class InformeResumenArqueoToExcel {

  private final String[] dias = {
      "LUNES", "MARTES", "MIERCOLES", "JUEVES", "VIERNES", "SABADO", "DOMINGO"
  };
  private InformeResumenArqueo informe;

  private Row titles;
  private ArrayList<Row> dataRow;
  private Row totalesRow;

  private Workbook wb;
  private Sheet sheet;
  private CreationHelper createHelper;
  private HashMap<String, CellStyle> styles;

  public InformeResumenArqueoToExcel(InformeResumenArqueo informe) {
    this.informe = informe;
    this.wb = new HSSFWorkbook();
    this.sheet = wb.createSheet();
    this.createHelper = wb.getCreationHelper();

    this.dataRow = new ArrayList<>();

    this.styles = this.generateStyles();
  }

  private void fillHeaders() {
    this.titles = sheet.createRow(0);
    int currentCell = 0;
    this.titles.createCell(currentCell++).setCellValue("Dia");
    this.titles.createCell(currentCell++).setCellValue("Fecha");
    this.titles.createCell(currentCell++).setCellValue("Efectivo");
    this.titles.createCell(currentCell++).setCellValue("Cheques");
    this.titles.createCell(currentCell++).setCellValue("T Credito");
    this.titles.createCell(currentCell++).setCellValue("Retiros");
    this.titles.createCell(currentCell++).setCellValue("Egresos");
    this.titles.createCell(currentCell++).setCellValue("Rendido");
    this.titles.createCell(currentCell++).setCellValue("Debe Rendir");
    this.titles.createCell(currentCell).setCellValue("Diferencia");
  }

  private void fillData() {
    int currentRow = 1;

    LocalDate currentDay = this.informe.getMes().atDay(1);
    LocalDate endDayPlusOne = this.informe.getMes().atEndOfMonth().plusDays(1);

    while (currentDay.isBefore(endDayPlusOne)) {
      int currentCell = 0;

      Row row = sheet.createRow(currentRow++);
      ResumenArqueo informe = this.informe.get(currentDay);

      row.createCell(currentCell++).setCellValue(this.dias[currentDay.getDayOfWeek().getValue()-1]);
      Date fecha = Date.from(currentDay.atStartOfDay(ZoneId.systemDefault()).toInstant());
      row.createCell(currentCell++).setCellValue(fecha);
      row.createCell(currentCell++).setCellValue(informe.getEfectivo());
      row.createCell(currentCell++).setCellValue(informe.getCheques());
      row.createCell(currentCell++).setCellValue(informe.getTarjetaCredito());
      row.createCell(currentCell++).setCellValue(informe.getRetiros());
      row.createCell(currentCell++).setCellValue(informe.getEgresos());
      row.createCell(currentCell++).setCellFormula("SUM(C" + currentRow + ":G" + currentRow + ")");
      row.createCell(currentCell++).setCellValue(informe.getDebeRendir());
      row.createCell(currentCell++).setCellFormula("H" + currentRow + "-I" + currentRow);

      dataRow.add(row);
      currentDay = currentDay.plusDays(1);
    }
  }

  private void fillTotal() {
    int lastRow = dataRow.size() + 1;
    int currentRow = dataRow.size() + 1;
    int currentCell = 0;
    totalesRow = sheet.createRow(currentRow);

    totalesRow.createCell(currentCell++).setCellValue("Totales");
    totalesRow.createCell(currentCell++);
    totalesRow.createCell(currentCell++).setCellFormula("SUM(C2:C" + lastRow + ")");
    totalesRow.createCell(currentCell++).setCellFormula("SUM(D2:D" + lastRow + ")");
    totalesRow.createCell(currentCell++).setCellFormula("SUM(E2:E" + lastRow + ")");
    totalesRow.createCell(currentCell++).setCellFormula("SUM(F2:F" + lastRow + ")");
    totalesRow.createCell(currentCell++).setCellFormula("SUM(G2:G" + lastRow + ")");
    totalesRow.createCell(currentCell++).setCellFormula("SUM(H2:H" + lastRow + ")");
    totalesRow.createCell(currentCell++).setCellFormula("SUM(I2:I" + lastRow + ")");
    totalesRow.createCell(currentCell++).setCellFormula("SUM(J2:J" + lastRow + ")");
  }

  private void setStyles() {
    this.titles.cellIterator().forEachRemaining(
        (cell) -> cell.setCellStyle(this.styles.get("header"))
    );

    this.totalesRow.cellIterator().forEachRemaining(
        (cell) -> cell.setCellStyle(this.styles.get("total"))
    );

    for(Row row: this.dataRow){
      int currentCell = 0;
      row.getCell(currentCell++).setCellStyle(this.styles.get("not_so_gray"));
      row.getCell(currentCell++).setCellStyle(this.styles.get("date"));
      row.getCell(currentCell++).setCellStyle(this.styles.get("money"));
      row.getCell(currentCell++).setCellStyle(this.styles.get("money"));
      row.getCell(currentCell++).setCellStyle(this.styles.get("money"));
      row.getCell(currentCell++).setCellStyle(this.styles.get("money"));
      row.getCell(currentCell++).setCellStyle(this.styles.get("money"));
      row.getCell(currentCell++).setCellStyle(this.styles.get("money"));
      row.getCell(currentCell++).setCellStyle(this.styles.get("money"));
      row.getCell(currentCell++).setCellStyle(this.styles.get("money"));
    }

    for(int x = 0; x < 10; x++){
      this.sheet.autoSizeColumn(x);
    }

    for(int x = 0; x < dataRow.size() + 2; x++) {
      this.sheet.getRow(x).setHeightInPoints(15);
    }
  }

  private void addBorders() {
    int size = dataRow.size() + 2;
    PropertyTemplate pt = new PropertyTemplate();
    pt.drawBorders(new CellRangeAddress(0, size - 1, 0, 9), BorderStyle.THIN, BorderExtent.ALL);
    pt.applyBorders(this.sheet);
  }

  private void freezeCells() {
    this.sheet.createFreezePane(2, 1);
  }

  public Workbook generarInforme() {
    fillHeaders();
    fillData();
    fillTotal();
    setStyles();
    addBorders();
    freezeCells();

    return this.wb;
  }

  public HashMap<String, CellStyle> generateStyles() {
    Font font = this.wb.createFont();
    font.setBold(true);
    font.setColor(IndexedColors.WHITE.getIndex());

    CellStyle regularStyle = this.wb.createCellStyle();

    CellStyle grayStyle = this.wb.createCellStyle();
    grayStyle.setFont(font);
    grayStyle.setVerticalAlignment(VerticalAlignment.CENTER);
    grayStyle.setFillForegroundColor(IndexedColors.GREY_80_PERCENT.getIndex());
    grayStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

    CellStyle notSoGrayStyle = this.wb.createCellStyle();
    notSoGrayStyle.setFont(font);
    notSoGrayStyle.setVerticalAlignment(VerticalAlignment.CENTER);
    notSoGrayStyle.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
    notSoGrayStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

    CellStyle dateStyle = this.wb.createCellStyle();
    dateStyle.cloneStyleFrom(notSoGrayStyle);
    dateStyle.setDataFormat(this.createHelper.createDataFormat().getFormat("dd/mm/yyyy"));

    CellStyle moneyStyle = this.wb.createCellStyle();
    moneyStyle
        .setDataFormat(
            this.createHelper.createDataFormat().getFormat("[$$-340A]#,##0;[RED][$$-340A] -#,##0"));

    CellStyle headerStyle = this.wb.createCellStyle();
    headerStyle.cloneStyleFrom(notSoGrayStyle);
    headerStyle.setAlignment(HorizontalAlignment.CENTER);

    CellStyle totalStyle = this.wb.createCellStyle();
    totalStyle.cloneStyleFrom(notSoGrayStyle);
    totalStyle
        .setDataFormat(
            this.createHelper.createDataFormat().getFormat("[$$-340A]#,##0;[RED][$$-340A] -#,##0"));

    CellStyle totalFinalStyle = this.wb.createCellStyle();
    totalFinalStyle.cloneStyleFrom(notSoGrayStyle);
    totalFinalStyle
        .setDataFormat(
            this.createHelper.createDataFormat().getFormat("[$$-340A]#,##0;[RED][$$-340A] -#,##0"));

    HashMap<String, CellStyle> styles = new HashMap<>();
    styles.put("regular", regularStyle);
    styles.put("gray", grayStyle);
    styles.put("not_so_gray", notSoGrayStyle);
    styles.put("date", dateStyle);
    styles.put("money", moneyStyle);
    styles.put("header", headerStyle);
    styles.put("total", totalStyle);
    styles.put("total_final", totalFinalStyle);

    return styles;
  }

}
