import 'package:canvas_danmaku/canvas_danmaku.dart';
import 'package:flutter/foundation.dart' show debugPrint;
import 'package:flutter/material.dart' show Colors;

import '../../../../core/contracts/danmaku.dart';
import '../../../../core/media/danmaku_comment_pipeline.dart';


const double _kBackwardSeekThreshold = -1.0;
const double _kForwardSeekThreshold = 5.0;


const int _kMaxFeedPerTick = 10;


const double _kMaxFeedLagSec = 1.0;

enum DanmakuPlaybackState { detached, disabled, playing, frozen, seeking }

class DanmakuFeeder {
  DanmakuController? _canvas;
  List<DanmakuComment> _comments = const [];
  DanmakuPanelSettings _settings = const DanmakuPanelSettings();
  int _feedIndex = 0;
  double _lastPosSec = -1;
  DanmakuPlaybackState _state = DanmakuPlaybackState.detached;
  double? _frozenPosSec;

  void attach(DanmakuController controller) {
    _canvas = controller;
    _state = _settings.enabled
        ? DanmakuPlaybackState.frozen
        : DanmakuPlaybackState.disabled;
  }

  void detach() {
    _canvas = null;
    _state = DanmakuPlaybackState.detached;
  }


  void setComments(List<DanmakuComment> commentsSortedByTime) {
    _comments = commentsSortedByTime;
    _canvas?.clear();
    _feedIndex = 0;
    _lastPosSec = -1;
    _frozenPosSec = null;
  }

  void setPanelSettings(
    DanmakuPanelSettings settings, {
    DanmakuOption? option,
  }) {
    _settings = settings;
    if (!_settings.enabled) {
      _state = DanmakuPlaybackState.disabled;
    } else if (_state == DanmakuPlaybackState.disabled) {
      _state = _canvas == null
          ? DanmakuPlaybackState.detached
          : DanmakuPlaybackState.frozen;
    }
    if (option != null) {
      try {
        _canvas?.updateOption(option);
      } catch (e) {
        debugPrint('[DanmakuFeeder] updateOption failed: $e; detaching canvas');
        _canvas = null;
        _state = DanmakuPlaybackState.detached;
      }
    }
  }


  void onPosition(double posSec) {
    final canvas = _canvas;
    if (canvas == null ||
        _comments.isEmpty ||
        !_settings.enabled ||
        _state != DanmakuPlaybackState.playing) {
      return;
    }
    final effectivePos = posSec - _settings.offset;
    final last = _lastPosSec;
    if (last >= 0 && _isTimelineJump(posSec - last)) {
      canvas.clear();
      _feedIndex = lowerBoundByTime(_comments, effectivePos);
    }
    _lastPosSec = posSec;

    var fedThisTick = 0;
    while (_feedIndex < _comments.length && fedThisTick < _kMaxFeedPerTick) {
      final comment = _comments[_feedIndex];
      if (comment.time > effectivePos) break;
      _feedIndex++;
      if (effectivePos - comment.time > _kMaxFeedLagSec) continue;
      canvas.addDanmaku(_toContentItem(comment));
      fedThisTick++;
    }
  }

  void freezeAt(double posSec) {
    final canvas = _canvas;
    if (canvas == null) {
      _state = DanmakuPlaybackState.detached;
      return;
    }
    if (!_settings.enabled) {
      _state = DanmakuPlaybackState.disabled;
      return;
    }
    _state = DanmakuPlaybackState.frozen;
    _frozenPosSec = posSec;
    _lastPosSec = posSec;
    if (canvas.running) {
      canvas.pause();
    }
  }

  void playFrom(double posSec) {
    final canvas = _canvas;
    if (canvas == null) {
      _state = DanmakuPlaybackState.detached;
      return;
    }
    if (!_settings.enabled) {
      _state = DanmakuPlaybackState.disabled;
      return;
    }
    final frozenPos = _frozenPosSec;
    if (_state == DanmakuPlaybackState.frozen &&
        frozenPos != null &&
        posSec > frozenPos) {
      final targetIndex = lowerBoundByTime(
        _comments,
        posSec - _settings.offset,
      );
      if (targetIndex > _feedIndex) {
        _feedIndex = targetIndex;
      }
    }
    _lastPosSec = posSec;
    _frozenPosSec = null;
    _state = DanmakuPlaybackState.playing;
    if (!canvas.running) {
      canvas.resume();
    }
  }

  void seekTo(double posSec, {bool clear = true}) {
    if (clear) _canvas?.clear();
    _feedIndex = lowerBoundByTime(_comments, posSec - _settings.offset);
    _lastPosSec = posSec;
    _frozenPosSec = null;
    if (_canvas == null) {
      _state = DanmakuPlaybackState.detached;
    } else {
      _state = _settings.enabled
          ? DanmakuPlaybackState.seeking
          : DanmakuPlaybackState.disabled;
    }
  }

  bool _isTimelineJump(double deltaSec) {
    return deltaSec < _kBackwardSeekThreshold ||
        deltaSec > _kForwardSeekThreshold;
  }

  DanmakuContentItem _toContentItem(DanmakuComment c) {
    final baseColor = _settings.colored ? c.color : Colors.white;


    final opacity = _settings.opacity.clamp(0.0, 1.0);
    final color = opacity >= 1.0
        ? baseColor
        : baseColor.withValues(alpha: opacity);
    return DanmakuContentItem(
      c.text,
      color: color,
      type: switch (c.type) {
        4 when !_settings.fixedToScroll => DanmakuItemType.bottom,
        5 when !_settings.fixedToScroll => DanmakuItemType.top,
        _ => DanmakuItemType.scroll,
      },
    );
  }
}
