<?php

namespace Drupal\Tests\cron_fail_alert\Functional;

use Drupal\Tests\BrowserTestBase;
use PHPUnit\Framework\Attributes\Group;

/**
 * Tests the Cron Fail Alert settings form.
 */
#[Group('cron_fail_alert')]
class SettingsFormTest extends BrowserTestBase {

  /**
   * {@inheritdoc}
   */
  protected $defaultTheme = 'stark';

  /**
   * {@inheritdoc}
   */
  protected static $modules = ['cron_fail_alert'];

  /**
   * A user with permission to administer cron fail alert settings.
   *
   * @var \Drupal\user\UserInterface
   */
  protected $adminUser;

  /**
   * {@inheritdoc}
   */
  protected function setUp(): void {
    parent::setUp();

    // Create a user with permission to administer site configuration.
    $this->adminUser = $this->drupalCreateUser([
      'administer cron-fail-alert configuration',
    ]);
  }

  /**
   * Tests the settings form loads with default values.
   */
  public function testSettingsFormDefaults(): void {
    $this->drupalLogin($this->adminUser);
    $this->drupalGet('admin/config/system/cron-fail-alert');

    // Assert the form is accessible.
    $this->assertSession()->statusCodeEquals(200);
    $this->assertSession()->pageTextContains('Monitoring settings');
    $this->assertSession()->pageTextContains('Email notification settings');

    // Assert default values are present.
    $this->assertSession()->fieldValueEquals('frequency', '15');
    $this->assertSession()->fieldValueEquals('tolerance', '20');
    $this->assertSession()->fieldValueEquals('subject', 'URGENT: Drupal cron has failed, please investigate');
  }

  /**
   * Tests form validation for email field.
   */
  public function testEmailValidation(): void {
    $this->drupalLogin($this->adminUser);
    $this->drupalGet('admin/config/system/cron-fail-alert');

    // Submit with invalid email.
    $edit = [
      'frequency' => '15',
      'tolerance' => '20',
      'to' => 'invalid-email',
      'subject' => 'Test Subject',
      'message' => 'Test message',
    ];
    $this->submitForm($edit, 'Save configuration');
    $this->assertSession()->pageTextContains('The email address invalid-email is not valid.');

    // Submit with valid email.
    $edit['to'] = 'admin@example.com';
    $this->submitForm($edit, 'Save configuration');
    $this->assertSession()->pageTextContains('The configuration options have been saved.');
  }

  /**
   * Tests form validation for tolerance greater than frequency.
   */
  public function testToleranceValidation(): void {
    $this->drupalLogin($this->adminUser);
    $this->drupalGet('admin/config/system/cron-fail-alert');

    // Submit with tolerance less than or equal to frequency.
    $edit = [
      'frequency' => '20',
      'tolerance' => '15',
      'to' => 'admin@example.com',
      'subject' => 'Test Subject',
      'message' => 'Test message',
    ];
    $this->submitForm($edit, 'Save configuration');
    $this->assertSession()->pageTextContains('The cron failure tolerance must be greater than the check frequency to avoid false positives.');

    // Submit with tolerance equal to frequency.
    $edit['tolerance'] = '20';
    $this->submitForm($edit, 'Save configuration');
    $this->assertSession()->pageTextContains('The cron failure tolerance must be greater than the check frequency to avoid false positives.');

    // Submit with tolerance greater than frequency.
    $edit['tolerance'] = '25';
    $this->submitForm($edit, 'Save configuration');
    $this->assertSession()->pageTextContains('The configuration options have been saved.');
  }

  /**
   * Tests that form values are saved correctly to configuration.
   */
  public function testSettingsFormSubmit(): void {
    $this->drupalLogin($this->adminUser);
    $this->drupalGet('admin/config/system/cron-fail-alert');

    // Submit the form with custom values.
    $edit = [
      'frequency' => '30',
      'tolerance' => '45',
      'to' => 'custom@example.com',
      'subject' => 'Custom Subject Line',
      'message' => 'Custom message with @minutes and :site tokens',
    ];
    $this->submitForm($edit, 'Save configuration');

    // Assert the configuration was saved.
    $this->assertSession()->pageTextContains('The configuration options have been saved.');

    // Verify the configuration values.
    $config = $this->config('cron_fail_alert.settings');
    $this->assertEquals('30', $config->get('frequency'));
    $this->assertEquals('45', $config->get('tolerance'));
    $this->assertEquals('custom@example.com', $config->get('to'));
    $this->assertEquals('Custom Subject Line', $config->get('subject'));
    $this->assertEquals('Custom message with @minutes and :site tokens', $config->get('message'));
  }

  /**
   * Tests access control to the settings form.
   */
  public function testSettingsFormAccess(): void {
    // Anonymous users should not have access.
    $this->drupalGet('admin/config/system/cron-fail-alert');
    $this->assertSession()->statusCodeEquals(403);

    // Regular authenticated users should not have access.
    $regular_user = $this->drupalCreateUser();
    $this->drupalLogin($regular_user);
    $this->drupalGet('admin/config/system/cron-fail-alert');
    $this->assertSession()->statusCodeEquals(403);

    // Admin users should have access.
    $this->drupalLogin($this->adminUser);
    $this->drupalGet('admin/config/system/cron-fail-alert');
    $this->assertSession()->statusCodeEquals(200);
  }

  /**
   * Tests field constraints (min/max values).
   */
  public function testFieldConstraints(): void {
    $this->drupalLogin($this->adminUser);
    $this->drupalGet('admin/config/system/cron-fail-alert');

    // Verify frequency field has proper constraints.
    $frequency_field = $this->assertSession()->fieldExists('frequency');
    $this->assertEquals('1', $frequency_field->getAttribute('min'));
    $this->assertEquals('1440', $frequency_field->getAttribute('max'));
    $this->assertEquals('1', $frequency_field->getAttribute('step'));

    // Verify tolerance field has proper constraints.
    $tolerance_field = $this->assertSession()->fieldExists('tolerance');
    $this->assertEquals('1', $tolerance_field->getAttribute('min'));
    $this->assertEquals('10080', $tolerance_field->getAttribute('max'));
    $this->assertEquals('1', $tolerance_field->getAttribute('step'));
  }

}
