import 'dart:async';
import 'dart:math' as math;

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

import '../../../core/contracts/playback.dart';
import '../../../core/infra/player_engine/player_engine.dart';
import '../../../providers/subtitle_settings_provider.dart';


class StyledSubtitleOverlay extends StatefulWidget {
  final PlayerEngine player;
  final SubtitleStyleSettings settings;


  final ValueListenable<List<String>>? externalLines;


  final ValueListenable<EmbySubtitleTrack?>? externalActive;

  const StyledSubtitleOverlay({
    super.key,
    required this.player,
    required this.settings,
    this.externalLines,
    this.externalActive,
  });

  @override
  State<StyledSubtitleOverlay> createState() => _StyledSubtitleOverlayState();
}

class _StyledSubtitleOverlayState extends State<StyledSubtitleOverlay> {
  static const _mpvReferenceHeight = 720.0;
  static const _baseEdgeInset = 24.0;

  List<String> _subtitle = const [];
  StreamSubscription<List<String>>? _subscription;

  @override
  void initState() {
    super.initState();
    _bindPlayer(widget.player);
    widget.externalLines?.addListener(_onExternalChanged);
    widget.externalActive?.addListener(_onExternalChanged);
  }

  @override
  void didUpdateWidget(covariant StyledSubtitleOverlay oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.player != widget.player) {
      unawaited(_subscription?.cancel());
      _bindPlayer(widget.player);
    }
    if (oldWidget.externalLines != widget.externalLines) {
      oldWidget.externalLines?.removeListener(_onExternalChanged);
      widget.externalLines?.addListener(_onExternalChanged);
    }
    if (oldWidget.externalActive != widget.externalActive) {
      oldWidget.externalActive?.removeListener(_onExternalChanged);
      widget.externalActive?.addListener(_onExternalChanged);
    }
  }

  @override
  void dispose() {
    unawaited(_subscription?.cancel());
    widget.externalLines?.removeListener(_onExternalChanged);
    widget.externalActive?.removeListener(_onExternalChanged);
    super.dispose();
  }

  void _bindPlayer(PlayerEngine player) {
    _subtitle = player.state.subtitle;
    _subscription = player.stream.subtitle.listen((value) {
      if (mounted) setState(() => _subtitle = value);
    });
  }

  void _onExternalChanged() {
    if (mounted) setState(() {});
  }

  bool get _externalIsActive => widget.externalActive?.value != null;

  List<String> get _activeLines =>
      _externalIsActive ? (widget.externalLines?.value ?? const []) : _subtitle;

  @override
  Widget build(BuildContext context) {
    final primaryText = _joinLines(_activeLines);
    if (primaryText.isEmpty) {
      return const SizedBox.shrink();
    }

    return IgnorePointer(
      child: LayoutBuilder(
        builder: (context, constraints) {
          final width = constraints.maxWidth;
          final height = constraints.maxHeight;
          if (!width.isFinite ||
              !height.isFinite ||
              width <= 0 ||
              height <= 0) {
            return const SizedBox.shrink();
          }

          final fontSize = _scaleFontSize(widget.settings.fontSize, height);

          final position = widget.settings.position.clamp(0, 150).toDouble();
          final verticalProgress = math.min(position, 100.0) / 100.0;
          final extraLowering = math.max(0.0, position - 100.0) / 50.0;
          final bottomInset =
              _baseEdgeInset * (1.0 - extraLowering.clamp(0.0, 1.0));

          final lineCount = math.max(1, primaryText.split('\n').length);
          final estimatedBlockHeight = math.min(
            height * 0.5,
            lineCount * fontSize * 1.32 + 12.0,
          );

          final verticalRange = math.max(
            0.0,
            height - _baseEdgeInset - bottomInset - estimatedBlockHeight,
          );
          final top = _baseEdgeInset + verticalRange * verticalProgress;
          final horizontalInset = math.min(_baseEdgeInset, width * 0.06);

          return Stack(
            fit: StackFit.expand,
            children: [
              Positioned(
                left: horizontalInset,
                right: horizontalInset,
                top: top,
                child: _buildLine(
                  text: primaryText,
                  fontSize: fontSize,
                  bgOpacity: widget.settings.bgOpacity.clamp(0.0, 1.0),
                ),
              ),
            ],
          );
        },
      ),
    );
  }

  String _joinLines(List<String> lines) => lines
      .map((line) => line.trim())
      .where((line) => line.isNotEmpty)
      .join('\n');

  double _scaleFontSize(double settingsFontSize, double height) =>
      (settingsFontSize * height / _mpvReferenceHeight).clamp(8.0, 200.0);

  Widget _buildLine({
    required String text,
    required double fontSize,
    required double bgOpacity,
  }) {
    final child = Text(
      text,
      textAlign: TextAlign.center,
      softWrap: true,
      textScaler: TextScaler.noScaling,
      style: TextStyle(
        color: Colors.white,
        fontSize: fontSize,
        height: 1.32,
        letterSpacing: 0.0,
        fontWeight: FontWeight.w600,
        shadows: const [
          Shadow(color: Colors.black, blurRadius: 2, offset: Offset(0, 1)),
          Shadow(color: Colors.black87, blurRadius: 4),
        ],
      ),
    );

    if (bgOpacity > 0) {
      return DecoratedBox(
        decoration: BoxDecoration(
          color: Colors.black.withOpacity(bgOpacity),
          borderRadius: BorderRadius.circular(4),
        ),
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
          child: child,
        ),
      );
    }
    return child;
  }
}
