<?php

/*
 +--------------------------------------------------------------------+
 | Copyright CiviCRM LLC. All rights reserved.                        |
 |                                                                    |
 | This work is published under the GNU AGPLv3 license with some      |
 | permitted exceptions and without any warranty. For full license    |
 | and copyright information, see https://civicrm.org/licensing       |
 +--------------------------------------------------------------------+
 */

/**
 *
 * @package CRM
 * @copyright CiviCRM LLC https://civicrm.org/licensing
 */


namespace api\v4\Entity;

use Civi\Api4\Setting;
use api\v4\Api4TestBase;
use Civi\Test\TransactionalInterface;

/**
 * @group headless
 */
class SettingTest extends Api4TestBase implements TransactionalInterface {

  public function testSettingASetting(): void {
    $setting = Setting::set(FALSE)
      ->addValue('menubar_position', 'above-crm-container')
      ->execute()->first();
    $this->assertEquals('above-crm-container', $setting['value']);
    $setting = Setting::get(FALSE)
      ->addSelect('menubar_position')
      ->execute()->first();
    $this->assertEquals('above-crm-container', $setting['value']);

    $setting = Setting::revert(FALSE)
      ->addSelect('menubar_position')
      ->execute()->column('value', 'name');
    $this->assertEquals(['menubar_position' => 'over-cms-menu'], $setting);
    $setting = civicrm_api4('Setting', 'get', ['select' => ['menubar_position'], 'checkPermissions' => FALSE], 0);
    $this->assertEquals('over-cms-menu', $setting['value']);
  }

  public function testInvalidSetting(): void {
    $message = '';
    try {
      Setting::set()->addValue('not_a_real_setting!', 'hello')->setCheckPermissions(FALSE)->execute();
    }
    catch (\CRM_Core_Exception $e) {
      $message = $e->getMessage();
    }
    $this->assertStringContainsString('setting', $message);
  }

  public function testSerailizedSetting(): void {
    $set = \Civi\Api4\Setting::set(FALSE)
      ->addValue('contact_edit_options:name', [
        'CommunicationPreferences',
        'CustomData',
      ])
      ->execute();

    $setting = \Civi\Api4\Setting::get(FALSE)
      ->addSelect('contact_edit_options')
      ->execute()->first();
    $this->assertTrue(is_array($setting['value']));
    $this->assertTrue(is_numeric($setting['value'][0]));

    $setting = \Civi\Api4\Setting::get(FALSE)
      ->addSelect('contact_edit_options:label')
      ->execute()->first();
    $this->assertEquals(['Communication Preferences', 'Custom Data'], $setting['value']);
    $this->assertEquals('contact_edit_options:label', $setting['name']);
  }

  /**
   * Ensure settings work with the "index" mode.
   */
  public function testSettingsWithIndexParam(): void {
    $settings = civicrm_api4('Setting', 'get', [], ['name' => 'value']);
    $stringValues = FALSE;
    $arrayValues = FALSE;
    // With indexing by [name => value], keys should be string and values should be string/array
    foreach ($settings as $name => $value) {
      $this->assertTrue(is_string($name) && !is_numeric($name));
      if (is_string($value)) {
        $stringValues = TRUE;
      }
      elseif (is_array($value)) {
        $arrayValues = TRUE;
      }
    }
    $this->assertTrue($stringValues);
    $this->assertTrue($arrayValues);
  }

  /**
   * Make sure options load from getFields.
   */
  public function testSettingGetFieldsOptions(): void {
    $setting = civicrm_api4('Setting', 'getFields', [
      'select' => ['options'],
      'loadOptions' => FALSE,
    ], 'name');
    $this->assertTrue($setting['contact_edit_options']['options']);

    $setting = civicrm_api4('Setting', 'getFields', [
      'select' => ['options'],
      'where' => [['name', '=', 'contact_edit_options']],
      'loadOptions' => TRUE,
    ], 'name');
    $this->assertContains('Custom Data', $setting['contact_edit_options']['options']);

    $setting = civicrm_api4('Setting', 'getFields', [
      'select' => ['options'],
      'loadOptions' => ['id', 'name', 'label'],
    ], 'name');
    $this->assertTrue(is_array($setting['contact_edit_options']['options'][0]));
  }

  /**
   * Ensure settings default values unserialize.
   */
  public function testSettingUnserializeDefaults(): void {
    $setting = civicrm_api4('Setting', 'getFields', ['where' => [['name', '=', 'contact_view_options']]], 0);
    $this->assertTrue(is_array($setting['default']));
  }

}
