<?php

declare(strict_types=1);

namespace Drupal\ffmpeg_media_streaming\Form;

use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\State\StateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Configure FFmpeg Media Streaming settings.
 */
final class StreamingSettingsForm extends ConfigFormBase {

  /**
   * The state service.
   */
  protected StateInterface $state;

  /**
   * {@inheritdoc}
   */
  #[\Override]
  public static function create(ContainerInterface $container): static {
    $instance = parent::create($container);
    $instance->state = $container->get(StateInterface::class);
    return $instance;
  }

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

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

  /**
   * {@inheritdoc}
   *
   * @phpstan-return array<string, mixed>
   */
  #[\Override]
  public function buildForm(array $form, FormStateInterface $form_state): array {
    $config = $this->config('ffmpeg_media_streaming.settings');

    // HLS Settings.
    $form['hls'] = [
      '#type' => 'details',
      '#title' => $this->t('<abbr title="HTTP Live Streaming">HLS</abbr> Settings'),
      '#description' => $this->t('HTTP Live Streaming (Apple HLS) configuration.'),
      '#open' => TRUE,
    ];

    $form['hls']['hls_segment_duration'] = [
      '#type' => 'number',
      '#title' => $this->t('Segment duration (seconds)'),
      '#description' => $this->t('Duration of each HLS segment. Typical values: 2-10 seconds.'),
      '#default_value' => $config->get('hls_segment_duration') ?? 6,
      '#min' => 1,
      '#max' => 60,
      '#required' => TRUE,
    ];

    $form['hls']['hls_playlist_type'] = [
      '#type' => 'select',
      '#title' => $this->t('Playlist type'),
      '#description' => $this->t('VOD for video-on-demand, Event for live recordings.'),
      '#options' => [
        'vod' => $this->t('VOD (Video on Demand)'),
        'event' => $this->t('Event (Live recording)'),
      ],
      '#default_value' => $config->get('hls_playlist_type') ?? 'vod',
      '#required' => TRUE,
    ];

    $form['hls']['hls_segment_pattern'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Segment filename pattern'),
      '#description' => $this->t('Pattern for segment filenames. Use %v for variant, %d for sequence number. Example: %v/segment_%03d.ts'),
      '#default_value' => $config->get('hls_segment_pattern') ?? '%v/segment_%03d.ts',
      '#required' => TRUE,
    ];

    $form['hls']['hls_segment_type'] = [
      '#type' => 'select',
      '#title' => $this->t('Segment type'),
      '#description' => $this->t('MPEG-TS is widely compatible. <abbr title="Fragmented MP4">fMP4</abbr> (<abbr title="Common Media Application Format">CMAF</abbr>) enables unified HLS/<abbr title="Dynamic Adaptive Streaming over HTTP">DASH</abbr> delivery.'),
      '#options' => [
        'mpegts' => $this->t('MPEG-TS (.ts)'),
        'fmp4' => $this->t('Fragmented MP4 / CMAF (.m4s)'),
      ],
      '#default_value' => $config->get('hls_segment_type') ?? 'mpegts',
      '#required' => TRUE,
    ];

    $form['hls']['hls_master_playlist'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Master playlist filename'),
      '#description' => $this->t('Filename for the master playlist. Must end with .m3u8'),
      '#default_value' => $config->get('hls_master_playlist') ?? 'master.m3u8',
      '#required' => TRUE,
    ];

    $form['hls']['hls_low_latency'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable <abbr title="Low-Latency HTTP Live Streaming">LL-HLS</abbr>'),
      '#description' => $this->t('Enables LL-HLS with partial segments for sub-second latency. Requires fMP4 segment type.'),
      '#default_value' => $config->get('hls_low_latency') ?? FALSE,
    ];

    $form['hls']['hls_part_duration'] = [
      '#type' => 'number',
      '#title' => $this->t('Partial segment duration (seconds)'),
      '#description' => $this->t('Duration of LL-HLS partial segments. Recommended: 0.2-0.5 seconds.'),
      '#default_value' => $config->get('hls_part_duration') ?? 0.333,
      '#min' => 0.1,
      '#max' => 2.0,
      '#step' => 0.001,
      '#states' => [
        'visible' => [
          ':input[name="hls_low_latency"]' => ['checked' => TRUE],
        ],
      ],
    ];

    // DASH Settings.
    $form['dash'] = [
      '#type' => 'details',
      '#title' => $this->t('DASH Settings'),
      '#description' => $this->t('MPEG-<abbr title="Dynamic Adaptive Streaming over HTTP">DASH</abbr> configuration.'),
      '#open' => TRUE,
    ];

    $form['dash']['dash_segment_duration'] = [
      '#type' => 'number',
      '#title' => $this->t('Segment duration (seconds)'),
      '#description' => $this->t('Duration of each DASH segment. Typical values: 2-6 seconds.'),
      '#default_value' => $config->get('dash_segment_duration') ?? 4,
      '#min' => 1,
      '#max' => 30,
      '#required' => TRUE,
    ];

    $form['dash']['dash_profile'] = [
      '#type' => 'select',
      '#title' => $this->t('Profile'),
      '#description' => $this->t('On-demand for <abbr title="Video on Demand">VOD</abbr> with byte-range requests. Live for streaming with sliding window.'),
      '#options' => [
        'ondemand' => $this->t('On-demand (VOD)'),
        'live' => $this->t('Live'),
      ],
      '#default_value' => $config->get('dash_profile') ?? 'ondemand',
      '#required' => TRUE,
    ];

    $form['dash']['dash_min_buffer_time'] = [
      '#type' => 'number',
      '#title' => $this->t('Minimum buffer time (seconds)'),
      '#description' => $this->t('Minimum buffer time for DASH playback.'),
      '#default_value' => $config->get('dash_min_buffer_time') ?? 1.5,
      '#min' => 0.5,
      '#max' => 10,
      '#step' => 0.5,
      '#required' => TRUE,
    ];

    $form['dash']['dash_init_segment'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Init segment pattern'),
      '#description' => $this->t('Pattern for initialization segments. Use $RepresentationID$ for variant ID.'),
      '#default_value' => $config->get('dash_init_segment') ?? 'init-$RepresentationID$.m4s',
      '#required' => TRUE,
    ];

    $form['dash']['dash_media_segment'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Media segment pattern'),
      '#description' => $this->t('Pattern for media segments. Use $RepresentationID$ and $Number$ (or $Time$) for segment numbering.'),
      '#default_value' => $config->get('dash_media_segment') ?? 'chunk-$RepresentationID$-$Number%05d$.m4s',
      '#required' => TRUE,
    ];

    $form['dash']['dash_low_latency'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable <abbr title="Low-Latency Dynamic Adaptive Streaming over HTTP">LL-DASH</abbr>'),
      '#description' => $this->t('Enables LL-DASH with chunked transfer and reduced latency. Switches profile to live.'),
      '#default_value' => $config->get('dash_low_latency') ?? FALSE,
    ];

    $form['dash']['dash_target_latency'] = [
      '#type' => 'number',
      '#title' => $this->t('Target latency (seconds)'),
      '#description' => $this->t('Target end-to-end latency for LL-DASH. Minimum 0.5 seconds.'),
      '#default_value' => $config->get('dash_target_latency') ?? 3.0,
      '#min' => 0.5,
      '#max' => 30,
      '#step' => 0.1,
      '#states' => [
        'visible' => [
          ':input[name="dash_low_latency"]' => ['checked' => TRUE],
        ],
      ],
    ];

    // Representations (ABR ladder).
    $form['representations'] = [
      '#type' => 'details',
      '#title' => $this->t('<abbr title="Adaptive Bitrate">ABR</abbr> Representations'),
      '#description' => $this->t('Configure the resolution/bitrate ladder for adaptive streaming.'),
      '#open' => TRUE,
    ];

    $form['representations']['per_title_encoding'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable per-title encoding'),
      '#description' => $this->t('Analyzes each video to determine optimal bitrate per resolution. Overrides the static ladder below when enabled.'),
      '#default_value' => $config->get('per_title_encoding') ?? FALSE,
    ];

    $representations = $form_state->get('representations');
    if ($representations === NULL) {
      $representations = $config->get('representations') ?? $this->getDefaultRepresentations();
      $form_state->set('representations', $representations);
    }

    $form['representations']['representations_table'] = [
      '#type' => 'table',
      '#header' => [
        $this->t('Name'),
        $this->t('Width'),
        $this->t('Height'),
        $this->t('Video Bitrate'),
        $this->t('Audio Bitrate'),
        $this->t('Operations'),
      ],
      '#prefix' => '<div id="representations-wrapper">',
      '#suffix' => '</div>',
      '#empty' => $this->t('No representations configured. Add at least one.'),
    ];

    foreach ($representations as $index => $rep) {
      $form['representations']['representations_table'][$index]['name'] = [
        '#type' => 'textfield',
        '#title' => $this->t('Name'),
        '#title_display' => 'invisible',
        '#default_value' => $rep['name'] ?? '',
        '#size' => 10,
        '#required' => TRUE,
        '#placeholder' => '720p',
      ];

      $form['representations']['representations_table'][$index]['width'] = [
        '#type' => 'number',
        '#title' => $this->t('Width'),
        '#title_display' => 'invisible',
        '#default_value' => $rep['width'] ?? 1280,
        '#min' => 160,
        '#max' => 7680,
        '#required' => TRUE,
      ];

      $form['representations']['representations_table'][$index]['height'] = [
        '#type' => 'number',
        '#title' => $this->t('Height'),
        '#title_display' => 'invisible',
        '#default_value' => $rep['height'] ?? 720,
        '#min' => 90,
        '#max' => 4320,
        '#required' => TRUE,
      ];

      $form['representations']['representations_table'][$index]['bitrate'] = [
        '#type' => 'textfield',
        '#title' => $this->t('Video Bitrate'),
        '#title_display' => 'invisible',
        '#default_value' => $rep['bitrate'] ?? '2500k',
        '#size' => 10,
        '#required' => TRUE,
        '#placeholder' => '2500k',
      ];

      $form['representations']['representations_table'][$index]['audio_bitrate'] = [
        '#type' => 'textfield',
        '#title' => $this->t('Audio Bitrate'),
        '#title_display' => 'invisible',
        '#default_value' => $rep['audio_bitrate'] ?? '128k',
        '#size' => 10,
        '#required' => TRUE,
        '#placeholder' => '128k',
      ];

      $form['representations']['representations_table'][$index]['remove'] = [
        '#type' => 'submit',
        '#value' => $this->t('Remove'),
        '#name' => 'remove_' . $index,
        '#submit' => ['::removeRepresentationSubmit'],
        '#ajax' => [
          'callback' => '::representationsAjaxCallback',
          'wrapper' => 'representations-wrapper',
        ],
        '#limit_validation_errors' => [],
        '#attributes' => [
          'aria-label' => $this->t('Remove representation @index', ['@index' => $index + 1]),
        ],
      ];
    }

    $form['representations']['add_representation'] = [
      '#type' => 'submit',
      '#value' => $this->t('Add representation'),
      '#submit' => ['::addRepresentationSubmit'],
      '#ajax' => [
        'callback' => '::representationsAjaxCallback',
        'wrapper' => 'representations-wrapper',
      ],
      '#limit_validation_errors' => [],
    ];

    // WHIP Settings (Experimental).
    $form['whip'] = [
      '#type' => 'details',
      '#title' => $this->t('<abbr title="WebRTC-HTTP Ingestion Protocol">WHIP</abbr> Settings (Experimental)'),
      '#description' => $this->t('WebRTC-HTTP Ingestion Protocol for sub-second latency live streaming. Requires FFmpeg 8.0+.'),
      '#open' => FALSE,
    ];

    $form['whip']['whip_enabled'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable WHIP streaming'),
      '#description' => $this->t('Allow WHIP output format for live streaming.'),
      '#default_value' => $config->get('whip_enabled') ?? FALSE,
    ];

    $form['whip']['whip_endpoint_url'] = [
      '#type' => 'url',
      '#title' => $this->t('WHIP endpoint URL'),
      '#description' => $this->t('The WHIP server endpoint URL (e.g., https://whip.example.com/ingest).'),
      '#default_value' => $config->get('whip_endpoint_url') ?? '',
      '#states' => [
        'visible' => [
          ':input[name="whip_enabled"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $envWhipToken = getenv('FFMPEG_WHIP_BEARER_TOKEN');
    $whipTokenDescription = $this->t('Authentication token for the WHIP endpoint (optional). Stored in the State API (not exported with config). Leave empty to keep current value.');
    if (is_string($envWhipToken) && $envWhipToken !== '') {
      $whipTokenDescription = $this->t('Currently provided via <code>FFMPEG_WHIP_BEARER_TOKEN</code> environment variable (takes precedence over this field).');
    }

    $form['whip']['whip_bearer_token'] = [
      '#type' => 'password',
      '#title' => $this->t('Bearer token'),
      '#description' => $whipTokenDescription,
      '#states' => [
        'visible' => [
          ':input[name="whip_enabled"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['whip']['whip_ice_servers'] = [
      '#type' => 'textfield',
      '#title' => $this->t('<abbr title="Interactive Connectivity Establishment">ICE</abbr> servers'),
      '#description' => $this->t('<abbr title="Session Traversal Utilities for NAT">STUN</abbr>/<abbr title="Traversal Using Relays around NAT">TURN</abbr> servers for <abbr title="Network Address Translation">NAT</abbr> traversal (e.g., stun:stun.l.google.com:19302).'),
      '#default_value' => $config->get('whip_ice_servers') ?? 'stun:stun.l.google.com:19302',
      '#states' => [
        'visible' => [
          ':input[name="whip_enabled"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['whip']['whip_video_bitrate'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Video bitrate'),
      '#description' => $this->t('Target video bitrate for WHIP streams (e.g., 2500k).'),
      '#default_value' => $config->get('whip_video_bitrate') ?? '2500k',
      '#size' => 10,
      '#states' => [
        'visible' => [
          ':input[name="whip_enabled"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['whip']['whip_audio_bitrate'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Audio bitrate'),
      '#description' => $this->t('Target audio bitrate for WHIP streams (e.g., 128k).'),
      '#default_value' => $config->get('whip_audio_bitrate') ?? '128k',
      '#size' => 10,
      '#states' => [
        'visible' => [
          ':input[name="whip_enabled"]' => ['checked' => TRUE],
        ],
      ],
    ];

    // RTP Settings (Experimental).
    $form['rtp'] = [
      '#type' => 'details',
      '#title' => $this->t('<abbr title="Real-time Transport Protocol">RTP</abbr> Settings (Experimental)'),
      '#description' => $this->t('Real-time Transport Protocol for low-latency streaming with <abbr title="Session Description Protocol">SDP</abbr> support.'),
      '#open' => FALSE,
    ];

    $form['rtp']['rtp_enabled'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Enable RTP streaming'),
      '#description' => $this->t('Allow RTP output format for live streaming.'),
      '#default_value' => $config->get('rtp_enabled') ?? FALSE,
    ];

    $form['rtp']['rtp_destination_host'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Destination host'),
      '#description' => $this->t('Target <abbr title="Internet Protocol">IP</abbr> address for RTP packets (unicast or multicast).'),
      '#default_value' => $config->get('rtp_destination_host') ?? '127.0.0.1',
      '#states' => [
        'visible' => [
          ':input[name="rtp_enabled"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['rtp']['rtp_video_port'] = [
      '#type' => 'number',
      '#title' => $this->t('Video port'),
      '#description' => $this->t('<abbr title="User Datagram Protocol">UDP</abbr> port for video RTP stream.'),
      '#default_value' => $config->get('rtp_video_port') ?? 5004,
      '#min' => 1024,
      '#max' => 65535,
      '#states' => [
        'visible' => [
          ':input[name="rtp_enabled"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['rtp']['rtp_audio_port'] = [
      '#type' => 'number',
      '#title' => $this->t('Audio port'),
      '#description' => $this->t('UDP port for audio RTP stream.'),
      '#default_value' => $config->get('rtp_audio_port') ?? 5006,
      '#min' => 1024,
      '#max' => 65535,
      '#states' => [
        'visible' => [
          ':input[name="rtp_enabled"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['rtp']['rtp_ttl'] = [
      '#type' => 'number',
      '#title' => $this->t('TTL (Time-to-live)'),
      '#description' => $this->t('<abbr title="Internet Protocol">IP</abbr> packet TTL, important for multicast routing.'),
      '#default_value' => $config->get('rtp_ttl') ?? 64,
      '#min' => 1,
      '#max' => 255,
      '#states' => [
        'visible' => [
          ':input[name="rtp_enabled"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['rtp']['rtp_generate_sdp'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Generate SDP file'),
      '#description' => $this->t('Create an SDP file for players to connect to the stream.'),
      '#default_value' => $config->get('rtp_generate_sdp') ?? TRUE,
      '#states' => [
        'visible' => [
          ':input[name="rtp_enabled"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['rtp']['rtp_video_bitrate'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Video bitrate'),
      '#description' => $this->t('Target video bitrate for RTP streams (e.g., 2500k).'),
      '#default_value' => $config->get('rtp_video_bitrate') ?? '2500k',
      '#size' => 10,
      '#states' => [
        'visible' => [
          ':input[name="rtp_enabled"]' => ['checked' => TRUE],
        ],
      ],
    ];

    $form['rtp']['rtp_audio_bitrate'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Audio bitrate'),
      '#description' => $this->t('Target audio bitrate for RTP streams (e.g., 128k).'),
      '#default_value' => $config->get('rtp_audio_bitrate') ?? '128k',
      '#size' => 10,
      '#states' => [
        'visible' => [
          ':input[name="rtp_enabled"]' => ['checked' => TRUE],
        ],
      ],
    ];

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

  /**
   * AJAX callback for representations table.
   *
   * @return array<string, mixed>
   *   The representations table render array.
   */
  public function representationsAjaxCallback(array &$form, FormStateInterface $form_state): array {
    return $form['representations']['representations_table'];
  }

  /**
   * Submit handler for adding a representation.
   */
  public function addRepresentationSubmit(array &$form, FormStateInterface $form_state): void {
    $representations = $form_state->get('representations') ?? [];
    $representations[] = [
      'name' => '',
      'width' => 1280,
      'height' => 720,
      'bitrate' => '2500k',
      'audio_bitrate' => '128k',
    ];
    $form_state->set('representations', $representations);
    $form_state->setRebuild();
  }

  /**
   * Submit handler for removing a representation.
   */
  public function removeRepresentationSubmit(array &$form, FormStateInterface $form_state): void {
    $trigger = $form_state->getTriggeringElement();
    $index = (int) str_replace('remove_', '', $trigger['#name'] ?? '');

    $representations = $form_state->get('representations') ?? [];
    unset($representations[$index]);
    $representations = array_values($representations);

    $form_state->set('representations', $representations);
    $form_state->setRebuild();
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  public function validateForm(array &$form, FormStateInterface $form_state): void {
    parent::validateForm($form, $form_state);

    // Validate HLS segment pattern.
    $hlsPattern = $form_state->getValue('hls_segment_pattern');
    if ($hlsPattern !== NULL && !str_contains($hlsPattern, '%') && !str_contains($hlsPattern, '.ts')) {
      $form_state->setErrorByName('hls_segment_pattern', $this->t('HLS segment pattern should contain format specifiers and end with .ts'));
    }

    // Validate HLS master playlist.
    $hlsMaster = $form_state->getValue('hls_master_playlist');
    if ($hlsMaster !== NULL && !str_ends_with($hlsMaster, '.m3u8')) {
      $form_state->setErrorByName('hls_master_playlist', $this->t('Master playlist filename must end with .m3u8'));
    }

    // Validate DASH init segment.
    $dashInit = $form_state->getValue('dash_init_segment');
    if ($dashInit !== NULL && !str_contains($dashInit, '$RepresentationID$')) {
      $form_state->setErrorByName('dash_init_segment', $this->t('DASH init segment pattern must contain $RepresentationID$'));
    }

    // Validate DASH media segment.
    $dashMedia = $form_state->getValue('dash_media_segment');
    if ($dashMedia !== NULL) {
      if (!str_contains($dashMedia, '$RepresentationID$')) {
        $form_state->setErrorByName('dash_media_segment', $this->t('DASH media segment pattern must contain $RepresentationID$'));
      }
      if (!str_contains($dashMedia, '$Number') && !str_contains($dashMedia, '$Time')) {
        $form_state->setErrorByName('dash_media_segment', $this->t('DASH media segment pattern must contain $Number$ or $Time$ (with optional format specifiers)'));
      }
    }

    // Validate LL-HLS settings.
    if ($form_state->getValue('hls_low_latency')) {
      $partDuration = (float) $form_state->getValue('hls_part_duration');
      if ($partDuration < 0.1 || $partDuration > 2.0) {
        $form_state->setErrorByName('hls_part_duration', $this->t('LL-HLS partial segment duration must be between 0.1 and 2.0 seconds.'));
      }
    }

    // Validate LL-DASH settings.
    if ($form_state->getValue('dash_low_latency')) {
      $targetLatency = (float) $form_state->getValue('dash_target_latency');
      if ($targetLatency < 0.5) {
        $form_state->setErrorByName('dash_target_latency', $this->t('LL-DASH target latency must be at least 0.5 seconds.'));
      }
    }

    // Validate representations.
    $representations = $form_state->getValue('representations_table') ?? [];
    if (empty($representations)) {
      $form_state->setErrorByName('representations_table', $this->t('At least one representation is required.'));
    }

    foreach ($representations as $index => $rep) {
      // Validate bitrate format.
      if (!empty($rep['bitrate']) && !preg_match('/^\d+[kKmM]?$/', $rep['bitrate'])) {
        $form_state->setErrorByName("representations_table][$index][bitrate", $this->t('Invalid video bitrate format. Use values like 2500k or 5M.'));
      }
      if (!empty($rep['audio_bitrate']) && !preg_match('/^\d+[kKmM]?$/', $rep['audio_bitrate'])) {
        $form_state->setErrorByName("representations_table][$index][audio_bitrate", $this->t('Invalid audio bitrate format. Use values like 128k or 192k.'));
      }
    }

    // Validate WHIP settings if enabled.
    if ($form_state->getValue('whip_enabled')) {
      $whipUrl = $form_state->getValue('whip_endpoint_url');
      if (empty($whipUrl)) {
        $form_state->setErrorByName('whip_endpoint_url', $this->t('WHIP endpoint URL is required when WHIP is enabled.'));
      }
      elseif (!filter_var($whipUrl, FILTER_VALIDATE_URL)) {
        $form_state->setErrorByName('whip_endpoint_url', $this->t('WHIP endpoint URL must be a valid URL.'));
      }

      $whipVideoBitrate = $form_state->getValue('whip_video_bitrate');
      if (!empty($whipVideoBitrate) && !preg_match('/^\d+[kKmM]?$/', $whipVideoBitrate)) {
        $form_state->setErrorByName('whip_video_bitrate', $this->t('Invalid video bitrate format.'));
      }

      $whipAudioBitrate = $form_state->getValue('whip_audio_bitrate');
      if (!empty($whipAudioBitrate) && !preg_match('/^\d+[kKmM]?$/', $whipAudioBitrate)) {
        $form_state->setErrorByName('whip_audio_bitrate', $this->t('Invalid audio bitrate format.'));
      }
    }

    // Validate RTP settings if enabled.
    if ($form_state->getValue('rtp_enabled')) {
      $rtpHost = $form_state->getValue('rtp_destination_host');
      if (empty($rtpHost)) {
        $form_state->setErrorByName('rtp_destination_host', $this->t('RTP destination host is required when RTP is enabled.'));
      }
      elseif (!filter_var($rtpHost, FILTER_VALIDATE_IP)) {
        $form_state->setErrorByName('rtp_destination_host', $this->t('RTP destination host must be a valid IP address.'));
      }

      $rtpVideoBitrate = $form_state->getValue('rtp_video_bitrate');
      if (!empty($rtpVideoBitrate) && !preg_match('/^\d+[kKmM]?$/', $rtpVideoBitrate)) {
        $form_state->setErrorByName('rtp_video_bitrate', $this->t('Invalid video bitrate format.'));
      }

      $rtpAudioBitrate = $form_state->getValue('rtp_audio_bitrate');
      if (!empty($rtpAudioBitrate) && !preg_match('/^\d+[kKmM]?$/', $rtpAudioBitrate)) {
        $form_state->setErrorByName('rtp_audio_bitrate', $this->t('Invalid audio bitrate format.'));
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  #[\Override]
  public function submitForm(array &$form, FormStateInterface $form_state): void {
    $representations = [];
    $tableValues = $form_state->getValue('representations_table') ?? [];

    foreach ($tableValues as $rep) {
      if (!empty($rep['name'])) {
        $representations[] = [
          'name' => $rep['name'],
          'width' => (int) $rep['width'],
          'height' => (int) $rep['height'],
          'bitrate' => $rep['bitrate'],
          'audio_bitrate' => $rep['audio_bitrate'],
        ];
      }
    }

    // Store bearer token in State API (non-exportable), not in config.
    $bearerToken = $form_state->getValue('whip_bearer_token');
    if (is_string($bearerToken) && $bearerToken !== '') {
      $this->state->set('ffmpeg_media_streaming.whip_bearer_token', $bearerToken);
    }

    $this->config('ffmpeg_media_streaming.settings')
      // HLS settings.
      ->set('hls_segment_duration', (int) $form_state->getValue('hls_segment_duration'))
      ->set('hls_playlist_type', $form_state->getValue('hls_playlist_type'))
      ->set('hls_segment_type', $form_state->getValue('hls_segment_type'))
      ->set('hls_segment_pattern', $form_state->getValue('hls_segment_pattern'))
      ->set('hls_master_playlist', $form_state->getValue('hls_master_playlist'))
      ->set('hls_low_latency', (bool) $form_state->getValue('hls_low_latency'))
      ->set('hls_part_duration', (float) $form_state->getValue('hls_part_duration'))
      // DASH settings.
      ->set('dash_segment_duration', (int) $form_state->getValue('dash_segment_duration'))
      ->set('dash_profile', $form_state->getValue('dash_profile'))
      ->set('dash_min_buffer_time', (float) $form_state->getValue('dash_min_buffer_time'))
      ->set('dash_low_latency', (bool) $form_state->getValue('dash_low_latency'))
      ->set('dash_target_latency', (float) $form_state->getValue('dash_target_latency'))
      ->set('dash_init_segment', $form_state->getValue('dash_init_segment'))
      ->set('dash_media_segment', $form_state->getValue('dash_media_segment'))
      // Representations.
      ->set('representations', $representations)
      ->set('per_title_encoding', (bool) $form_state->getValue('per_title_encoding'))
      // WHIP settings (bearer token stored in State API, not here).
      ->set('whip_enabled', (bool) $form_state->getValue('whip_enabled'))
      ->set('whip_endpoint_url', $form_state->getValue('whip_endpoint_url') ?? '')
      ->set('whip_bearer_token', '')
      ->set('whip_ice_servers', $form_state->getValue('whip_ice_servers') ?? '')
      ->set('whip_video_bitrate', $form_state->getValue('whip_video_bitrate') ?? '2500k')
      ->set('whip_audio_bitrate', $form_state->getValue('whip_audio_bitrate') ?? '128k')
      // RTP settings.
      ->set('rtp_enabled', (bool) $form_state->getValue('rtp_enabled'))
      ->set('rtp_destination_host', $form_state->getValue('rtp_destination_host') ?? '127.0.0.1')
      ->set('rtp_video_port', (int) $form_state->getValue('rtp_video_port'))
      ->set('rtp_audio_port', (int) $form_state->getValue('rtp_audio_port'))
      ->set('rtp_ttl', (int) $form_state->getValue('rtp_ttl'))
      ->set('rtp_generate_sdp', (bool) $form_state->getValue('rtp_generate_sdp'))
      ->set('rtp_video_bitrate', $form_state->getValue('rtp_video_bitrate') ?? '2500k')
      ->set('rtp_audio_bitrate', $form_state->getValue('rtp_audio_bitrate') ?? '128k')
      ->save();

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

  /**
   * Gets default representations for adaptive streaming.
   *
   * @return array<int, array{name: string, width: int, height: int, bitrate: string, audio_bitrate: string}>
   *   Default representation configurations.
   */
  protected function getDefaultRepresentations(): array {
    return [
      [
        'name' => '360p',
        'width' => 640,
        'height' => 360,
        'bitrate' => '800k',
        'audio_bitrate' => '96k',
      ],
      [
        'name' => '720p',
        'width' => 1280,
        'height' => 720,
        'bitrate' => '2500k',
        'audio_bitrate' => '128k',
      ],
      [
        'name' => '1080p',
        'width' => 1920,
        'height' => 1080,
        'bitrate' => '5000k',
        'audio_bitrate' => '192k',
      ],
    ];
  }

}
