import 'dart:async';
import 'dart:isolate';
import 'dart:typed_data';
import 'package:async/async.dart' as async;
import 'dart:ui' as ui;
import 'package:image/image.dart' as img;

class JpegConvertThread {
  ReceivePort? _receivePort;
  SendPort? _sendPort;
  Isolate? _isolate;
  async.StreamQueue<dynamic>? _streamQueue;

  Future<void> run() async {
    final p = ReceivePort();

    _isolate = await Isolate.spawn(_readAndConvertService, p.sendPort);

    _streamQueue = async.StreamQueue<dynamic>(p);
    SendPort sendPort = await _streamQueue!.next;
    _sendPort = sendPort;
  }

  void cancel() {
    _sendPort?.send(null);
    _streamQueue?.cancel();
    _isolate?.kill();
    _sendPort = null;
    _streamQueue = null;
    _isolate = null;
  }

  Future<void> _readAndConvertService(SendPort p) async {
    final commandPort = ReceivePort();
    p.send(commandPort.sendPort);

    // Wait for messages from the main isolate.
    await for (final message in commandPort) {
      if (message is _ConvertTaskItem) {
        final _ConvertTaskItem item = message;
        ui.Image frame = item.frame;
        final bytes = await frame.toByteData();
        img.Image bitmap = img.Image.fromBytes(
          frame.width,
          frame.height,
          bytes!.buffer.asUint8List(),
        );

        int dstWidth = bitmap.width;
        int dstHeight = bitmap.height;

        if (item.cropRegion != null) {
          dstWidth = (dstWidth * item.cropRegion!.width).toInt();
          dstHeight = (dstHeight * item.cropRegion!.height).toInt();
          bitmap = img.copyCrop(bitmap, 0, 0, dstWidth, dstHeight);
        }

        final jpgBytes = Uint8List.fromList(img.encodeJpg(bitmap, quality: 80));

        p.send(jpgBytes);
      } else if (message == null) {
        // Exit if the main isolate sends a null message, indicating there are no
        // more files to read and parse.
        // break;
      }
    }

    // print('Spawned isolate finished.');
    // Isolate.exit();
  }

  Future<Uint8List> convert(ui.Image image, ui.Rect? cropRegion) async {
    // final completer = Completer<Uint8List>();
    final message = _ConvertTaskItem(image, cropRegion);
    _sendPort!.send(message);
    final result = await _streamQueue!.next;
    return result;
    // return completer.future;
  }
}

class _ConvertTaskItem {
  final ui.Image frame;
  final ui.Rect? cropRegion;

  _ConvertTaskItem(this.frame, this.cropRegion);
}
