import 'dart:async';
import 'dart:io';

import 'package:flutter/services.dart';

import '../../../shared/utils/app_logger.dart';

const _tag = 'AndroidPip';


enum PipAction { play, pause, next, prev, seekForward, seekBackward }


class AndroidPipController {
  static const _methodChannel = MethodChannel('smplayer/pip');
  static const _eventChannel = EventChannel('smplayer/pip_events');

  AndroidPipController._();
  static final AndroidPipController instance = AndroidPipController._();

  StreamController<bool>? _pipModeController;
  StreamController<PipAction>? _actionController;
  StreamSubscription<dynamic>? _eventSub;


  Future<bool> isSupported() async {
    if (!Platform.isAndroid) return false;
    try {
      return (await _methodChannel.invokeMethod<bool>('isSupported')) ?? false;
    } catch (e) {
      AppLogger.warn(_tag, 'isSupported check failed', e);
      return false;
    }
  }


  Future<bool> isInPipMode() async {
    if (!Platform.isAndroid) return false;
    try {
      return (await _methodChannel.invokeMethod<bool>('isInPipMode')) ?? false;
    } catch (e) {
      return false;
    }
  }


  Future<void> configure({
    int aspectX = 16,
    int aspectY = 9,
    bool autoEnterOnLeave = false,
    bool isPlaying = false,
    bool hasNext = false,
    bool hasPrev = false,
    bool useEpisodeActions = true,
  }) async {
    if (!Platform.isAndroid) return;
    try {
      await _methodChannel.invokeMethod<bool>('configure', {
        'aspectX': aspectX,
        'aspectY': aspectY,
        'autoEnterOnLeave': autoEnterOnLeave,
        'isPlaying': isPlaying,
        'hasNext': hasNext,
        'hasPrev': hasPrev,
        'useEpisodeActions': useEpisodeActions,
      });
    } catch (e) {
      AppLogger.warn(_tag, 'configure failed', e);
    }
  }


  Future<bool> enterPip({int? aspectX, int? aspectY}) async {
    if (!Platform.isAndroid) return false;
    try {
      return (await _methodChannel.invokeMethod<bool>('enterPip', {
            'aspectX': aspectX ?? 16,
            'aspectY': aspectY ?? 9,
          })) ??
          false;
    } catch (e) {
      AppLogger.warn(_tag, 'enterPip failed', e);
      return false;
    }
  }


  Future<void> updatePlaybackState({
    required bool isPlaying,
    required bool hasNext,
    required bool hasPrev,
    required bool useEpisodeActions,
  }) async {
    if (!Platform.isAndroid) return;
    try {
      await _methodChannel.invokeMethod<bool>('updatePlaybackState', {
        'isPlaying': isPlaying,
        'hasNext': hasNext,
        'hasPrev': hasPrev,
        'useEpisodeActions': useEpisodeActions,
      });
    } catch (e) {
      AppLogger.warn(_tag, 'updatePlaybackState failed', e);
    }
  }


  Stream<bool> get pipModeChanges {
    _ensureEventListening();
    return (_pipModeController ??= StreamController<bool>.broadcast()).stream;
  }


  Stream<PipAction> get actionStream {
    _ensureEventListening();
    return (_actionController ??= StreamController<PipAction>.broadcast())
        .stream;
  }

  void _ensureEventListening() {
    if (_eventSub != null) return;
    _eventSub = _eventChannel.receiveBroadcastStream().listen(
      (event) {
        if (event is! Map) return;
        final map = event.cast<Object?, Object?>();
        final type = map['type'] as String?;

        if (type == 'modeChanged') {
          final isInPip = map['isInPip'] as bool? ?? false;
          _pipModeController?.add(isInPip);
        } else if (type == 'action') {
          final action = _parseAction(map['action'] as String?);
          if (action != null) {
            _actionController?.add(action);
          }
        }
      },
      onError: (Object e) {
        AppLogger.warn(_tag, 'event stream error', e);
      },
    );
  }

  Future<void> dispose() async {
    final eventSub = _eventSub;
    _eventSub = null;
    await eventSub?.cancel();
    await _pipModeController?.close();
    _pipModeController = null;
    await _actionController?.close();
    _actionController = null;
  }

  PipAction? _parseAction(String? name) => switch (name) {
    'play' => PipAction.play,
    'pause' => PipAction.pause,
    'next' => PipAction.next,
    'prev' => PipAction.prev,
    'seekForward' => PipAction.seekForward,
    'seekBackward' => PipAction.seekBackward,
    _ => null,
  };
}
