import 'dart:async';
import 'dart:typed_data';
import 'dart:math' as math;
import 'package:fis_common/event/event_type.dart';
import 'package:fis_common/logger/logger.dart';
import 'package:fis_lib_media_rt/implementations/nt_rtmp/values.dart';
import 'package:flutter/material.dart';
import 'dart:convert';

class ShellCameraPlayController {
  static bool _playing = false;

  /// 拉流地址
  final String url;

  final int width;

  final int height;

  /// 事件 - 收到缓冲片段
  static final bufferFragmentReceived = FEventHandler<Uint8List>();

  ShellCameraPlayController(
    this.url, {
    this.width = 640,
    this.height = 480,
  });

  Future<void> init() {
    return Future(() => null);
  }

  /// 播放
  void play() {
    if (_playing) return;
    _playing = true;

    logger.i("$TAG - ShellCamera start");
  }

  static void setPreviewImageData(String imageData) {
    try {
      if (_playing) {
        var data = base64Decode(imageData);
        bufferFragmentReceived.emit("shell_camera", data);
      } else {
        logger
            .e("refresh camera preview failed since publish already stopped!");
      }
    } catch (e) {
      logger.e("Camera review error", e);
    }
  }

  /// 停止
  void stop() {
    _playing = false;

    logger.i("$TAG - ShellCamera stop");
  }
}

class ShellCameraPlayer extends StatefulWidget {
  final ShellCameraPlayController controller;

  const ShellCameraPlayer({super.key, required this.controller});

  @override
  State<StatefulWidget> createState() => _ShellCameraPlayerState();
}

class _ShellCameraPlayerState extends State<ShellCameraPlayer> {
  static const int _RETRY_LIMIT = 10;
  Uint8List? _frameBuffer;
  late Uint8List _bufferArea;
  int _bufferPosition = 0;
  bool _hasError = false;
  int _rgbaSize = 0;
  int _retryCount = 0;

  @override
  void initState() {
    super.initState();

    _rgbaSize = 4 * widget.controller.width * widget.controller.height;
    _bufferArea = Uint8List(_rgbaSize);
    WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      ShellCameraPlayController.bufferFragmentReceived.addListener(_onBuffer);
    });
  }

  @override
  void dispose() {
    ShellCameraPlayController.bufferFragmentReceived.removeListener(_onBuffer);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    Widget child;
    if (_hasError) {
      child = const Center(
        child: Text("Error", style: TextStyle(color: Colors.white)),
      );
    } else if (_frameBuffer != null) {
      child = Image.memory(
        _frameBuffer!,
        fit: BoxFit.contain,
        gaplessPlayback: true,
      );
      // 水平翻转
      child = Transform(
        alignment: Alignment.center,
        transform: Matrix4.rotationY(math.pi),
        child: child,
      );
    } else {
      child = const SizedBox();
    }

    return Container(
      color: Colors.black,
      child: child,
    );
  }

  void _onBufferOnce(Object sender, Uint8List e) {
    // _bufferArea.setAll(_bufferPosition, e);
    // _bufferPosition += e.length;

    // if (_bufferPosition < 8) {
    //   // 已缓冲数据长度 不够读取帧长度
    //   return;
    // }

    // final frameSize = readInt64V2(_bufferArea);
    // final onceSize = 8 + frameSize;

    // if (_bufferPosition < onceSize) {
    //   // 已缓冲数据 不够读取下一帧
    //   return;
    // }

    // 提取帧数据
    // final frameData = Uint8List(frameSize);
    // frameData.setAll(0, _bufferArea.skip(8).take(frameSize));

    // _bufferPosition -= onceSize;
    //  logger.i("_ShellCameraPlayerState ")
    // if (mounted) {
    //   setState(() {
    //     _frameBuffer = frameData;
    //   });
    // }

    // if (_bufferPosition > 0) {
    //   // // 剩余未读数据，重新往索引0开始写
    //   // final left = _bufferArea.skip(onceSize).take(_bufferPosition);
    //   // _bufferArea.setAll(0, left);

    //   // 丢弃来不及处理的帧，一直追最新帧
    //   _abandonBufferedFrames(onceSize);
    // }
    setState(() {
      _frameBuffer = e;
    });
  }

  // void _abandonBufferedFrames(int preFrameSize) {
  //   int abandonSize = preFrameSize;
  //   while (true) {
  //     if (_bufferPosition < 8) return;

  //     final frameSize = readInt64V2(_bufferArea);
  //     final onceSize = 8 + frameSize;

  //     if (_bufferPosition < onceSize) {
  //       break;
  //     }

  //     abandonSize += onceSize;
  //     _bufferPosition -= onceSize;
  //   }
  //   logger.i("$TAG - ShellCamera Skip frames, buffer size: $abandonSize");
  //   _restoreBufferAt(abandonSize);
  // }

  // void _restoreBufferAt(int index) {
  //   final left = _bufferArea.skip(index).take(_bufferPosition);
  //   _bufferArea.setAll(0, left);
  // }

  void _onBuffer(Object sender, Uint8List e) {
    try {
      _onBufferOnce(sender, e);
    } catch (e) {
      _handleError();
    }
  }

  void _handleError() {
    widget.controller.stop();

    if (_retryCount > _RETRY_LIMIT) {
      setState(() {
        _hasError = true;
      });
    }

    Future.delayed(const Duration(milliseconds: 800), () {
      widget.controller.play();
    });
    _retryCount++;
  }

  static int readInt64(Uint8List data, [int index = 0]) {
    var intData = data.buffer.asByteData(index, 8);
    return intData.getInt64(0, Endian.little);
  }

  static int readInt64V2(Uint8List data, [int index = 0]) {
    int low = readInt(data, index);
    int high = readInt(data, index + 4);
    int value = high >> 32;
    value |= low;
    return value;
  }

  static int readInt(Uint8List data, [int index = 0]) {
    var intData = data.buffer.asByteData(index, 4);
    return intData.getInt32(0, Endian.little);
  }
}
