<?php

declare(strict_types=1);

namespace Drupal\ffmpeg_media_image\Form;

use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\TypedConfigManagerInterface;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
use Drupal\ffmpeg_media_image\Plugin\FFmpegProcessor\GifProcessor;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Configure FFmpeg Media image processing settings.
 */
final class ImageSettingsForm extends ConfigFormBase {

  /**
   * Constructs the image settings form.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   The config factory.
   * @param \Drupal\Core\Config\TypedConfigManagerInterface $typedConfigManager
   *   The typed config manager.
   * @param \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $streamWrapperManager
   *   The stream wrapper manager.
   */
  public function __construct(
    ConfigFactoryInterface $configFactory,
    TypedConfigManagerInterface $typedConfigManager,
    private readonly StreamWrapperManagerInterface $streamWrapperManager,
  ) {
    parent::__construct($configFactory, $typedConfigManager);
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  public static function create(ContainerInterface $container): static {
    return new static(
      $container->get('config.factory'),
      $container->get('config.typed'),
      $container->get('stream_wrapper_manager'),
    );
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  public function getFormId(): string {
    return 'ffmpeg_media_image_settings';
  }

  /**
   * {@inheritdoc}
   *
   * @phpstan-return array<int, string>
   */
  #[\Override]
  protected function getEditableConfigNames(): array {
    return ['ffmpeg_media_image.settings'];
  }

  /**
   * {@inheritdoc}
   *
   * @param array<string, mixed> $form
   *   Form structure.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   *
   * @phpstan-return array<string, mixed>
   */
  #[\Override]
  public function buildForm(array $form, FormStateInterface $form_state): array {
    $config = $this->config('ffmpeg_media_image.settings');

    $form['thumbnail'] = [
      '#type' => 'details',
      '#title' => $this->t('Thumbnail'),
      '#open' => TRUE,
    ];

    $form['thumbnail']['thumbnail_time_offset'] = [
      '#type' => 'number',
      '#title' => $this->t('Time offset (seconds)'),
      '#description' => $this->t('Time offset from the start to capture the thumbnail frame.'),
      '#default_value' => $config->get('thumbnail_time_offset') ?? 5,
      '#min' => 0,
      '#max' => 300,
      '#required' => TRUE,
    ];

    $form['thumbnail']['thumbnail_width'] = [
      '#type' => 'number',
      '#title' => $this->t('Width (pixels)'),
      '#description' => $this->t('Thumbnail width. Height is auto-calculated to preserve aspect ratio.'),
      '#default_value' => $config->get('thumbnail_width') ?? 640,
      '#min' => 64,
      '#max' => 3840,
      '#required' => TRUE,
    ];

    $form['gif'] = [
      '#type' => 'details',
      '#title' => $this->t('GIF'),
      '#open' => FALSE,
    ];

    $form['gif']['gif_start_time'] = [
      '#type' => 'number',
      '#title' => $this->t('Start time (seconds)'),
      '#default_value' => $config->get('gif_start_time') ?? 0,
      '#min' => 0,
      '#max' => 300,
      '#required' => TRUE,
    ];

    $form['gif']['gif_duration'] = [
      '#type' => 'number',
      '#title' => $this->t('Duration (seconds)'),
      '#default_value' => $config->get('gif_duration') ?? 5,
      '#min' => 1,
      '#max' => 30,
      '#required' => TRUE,
    ];

    $form['gif']['gif_width'] = [
      '#type' => 'number',
      '#title' => $this->t('Width (pixels)'),
      '#default_value' => $config->get('gif_width') ?? 480,
      '#min' => 64,
      '#max' => 1920,
      '#required' => TRUE,
    ];

    $form['gif']['gif_fps'] = [
      '#type' => 'number',
      '#title' => $this->t('<abbr title="Frames Per Second">FPS</abbr>'),
      '#default_value' => $config->get('gif_fps') ?? 10,
      '#min' => 1,
      '#max' => 60,
      '#required' => TRUE,
    ];

    $form['gif']['gif_palette_optimization'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Palette optimization'),
      '#description' => $this->t('Enable palette generation/use for better GIF quality and smaller files.'),
      '#default_value' => $config->get('gif_palette_optimization') ?? TRUE,
    ];

    $form['gif']['gif_dither_mode'] = [
      '#type' => 'select',
      '#title' => $this->t('Dither mode'),
      '#description' => $this->t('Dithering algorithm used during palette application.'),
      '#options' => GifProcessor::getAvailableDitherModes(),
      '#default_value' => $config->get('gif_dither_mode') ?? 'bayer',
      '#required' => TRUE,
    ];

    $form['gif']['gif_output_directory'] = [
      '#type' => 'textfield',
      '#title' => $this->t('GIF output directory'),
      '#description' => $this->t('Directory for generated GIF files. Must be a Drupal stream wrapper URI such as <em>public://ffmpeg_gifs</em> or <em>private://ffmpeg_gifs</em>.'),
      '#default_value' => $config->get('gif_output_directory') ?? 'public://ffmpeg_gifs',
      '#required' => TRUE,
    ];

    $form['segment_thumbnails'] = [
      '#type' => 'details',
      '#title' => $this->t('Segment thumbnails'),
      '#open' => FALSE,
    ];

    $form['segment_thumbnails']['segment_thumbnail_interval'] = [
      '#type' => 'number',
      '#title' => $this->t('Interval (seconds)'),
      '#default_value' => $config->get('segment_thumbnail_interval') ?? 10,
      '#min' => 1,
      '#max' => 600,
      '#required' => TRUE,
    ];

    $form['segment_thumbnails']['segment_thumbnail_width'] = [
      '#type' => 'number',
      '#title' => $this->t('Width (pixels)'),
      '#default_value' => $config->get('segment_thumbnail_width') ?? 320,
      '#min' => 64,
      '#max' => 3840,
      '#required' => TRUE,
    ];

    $form['segment_thumbnails']['segment_thumbnail_quality'] = [
      '#type' => 'number',
      '#title' => $this->t('JPEG quality (2-31)'),
      '#description' => $this->t('Lower values mean better quality and larger files.'),
      '#default_value' => $config->get('segment_thumbnail_quality') ?? 3,
      '#min' => 2,
      '#max' => 31,
      '#required' => TRUE,
    ];

    $form['segment_thumbnails']['segment_thumbnail_max'] = [
      '#type' => 'number',
      '#title' => $this->t('Maximum thumbnails'),
      '#default_value' => $config->get('segment_thumbnail_max') ?? 100,
      '#min' => 1,
      '#max' => 1000,
      '#required' => TRUE,
    ];

    $form['segment_gifs'] = [
      '#type' => 'details',
      '#title' => $this->t('Segment GIFs'),
      '#open' => FALSE,
    ];

    $form['segment_gifs']['segment_gif_interval'] = [
      '#type' => 'number',
      '#title' => $this->t('Interval (seconds)'),
      '#default_value' => $config->get('segment_gif_interval') ?? 30,
      '#min' => 1,
      '#max' => 600,
      '#required' => TRUE,
    ];

    $form['segment_gifs']['segment_gif_duration'] = [
      '#type' => 'number',
      '#title' => $this->t('Duration (seconds)'),
      '#default_value' => $config->get('segment_gif_duration') ?? 3,
      '#min' => 1,
      '#max' => 30,
      '#required' => TRUE,
    ];

    $form['segment_gifs']['segment_gif_fps'] = [
      '#type' => 'number',
      '#title' => $this->t('FPS'),
      '#default_value' => $config->get('segment_gif_fps') ?? 10,
      '#min' => 1,
      '#max' => 60,
      '#required' => TRUE,
    ];

    $form['segment_gifs']['segment_gif_width'] = [
      '#type' => 'number',
      '#title' => $this->t('Width (pixels)'),
      '#default_value' => $config->get('segment_gif_width') ?? 320,
      '#min' => 64,
      '#max' => 1920,
      '#required' => TRUE,
    ];

    $form['segment_gifs']['segment_gif_max'] = [
      '#type' => 'number',
      '#title' => $this->t('Maximum GIFs'),
      '#default_value' => $config->get('segment_gif_max') ?? 20,
      '#min' => 1,
      '#max' => 200,
      '#required' => TRUE,
    ];

    $form['segment_gifs']['segment_gif_optimize'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Palette optimization'),
      '#default_value' => $config->get('segment_gif_optimize') ?? TRUE,
    ];

    return parent::buildForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   *
   * @param array<array-key, mixed> $form
   *   Form structure.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  #[\Override]
  public function validateForm(array &$form, FormStateInterface $form_state): void {
    parent::validateForm($form, $form_state);

    $ditherMode = (string) $form_state->getValue('gif_dither_mode');
    if (!isset(GifProcessor::DITHER_MODES[$ditherMode])) {
      $form_state->setErrorByName('gif_dither_mode', $this->t('Invalid dither mode selected.'));
    }

    $outputDirectory = trim((string) $form_state->getValue('gif_output_directory'));
    if ($outputDirectory === '') {
      $form_state->setErrorByName('gif_output_directory', $this->t('GIF output directory is required.'));
      return;
    }

    if (!str_contains($outputDirectory, '://')) {
      $form_state->setErrorByName('gif_output_directory', $this->t('GIF output directory must be a stream wrapper URI (for example, <em>public://ffmpeg_gifs</em> or <em>private://ffmpeg_gifs</em>). Absolute filesystem paths are not supported.'));
      return;
    }

    $scheme = explode('://', $outputDirectory, 2)[0];
    if (!$this->streamWrapperManager->getViaScheme($scheme)) {
      $form_state->setErrorByName('gif_output_directory', $this->t('The stream wrapper @scheme:// is not available. Use public:// or configure the @scheme file system.', [
        '@scheme' => $scheme,
      ]));
    }
  }

  /**
   * {@inheritdoc}
   *
   * @param array<array-key, mixed> $form
   *   Form structure.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  #[\Override]
  public function submitForm(array &$form, FormStateInterface $form_state): void {
    $this->config('ffmpeg_media_image.settings')
      ->set('thumbnail_time_offset', (int) $form_state->getValue('thumbnail_time_offset'))
      ->set('thumbnail_width', (int) $form_state->getValue('thumbnail_width'))
      ->set('gif_start_time', (int) $form_state->getValue('gif_start_time'))
      ->set('gif_duration', (int) $form_state->getValue('gif_duration'))
      ->set('gif_width', (int) $form_state->getValue('gif_width'))
      ->set('gif_fps', (int) $form_state->getValue('gif_fps'))
      ->set('gif_palette_optimization', (bool) $form_state->getValue('gif_palette_optimization'))
      ->set('gif_output_directory', (string) $form_state->getValue('gif_output_directory'))
      ->set('gif_dither_mode', (string) $form_state->getValue('gif_dither_mode'))
      ->set('segment_thumbnail_interval', (int) $form_state->getValue('segment_thumbnail_interval'))
      ->set('segment_thumbnail_width', (int) $form_state->getValue('segment_thumbnail_width'))
      ->set('segment_thumbnail_quality', (int) $form_state->getValue('segment_thumbnail_quality'))
      ->set('segment_thumbnail_max', (int) $form_state->getValue('segment_thumbnail_max'))
      ->set('segment_gif_interval', (int) $form_state->getValue('segment_gif_interval'))
      ->set('segment_gif_duration', (int) $form_state->getValue('segment_gif_duration'))
      ->set('segment_gif_fps', (int) $form_state->getValue('segment_gif_fps'))
      ->set('segment_gif_width', (int) $form_state->getValue('segment_gif_width'))
      ->set('segment_gif_max', (int) $form_state->getValue('segment_gif_max'))
      ->set('segment_gif_optimize', (bool) $form_state->getValue('segment_gif_optimize'))
      ->save();

    parent::submitForm($form, $form_state);
  }

}
