

part of 'player_page.dart';


bool _isDanmakuLayoutChange(DanmakuPanelSettings a, DanmakuPanelSettings b) {
  return a.maxRows != b.maxRows ||
      a.fontSize != b.fontSize ||
      a.lineHeight != b.lineHeight ||
      a.fontFamily != b.fontFamily ||
      a.area != b.area;
}

void _syncDanmakuFeederForSession(
  DanmakuFeeder feeder,
  PlaybackSession session,
  double posSec, {
  bool clear = false,
}) {
  feeder.seekTo(posSec, clear: clear);
  if (session.isDanmakuActive) {
    feeder.playFrom(posSec);
  } else {
    feeder.freezeAt(posSec);
  }
}

extension _PlayerPageDanmaku on _PlayerPageState {
  DanmakuOption _buildDanmakuOption(DanmakuPanelSettings settings) {
    final base = settings.toDanmakuOption(screenHeight: _danmakuOverlayHeight);
    if (_playbackRate == 1.0 || _playbackRate <= 0) return base;
    return base.copyWith(duration: base.duration / _playbackRate);
  }

  void _applyDanmakuPanelSettings(DanmakuPanelSettings settings) {
    _panelSettings = settings;
    _feeder.setPanelSettings(settings, option: _buildDanmakuOption(settings));
  }


  void _wireDanmakuListeners() {
    final session = ref.read(danmakuSessionProvider).value;
    if (session != null) {
      _sessionState = session;
      if (session is DanmakuSessionMatched &&
          session.commentStatus == DanmakuCommentStatus.ready &&
          !identical(session, _lastSyncedDanmakuSession)) {
        _lastSyncedDanmakuSession = session;
        _feeder.setComments(session.comments);
        final s = _session;
        if (s != null) {
          _syncDanmakuFeederForSession(
            _feeder,
            s,
            s.engine.state.position.inMilliseconds / 1000.0,
          );
        }
      }
    }
    final settingsPanel = ref
        .read(danmakuSettingsProvider)
        .value
        ?.panelSettings;
    if (settingsPanel != null && settingsPanel != _panelSettings) {
      _applyDanmakuPanelSettings(settingsPanel);
    }

    ref.listen<AsyncValue<DanmakuSessionState>>(danmakuSessionProvider, (
      prev,
      next,
    ) {
      final state = next.value;
      if (state == null) return;
      _sessionState = state;

      if (state is DanmakuSessionMatched &&
          state.commentStatus == DanmakuCommentStatus.ready) {
        _lastSyncedDanmakuSession = state;
        _feeder.setComments(state.comments);
        final s = _session;
        if (s != null) {
          final posSec = s.engine.state.position.inMilliseconds / 1000.0;
          _syncDanmakuFeederForSession(_feeder, s, posSec);
        }
      } else {
        _lastSyncedDanmakuSession = null;
        _feeder.setComments(const []);
      }

      _invalidateBottomBar();
      _refreshPanel();
      _invalidateDanmakuOverlay();
    });

    ref.listen<AsyncValue<DanmakuSettingsState>>(danmakuSettingsProvider, (
      prev,
      next,
    ) {
      final settings = next.value;
      if (settings == null) return;
      final newPanel = settings.panelSettings;
      final oldPanel = _panelSettings;
      final panelChanged = oldPanel != newPanel;
      final previousSettings = prev?.value;
      final keywordsChanged =
          previousSettings != null &&
          !listEquals(
            previousSettings.blockedKeywords,
            settings.blockedKeywords,
          );

      final enabledChanged = oldPanel.enabled != newPanel.enabled;
      final offsetChanged = oldPanel.offset != newPanel.offset;
      final layoutChanged = _isDanmakuLayoutChange(oldPanel, newPanel);


      final opacityChanged = oldPanel.opacity != newPanel.opacity;
      if (panelChanged) {
        _applyDanmakuPanelSettings(newPanel);
        if (enabledChanged) {
          _invalidateBottomBar();
        }
        _invalidateDanmakuOverlay();
        final s = _session;
        if ((enabledChanged ||
                offsetChanged ||
                layoutChanged ||
                opacityChanged) &&
            s != null) {
          final posSec = s.engine.state.position.inMilliseconds / 1000.0;
          _syncDanmakuFeederForSession(_feeder, s, posSec, clear: true);
        }
      }
      if (panelChanged || keywordsChanged) {
        _refreshPanel();
      }
    });
  }

  bool get _danmakuLoaded =>
      _sessionState is DanmakuSessionMatched ||
      _sessionState is DanmakuSessionEmpty;

  bool get _danmakuSearching =>
      _sessionState is DanmakuSessionMatching ||
      (_sessionState is DanmakuSessionMatched &&
          (_sessionState as DanmakuSessionMatched).commentStatus ==
              DanmakuCommentStatus.loading);

  List<DanmakuMatchCandidate> get _danmakuMatches {
    final s = _sessionState;
    return s is DanmakuSessionMatched ? s.matches : const [];
  }

  int get _danmakuSelectedMatchIndex {
    final s = _sessionState;
    return s is DanmakuSessionMatched ? s.selectedIndex : -1;
  }

  int get _danmakuCommentCount {
    final s = _sessionState;
    return s is DanmakuSessionMatched ? s.comments.length : 0;
  }
}
