package ru.micord.ervu_dashboard.service;

import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import ru.micord.ervu_dashboard.dao.AppealsDao;
import ru.micord.ervu_dashboard.exception.FileUploadException;
import ru.micord.ervu_dashboard.exception.MissingHeaderException;

/**
 * @author Adel Kalimullin
 */
@Service
public class AppealsFileUploadService {
  private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("dd.MM.yyyy");
  private final AppealsDao appealsDao;
  private final List<String> requiredHeaders;

  public AppealsFileUploadService(AppealsDao appealsDao,
      @Value("${ervu.file.upload.xlsx.required.headers}") String rawHeaders) {
    this.appealsDao = appealsDao;
    this.requiredHeaders = getRequiredHeaders(rawHeaders);
  }

  public void save(MultipartFile file) {
    List<Map<String, String>> maps = parseFile(file);
    appealsDao.save(maps);
  }

  private List<Map<String, String>> parseFile(MultipartFile file) {
    List<Map<String, String>> records = new ArrayList<>();
    try (InputStream inputStream = file.getInputStream();
         Workbook workbook = WorkbookFactory.create(inputStream)) {

      Sheet sheet = workbook.getSheetAt(0);
      Iterator<Row> rowIterator = sheet.iterator();

      List<String> headers = new ArrayList<>();
      if (rowIterator.hasNext()) {
        Row headerRow = rowIterator.next();
        for (Cell cell : headerRow) {
          headers.add(cell.getStringCellValue());
        }
        validateHeaders(headers);
      }
      while (rowIterator.hasNext()) {
        Row row = rowIterator.next();
        Map<String, String> rowData = new HashMap<>();

        for (int i = 0; i < headers.size(); i++) {
          Cell cell = row.getCell(i, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
          rowData.put(headers.get(i), getCellValue(cell));
        }
        records.add(rowData);
      }
    }
    catch (Exception e) {
      throw new FileUploadException("Error parsing the file", e);
    }
    return records;
  }

  private void validateHeaders(List<String> headers) {
    for (String requiredHeader : requiredHeaders) {
      if (!headers.contains(requiredHeader)) {
        throw new MissingHeaderException("Required header is missing:" + requiredHeader);
      }
    }
  }

  private String getCellValue(Cell cell) {
    switch (cell.getCellType()) {
      case STRING:
        return cell.getStringCellValue();
      case NUMERIC:
        if (DateUtil.isCellDateFormatted(cell)) {
          LocalDateTime dateTime = cell.getLocalDateTimeCellValue();
          return dateTime.format(DATE_TIME_FORMATTER);
        }
        else {
          return String.valueOf((int) cell.getNumericCellValue());
        }
      case BOOLEAN:
        return String.valueOf(cell.getBooleanCellValue());
      case BLANK:
        return "";
      default:
        return cell.toString();
    }
  }

  private List<String> getRequiredHeaders(String rawHeaders) {
    return Arrays.stream(rawHeaders.split(";"))
        .map(String::trim)
        .toList();
  }
}
