import 'dart:ffi';

import 'package:ffi/ffi.dart';
import 'package:segmentation_douglas_peucker_flutter/gen/generated_bindings.dart';
import 'package:segmentation_douglas_peucker_flutter/lib.dart';

class DotNetException implements Exception {
  final String message;

  const DotNetException(this.message);

  factory DotNetException.fromPointer(Pointer<System_Exception_t> pointer) {
    final NativeLibrary nativeLibrary = NativeLibrary(Lib.shared);

    final System_String_t messagePtr =
        nativeLibrary.System_Exception_Message_Get(
      pointer.value,
      nullptr,
    );

    final Pointer<Char> chars = nativeLibrary.DNStringToC(messagePtr);

    final message = chars.cast<Utf8>().toDartString();

    return DotNetException(message.replaceAll('\n', '').trim());
  }

  static void handle(Pointer<System_Exception_t> exception) {
    if (exception.value != nullptr) {
      throw DotNetException.fromPointer(exception);
    }
  }

  @override
  String toString() {
    return message;
  }
}

extension PointerExtensions on Pointer<System_Exception_t> {
  void handle({void Function(Object e)? onException}) {
    try {
      DotNetException.handle(this);
    } catch (e) {
      if (onException != null) {
        onException(e);
      } else {
        rethrow;
      }
    }
  }
}
