part of 'url_bloc.dart';

typedef UrlStateIndexedEventCreator = UrlEvent Function(int index);
typedef UrlStateStringEventCreator = UrlEvent Function(String value);

enum UIType { list, input, listWithInput }

/// Состояние по умолчанию
@immutable
class UrlState {
  final String title;
  final Key key;
  final List<OptionData> options;
  final String? visibleUrlPath;
  final String? urlPath;
  final bool? isLive;
  final int? initialIndex;
  final int? currentIndex;
  final UrlState? parent;
  final bool isFinal;
  final UIType uiType;
  final UrlStateIndexedEventCreator? createIndexedEvent;
  final UrlStateStringEventCreator? createStringEvent;

  const UrlState({
    required this.title,
    required this.key,
    this.options = const [],
    this.visibleUrlPath,
    this.urlPath,
    this.isLive,
    this.initialIndex,
    this.currentIndex,
    this.parent,
    this.isFinal = false,
    required this.uiType,
    this.createIndexedEvent,
    this.createStringEvent
  });

  factory UrlState.create() {
    return UrlState(
      title: '1. Выберите вариант загрузки видео',
      key: const Key('ChooseWayToLoadVideoListID'),
      options: const [
        OptionData(key: Key('ListElementExampleID'), title: 'Использовать пример'),
        OptionData(key: Key('ListElementUrlID'), title: 'Загрузить по ссылке')
      ],
      uiType: UIType.list,
      createIndexedEvent: (index) => ChooseWayToLoadVideoEvent(index),
    );
  }
}

/// Состояние, когда выбран пункт "Использовать пример"
class UseExampleChosenOptionState extends UrlState {
  const UseExampleChosenOptionState(
      String title,
      Key key,
      List<OptionData> options,
      String? urlPath,
      bool? isLive,
      int? initialIndex,
      int? currentIndex,
      UrlState? parent,
      bool isFinal,
      UIType uiType,
      UrlStateIndexedEventCreator? createIndexedEvent
  ): super(
      title: title,
      key: key,
      options: options,
      urlPath: urlPath,
      isLive: isLive,
      initialIndex: initialIndex,
      currentIndex: currentIndex,
      parent: parent,
      isFinal: isFinal,
      uiType: uiType,
      createIndexedEvent: createIndexedEvent
  );

  factory UseExampleChosenOptionState.create(UrlState? parent, int? selectedIndex) {
    var options = const [
      OptionData(key: Key('ListElementUrl1ID'), title: 'HLS VOD', value: 'https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8'),
      OptionData(key: Key('ListElementUrl2ID'), title: 'HLS LIVE', value: 'https://cph-p2p-msl.akamaized.net/hls/live/2000341/test/master.m3u8', isLive: true),
      OptionData(key: Key('ListElementUrl3ID'), title: 'MP4 (4K)', value: 'https://filesamples.com/samples/video/mp4/sample_3840x2160.mp4'),
      OptionData(key: Key('ListElementUrl4ID'), title: 'MP4 (1440p)', value: 'https://filesamples.com/samples/video/mp4/sample_2560x1440.mp4'),
      OptionData(key: Key('ListElementUrl5ID'), title: 'MP4 (1080p)', value: 'https://filesamples.com/samples/video/mp4/sample_1920x1080.mp4'),
      OptionData(key: Key('ListElementUrl6ID'), title: 'MP4 (720р)', value: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4'),
      OptionData(key: Key('ListElementUrl7ID'), title: 'MP4 (360p)', value: 'https://filesamples.com/samples/video/mp4/sample_640x360.mp4'),
      OptionData(key: Key('ListElementUrl8ID'), title: 'MP4 (144р)', value: 'https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4'),
      OptionData(key: Key('ListElementUrl9ID'), title: 'MP4 (более 10 часов)', value: 'https://cloud.nut.tech/index.php/s/TgFkebRSs3A9i3r/download/Гендальф_10_часовая_версия_Gandalf_10_hour_version.mp4')
    ];

    final String? currentUrlPath;
    final bool? isLive;
    if (selectedIndex != null) {
      currentUrlPath = options[selectedIndex].value;
      isLive = options[selectedIndex].isLive;
    } else {
      currentUrlPath = null;
      isLive = null;
    }

    return UseExampleChosenOptionState(
        '2. Выберите пример видео',
        const Key('ChooseWayToGetUrlListID'),
        options,
        currentUrlPath,
        isLive,
        0,
        selectedIndex,
        parent,
        (selectedIndex != null),
        UIType.list,
        (index) => ChooseExampleVideoEvent(index)
    );
  }
}

/// Состояние, когда выбран пункт "Загрузить по ссылке"
class LoadWithLinkChosenOptionState extends UrlState {
  const LoadWithLinkChosenOptionState(
      String title,
      Key key,
      List<OptionData> options,
      int? initialIndex,
      UrlState? parent,
      UIType uiType,
      UrlStateIndexedEventCreator? createIndexedEvent
  ): super(
      title: title,
      key: key,
      options: options,
      initialIndex: initialIndex,
      parent: parent,
      uiType: uiType,
      createIndexedEvent: createIndexedEvent
  );

  factory LoadWithLinkChosenOptionState.create(UrlState? parent) {
    return LoadWithLinkChosenOptionState(
        '2. Выберите способ получения ссылки',
        const Key('ChooseWayToGetLinkListID'),
        const [
          OptionData(key: Key('ListElementUseUrlID'), title: 'Указать ссылку'),
          OptionData(key: Key('ListElementExtraOptionsID'), title: 'Использовать доп. опции')
        ],
        1,
        parent,
        UIType.list,
        (index) => ChooseWayToGetLinkEvent(index)
    );
  }
}

/// Состояние, когда выбран пункт "Указать ссылку"
class UseOwnLinkState extends UrlState {
  const UseOwnLinkState(
      String title,
      Key key,
      String? urlPath,
      bool? isLive,
      int? initialIndex,
      UrlState? parent,
      bool isFinal,
      UIType uiType,
      UrlStateStringEventCreator? createStringEvent
  ): super(
      title: title,
      key: key,
      urlPath: urlPath,
      isLive: isLive,
      initialIndex: initialIndex,
      parent: parent,
      isFinal: isFinal,
      visibleUrlPath: urlPath,
      uiType: uiType,
      createStringEvent: createStringEvent
  );

  factory UseOwnLinkState.create(UrlState? parent, String? urlPath, {bool isLive = false}) {
    var finalUrlPath = urlPath ?? 'https://cloud.nut.tech/index.php/s/iY3KtaL7bekWnwM/download/IMG_3059.MP4';
    return UseOwnLinkState(
        '3. Вставьте ссылку',
        const Key('TypeOwnUrlViewID'),
        finalUrlPath,
        isLive,
        0,
        parent,
        finalUrlPath.isNotEmpty,
        UIType.input,
        (value) => TypeOwnLinkEvent(value)
    );
  }
}

/// Состояние, когда выбран пункт "Использовать доп. опции"
class ChooseExtraOptionsState extends UrlState {
  const ChooseExtraOptionsState(
      String title,
      Key key,
      List<OptionData> options,
      int? initialIndex,
      UrlState? parent,
      UIType uiType,
      UrlStateIndexedEventCreator? createIndexedEvent
  ): super(
      title: title,
      key: key,
      options: options,
      initialIndex: initialIndex,
      parent: parent,
      uiType: uiType,
      createIndexedEvent: createIndexedEvent
  );

  factory ChooseExtraOptionsState.create(UrlState? parent) {
    return ChooseExtraOptionsState(
        '3. Выберите дополнительные опции',
        const Key('ChooseExtraOptionsListID'),
        const [
          OptionData(key: Key('ListElementNoFormatOptionID'), title: 'Ссылка без расширения'),
          OptionData(key: Key('ListElementJSONFileID'), title: 'JSON-файл для MP4')
        ],
        1,
        parent,
        UIType.list,
        (index) => ChooseExtraOptionsEvent(index)
    );
  }
}

/// Состояние, когда выбран пункт "Ссылка без расширения"
class UseOwnLinkWithoutFormat extends UrlState {
  const UseOwnLinkWithoutFormat(
      String title,
      Key key,
      List<OptionData> options,
      String? urlPath,
      String? visibleUrlPath,
      int? initialIndex,
      int? currentIndex,
      UrlState? parent,
      bool isFinal,
      UIType uiType,
      UrlStateIndexedEventCreator? createIndexedEvent,
      UrlStateStringEventCreator? createStringEvent
  ): super(
      title: title,
      key: key,
      options: options,
      urlPath: urlPath,
      visibleUrlPath: visibleUrlPath,
      initialIndex: initialIndex,
      currentIndex: currentIndex,
      parent: parent,
      isFinal: isFinal,
      uiType: uiType,
      createIndexedEvent: createIndexedEvent,
      createStringEvent: createStringEvent
  );

  factory UseOwnLinkWithoutFormat.create(UrlState? parent, String? urlPath, int? selectedIndex) {
    var options = const [
      OptionData(key: Key('ListElementFormat1ID'), title: 'MP4', value: '.mp4'),
      OptionData(key: Key('ListElementFormat3ID'), title: 'M3U8', value: '.m3u8')
    ];

    var visibleUrlPath = _removeFormatIfNeeded(urlPath) ?? 'https://cloud.nut.tech/index.php/s/iY3KtaL7bekWnwM/download/IMG_3059';
    var currentSelectedIndex = selectedIndex ?? 0;
    var finalUrlPath = "$visibleUrlPath${options[currentSelectedIndex].value}";

    return UseOwnLinkWithoutFormat(
        '4. Вставьте ссылку и выберите формат видео',
        const Key('UseOwnLinkWithoutFormatListID'),
        options,
        finalUrlPath,
        visibleUrlPath,
        0,
        currentSelectedIndex,
        parent,
        finalUrlPath.isNotEmpty,
        UIType.listWithInput,
        (index) => ChooseVideoFormatEvent(index),
        (value) => TypeOwnLinkWithoutFormatEvent(value)
    );
  }
  
  static String? _removeFormatIfNeeded(String? urlPath) {
    if (urlPath != null && urlPath.endsWith('.mp4')) {
      return urlPath.replaceAll(RegExp('.mp4'), '');
    } else if (urlPath != null && urlPath.endsWith('.m3u8')) {
      return urlPath.replaceAll(RegExp('.m3u8'), '');
    } else {
      return urlPath;
    }
  }
}

/// Состояние, когда выбран пункт "JSON-файл для MP4"
class ChooseJsonFileState extends UrlState {
  const ChooseJsonFileState(
      String title,
      Key key,
      List<OptionData> options,
      int? initialIndex,
      int? currentIndex,
      UrlState? parent,
      bool isFinal,
      UIType uiType,
      UrlStateIndexedEventCreator? createIndexedEvent
  ): super(
      title: title,
      key: key,
      options: options,
      initialIndex: initialIndex,
      currentIndex: currentIndex,
      parent: parent,
      isFinal: isFinal,
      uiType: uiType,
      createIndexedEvent: createIndexedEvent
  );

  factory ChooseJsonFileState.create(UrlState? parent, int? selectedIndex) {
    return ChooseJsonFileState(
        '4. Выберите файл конфигурации',
        const Key('ChooseConfigFileListID'),
        const [
            OptionData(key: Key('ListElementConfig1ID'), title: 'Config 1'),
            OptionData(key: Key('ListElementConfig2ID'), title: 'Config 2'),
            OptionData(key: Key('ListElementConfig3ID'), title: 'Config 3'),
            OptionData(key: Key('ListElementConfig4ID'), title: 'Config 4')
        ],
        1,
        selectedIndex,
        parent,
        // TODO: Пока не реализовано
        false,//selectedIndex != null,
        UIType.list,
        (index) => ChooseConfigFileEvent(index)
    );
  }
}