<?php
/**
 * Copyright (C) 2023  Jaap Jansma (jaap.jansma@civicoop.org)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

namespace Civi\DataProcessor\FilterHandler;

use Civi\DataProcessor\Exception\FilterRequiredException;
use CRM_Core_Exception;
use CRM_Core_Form;
use CRM_Dataprocessor_ExtensionUtil as E;
use CRM_Dataprocessor_Utils_Date;
use CRM_Dataprocessor_Utils_Form;

abstract class AbstractFieldInPeriodFilter extends AbstractFieldFilterHandler {

  /**
   * Add the elements to the filter form.
   *
   * @param \CRM_Core_Form $form
   * @param array $defaultFilterValue
   * @param string $size
   *   Possible values: full or compact
   * @return array
   *   Return variables belonging to this filter.
   */
  public function addToFilterForm(CRM_Core_Form $form, $defaultFilterValue, $size='full'): array {
    $fieldSpec = $this->getFieldSpecification();
    $operations = $this->getOperatorOptions($fieldSpec);
    $defaults = array();

    $title = $fieldSpec->title;
    $alias = $fieldSpec->alias;
    if ($this->isRequired()) {
      $title .= ' <span class="crm-marker">*</span>';
    }
    $sizeClass = $this->getSizeClass($size);
    $minWidth = $this->getMinWidth($size);

    try {
      $form->add('select', "{$alias}_op", E::ts('Operator:'), $operations, TRUE, [
        'style' => $minWidth,
        'class' => 'crm-select2 ' . $sizeClass,
        'multiple' => FALSE,
        'placeholder' => E::ts('- select -'),
      ]);
    } catch (CRM_Core_Exception $e) {
    }

    CRM_Dataprocessor_Utils_Form::addDatePickerRange($form, $alias, $title, FALSE, FALSE, E::ts('From'), E::ts('To'), [], '_high', '_low', $sizeClass);

    if (isset($defaultFilterValue['value'])) {
      $defaults[$alias.'_value'] = $defaultFilterValue['value'];
    }
    if (isset($defaultFilterValue['relative'])) {
      $defaults[$alias.'_relative'] = $defaultFilterValue['relative'];
    }
    if (isset($defaultFilterValue['from'])) {
      $defaults[$alias.'_from'] = $defaultFilterValue['from'];
    }
    if (isset($defaultFilterValue['to'])) {
      $defaults[$alias.'_to'] = $defaultFilterValue['to'];
    }
    if (isset($defaultFilterValue['from_time'])) {
      $defaults[$alias.'_from_time'] = $defaultFilterValue['from_time'];
    }
    if (isset($defaultFilterValue['to_time'])) {
      $defaults[$alias.'_to_time'] = $defaultFilterValue['to_time'];
    }
    if (isset($defaultFilterValue['op'])) {
      $defaults[$alias . '_op'] = $defaultFilterValue['op'];
    } else {
      $defaults[$alias . '_op'] = key($operations);
    }

    if (count($defaults)) {
      $form->setDefaults($defaults);
    }

    $filter['type'] = $fieldSpec->type;
    $filter['alias'] = $fieldSpec->alias;
    $filter['title'] = $title;
    $filter['size'] = $size;
    return $filter;
  }

  /**
   * Apply the submitted filter
   *
   * @param $submittedValues
   * @throws \Exception
   */
  public function applyFilterFromSubmittedFilterParams($submittedValues) {
    $filterSpec = $this->getFieldSpecification();
    $dateFilterSet = CRM_Dataprocessor_Utils_Date::getDateFilterFromSubmittedValues($submittedValues);
    if ($this->isRequired() && !$dateFilterSet) {
      throw new FilterRequiredException('Field ' . $filterSpec->title . ' is required');
    }
    $filterParams = [];
    if ($dateFilterSet) {
      $filterParams['date'] = $dateFilterSet;
    }
    $filterParams = $this->extendFilterParamsFromSubmittedValues($submittedValues, $filterParams);

    $isFilterSet = false;
    if (isset($submittedValues['op'])) {
      switch ($submittedValues['op']) {
        case 'IN':
        case 'NOT IN':
          $filterParams['op'] = $submittedValues['op'];
          $isFilterSet = TRUE;
          break;
      }
    }
    if ($this->isRequired() && !$isFilterSet) {
      throw new FilterRequiredException('Field ' . $filterSpec->title . ' is required');
    }

    if ($isFilterSet && isset($filterParams['date'])) {
      $this->setFilter($filterParams);
    }
  }

  /**
   * Return the SQL statement for the date field.
   * @param string $tableAlias
   * @param string $fieldAlias
   * @param array $filter
   *
   * @return string
   */
  protected function getDateSqlStatement(string $tableAlias, string $fieldAlias, array $filter): string {
    $sqlStatement = "`$tableAlias`.`$fieldAlias` {$filter['date']['op']} ";
    if (is_array($filter['date']['value'])) {
      $sqlStatement .= "DATE('{$filter['date']['value'][0]}') AND DATE('{$filter['date']['value'][1]}')";
    } else {
      $sqlStatement .= "DATE('{$filter['date']['value']}')";
    }
    return $sqlStatement;
  }

}
