import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flyinsono/managers/interfaces/entities/single_frame_params.dart';
import 'package:flyinsono/managers/interfaces/entities/vidImage_parameters.dart';
import 'package:flyinsono/managers/interfaces/local_rtmp.dart';
import 'package:flyinsono/rpc.dart';
import 'package:get/get.dart';
import 'package:flutter/services.dart';
import 'package:vid/us/vid_us_image_data.dart';

class VideoFrameWidget extends StatefulWidget {
  @override
  _VideoFrameWidgetState createState() => _VideoFrameWidgetState();
}

class _VideoFrameWidgetState extends State<VideoFrameWidget> {
  Uint8List? _currentFrame;
  String? _coverImageUrl;
  int? _currentFrameWidth;
  int? _currentFrameHeight;
  bool _isRecording = false;
  int recordSize = 0;
  String? _recordImageCode;
  DateTime? _startRecordingTime;
  VidUsImageData? _imageData;
  final localRtmpManager = Get.find<ILocalRtmpManager>();
  final StreamController<Uint8List> _streamController =
      StreamController<Uint8List>();

  @override
  void initState() {
    localRtmpManager.onSingleFrameImageReceive
        .addListener(onSingleFrameImageReceive);
    localRtmpManager.onCaptureFrame.addListener(onCaptureFrame);
    localRtmpManager.onRecord.addListener(onRecord);
    super.initState();
  }

  @override
  void dispose() {
    localRtmpManager.onSingleFrameImageReceive
        .removeListener(onSingleFrameImageReceive);
    localRtmpManager.onCaptureFrame.removeListener(onCaptureFrame);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Center(
      child: StreamBuilder<Uint8List>(
        stream: _streamController.stream,
        builder: (BuildContext context, AsyncSnapshot<Uint8List> snapshot) {
          if (snapshot.hasData) {
            return Center(
              child: Image.memory(
                snapshot.data!,
                fit: BoxFit.contain,
                gaplessPlayback: true,
              ),
            );
          } else if (snapshot.hasError) {
            return Center(
              child: Text('Error: ${snapshot.error}'),
            );
          } else {
            return Center(
              child: CircularProgressIndicator(),
            );
          }
        },
      ),
    );
  }

  void onSingleFrameImageReceive(Object sender, SingleFrameParams e) {
    _currentFrame = e.bytes;
    _currentFrameWidth = e.width;
    _currentFrameHeight = e.height;
    _streamController.add(e.bytes);
    if (_isRecording) {
      _imageData!.addJpegImage(e.bytes, e.width, e.height);
      recordSize += e.bytes.length;
    }
  }

  Future<void> onCaptureFrame(Object sender, bool e) async {
    if (_currentFrame != null) {
      final String imageCode = DateTime.now().millisecondsSinceEpoch.toString();
      print(imageCode);
      localRtmpManager.onUploadImage.emit(
        this,
        VidImageParameters(
          code: imageCode,
          corverImage: "",
          previewImage: "",
          vidImage: "",
        ),
      );
      _imageData = VidUsImageData.empty(1, VidUsImageFormat.Jpeg);
      final String sourceFileName = "$imageCode.vid";
      final String coverFileName = "$imageCode-cover.jpg";
      _imageData!.addJpegImage(
          _currentFrame!, _currentFrameWidth!, _currentFrameHeight!);
      final corverImageUrl =
          await rpc.storage.uploadUint8List(_currentFrame!, coverFileName) ??
              '';
      var imageDatas = _imageData!.flush();
      final fileToken =
          await rpc.storage.uploadUint8List(imageDatas, sourceFileName) ?? '';
      localRtmpManager.onUploadImage.emit(
        this,
        VidImageParameters(
          code: imageCode,
          corverImage: corverImageUrl,
          previewImage: corverImageUrl,
          vidImage: fileToken,
          size: imageDatas.length,
        ),
      );
    }
  }

  Future<void> onRecord(Object sender, bool isStart) async {
    if (isStart) {
      _recordImageCode = DateTime.now().millisecondsSinceEpoch.toString();
      print(_recordImageCode);
      final String coverFileName = "$_recordImageCode-cover.jpg";
      recordSize = 0;
      _imageData = VidUsImageData.empty(10, VidUsImageFormat.Jpeg);
      _startRecordingTime = DateTime.now();
      if (_currentFrame != null) {
        _imageData!.addJpegImage(
            _currentFrame!, _currentFrameWidth!, _currentFrameHeight!);
        _coverImageUrl =
            await rpc.storage.uploadUint8List(_currentFrame!, coverFileName) ??
                '';
        recordSize += _currentFrame!.length;
      }
      _isRecording = true;
    } else {
      _isRecording = false;
      localRtmpManager.onUploadImage.emit(
        this,
        VidImageParameters(
          code: _recordImageCode!,
          corverImage: "",
          previewImage: "",
          vidImage: "",
        ),
      );
      var difference = DateTime.now().difference(_startRecordingTime!);
      var seconds = difference.inSeconds;
      int frameRate = (_imageData!.imageCount / seconds).round();
      _imageData!.setThirdPartFPS(frameRate);
      var imageDatas = _imageData!.flush();
      final String sourceFileName = "$_recordImageCode.vid";
      final fileToken =
          await rpc.storage.uploadUint8List(imageDatas, sourceFileName) ?? '';
      localRtmpManager.onUploadImage.emit(
          this,
          VidImageParameters(
            code: _recordImageCode!,
            corverImage: _coverImageUrl!,
            previewImage: _coverImageUrl!,
            vidImage: fileToken,
            isVideo: true,
            size: imageDatas.length,
          ));
      recordSize = 0;
      _recordImageCode = null;
    }
  }
}
