<?php
namespace nur\sery\ext\spreadsheet;

use nur\sery\cl;
use nur\sery\file\csv\AbstractReader;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\RichText\RichText;

class PhpSpreadsheetReader extends AbstractReader {
  const DATETIME_FORMAT = 'dd/mm/yyyy hh:mm:ss';
  const DATE_FORMAT = 'dd/mm/yyyy';
  const TIME_FORMAT = 'hh:mm:ss';
  const FORMAT_MAPPINGS = [
    'mm/dd hh' => self::DATETIME_FORMAT,
    'dd/mm hh' => self::DATETIME_FORMAT,
    'mm/dd hh:mm' => self::DATETIME_FORMAT,
    'dd/mm hh:mm' => self::DATETIME_FORMAT,
    'mm/dd hh:mm:ss' => self::DATETIME_FORMAT,
    'dd/mm hh:mm:ss' => self::DATETIME_FORMAT,
    'mm/dd/yyyy hh' => self::DATETIME_FORMAT,
    'dd/mm/yyyy hh' => self::DATETIME_FORMAT,
    'mm/dd/yyyy hh:mm' => self::DATETIME_FORMAT,
    'dd/mm/yyyy hh:mm' => self::DATETIME_FORMAT,
    'mm/dd/yyyy hh:mm:ss' => self::DATETIME_FORMAT,
    'dd/mm/yyyy hh:mm:ss' => self::DATETIME_FORMAT,
    'yyyy/mm/dd hh' => self::DATETIME_FORMAT,
    'yyyy/mm/dd hh:mm' => self::DATETIME_FORMAT,
    'yyyy/mm/dd hh:mm:ss' => self::DATETIME_FORMAT,

    'mm/dd' => self::DATE_FORMAT,
    'dd/mm' => self::DATE_FORMAT,
    'mm/dd/yyyy' => self::DATE_FORMAT,
    'dd/mm/yyyy' => self::DATE_FORMAT,
    'yyyy/mm/dd' => self::DATE_FORMAT,
    'mm/yyyy' => self::DATE_FORMAT,

    'hh AM/PM' => self::TIME_FORMAT,
    'hh:mm AM/PM' => self::TIME_FORMAT,
    'hh:mm:ss AM/PM' => self::TIME_FORMAT,
    'hh' => self::TIME_FORMAT,
    'hh:mm' => self::TIME_FORMAT,
    'hh:mm:ss' => self::TIME_FORMAT,
    '[hh]:mm:ss' => self::TIME_FORMAT,
    'mm:ss' => self::TIME_FORMAT,
  ];

  /** @var string|int|null nom de la feuille depuis laquelle lire */
  const WSNAME = null;

  function __construct($input, ?array $params=null) {
    parent::__construct($input, $params);
    $this->wsname = $params["wsname"] ?? static::WSNAME;
  }

  protected $wsname;

  /**
   * @param string|int|null $wsname
   */
  function setWsname($wsname): self {
    $this->wsname = $wsname;
    return $this;
  }

  function getIterator() {
    $ss = IOFactory::load($this->input);
    $ws = wsutils::get_ws($this->wsname, $ss);

    [$nbCols, $nbRows] = wsutils::compute_max_coords($ws);
    $this->isrc = $this->idest = 0;
    for ($nrow = 1; $nrow <= $nbRows; $nrow++) {
      $row = [];
      for ($ncol = 1; $ncol <= $nbCols; $ncol++) {
        if ($ws->cellExistsByColumnAndRow($ncol, $nrow)) {
          $cell = $ws->getCellByColumnAndRow($ncol, $nrow);
          $col = $cell->getValue();
          if ($col instanceof RichText) {
            $col = $col->getPlainText();
          } else {
            $dataType = $cell->getDataType();
            if ($dataType == DataType::TYPE_NUMERIC || $dataType == DataType::TYPE_FORMULA) {
              # si c'est un format date, le forcer à une valeur standard
              $origFormatCode = $cell->getStyle()->getNumberFormat()->getFormatCode();
              if (strpbrk($origFormatCode, "ymdhs") !== false) {
                $formatCode = $origFormatCode;
                $formatCode = preg_replace('/y+/', "yyyy", $formatCode);
                $formatCode = preg_replace('/m+/', "mm", $formatCode);
                $formatCode = preg_replace('/d+/', "dd", $formatCode);
                $formatCode = preg_replace('/h+/', "hh", $formatCode);
                $formatCode = preg_replace('/s+/', "ss", $formatCode);
                $formatCode = preg_replace('/-+/', "/", $formatCode);
                $formatCode = preg_replace('/\\\\ /', " ", $formatCode);
                $formatCode = preg_replace('/;@$/', "", $formatCode);
                $formatCode = cl::get(self::FORMAT_MAPPINGS, $formatCode, $formatCode);
                if ($formatCode !== $origFormatCode) {
                  $cell->getStyle()->getNumberFormat()->setFormatCode($formatCode);
                }
              }
            }
            $col = $cell->getFormattedValue();
            $this->verifixCol($col);
          }
        } else {
          $col = null;
        }
        $row[] = $col;
      }
      if ($this->cookRow($row)) {
        yield $row;
        $this->idest++;
      }
      $this->isrc++;
    }
  }
}
