//--------------------------------------------------------------------------------------------------
// Copyright (c) id3 Technologies
// All Rights Reserved.
//--------------------------------------------------------------------------------------------------
// ignore_for_file: unused_import
import 'dart:convert';
import 'dart:ffi';
import 'dart:typed_data';
import 'package:ffi/ffi.dart';
import 'face_sdk_generated_bindings.dart';
import 'face_native.dart';

import '../id3_face.dart';

final _finalizer = NativeFinalizer(faceSDK.addresses.id3FaceCandidate_Dispose.cast());

/// Represents a candidate in a one-to-many search.
class FaceCandidate implements Finalizable {
  /// Native handle.
  late Pointer<Pointer<id3FaceCandidate>> _pHandle;
  bool _disposable = true;

  /// Gets the native handle.
  /// return The native handle.
  Pointer<id3FaceCandidate> get handle => _pHandle.value;

  /// Creates a new instance of the FaceCandidate class.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  FaceCandidate() {
    _pHandle = calloc();
    try {
      var err = faceSDK.id3FaceCandidate_Initialize(_pHandle);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      _finalizer.attach(this, _pHandle.cast(), detach: this);
    } finally {}
  }

  /// Creates a new instance of the FaceCandidate class.
  ///
  /// param handle     Handle to the FaceCandidate.
  /// throws FaceException An error has occurred during Face Library execution.
  FaceCandidate.fromHandle(Pointer<id3FaceCandidate> handle) {
    _pHandle = calloc();
    _pHandle.value = handle;
    _disposable = false;
  }

  /// Releases all resources used by this FaceCandidate.
  void dispose() {
    if (_disposable) {
      faceSDK.id3FaceCandidate_Dispose(_pHandle);
      calloc.free(_pHandle);
      _finalizer.detach(this);
    }
  }

  // Copyable methods

  /// Creates a copy of the FaceCandidate object.
  ///
  /// return The newly created FaceCandidate object.
  /// throws FaceException An error has occurred during Face Library execution.
  FaceCandidate clone() {
    FaceCandidate clone = FaceCandidate();
    var err = faceSDK.id3FaceCandidate_CopyTo(_pHandle.value, clone.handle);
    if (err != FaceError.success.value) {
      throw FaceException(err);
    }
    return clone;
  }


  ///
  /// ID of the most similar face template as defined in the reference face template list used to perform the search.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  String get id => getId();

  ///
  /// Match score between the face probe template and the most similar one in the reference face template list used to perform the search.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get score => getScore();

  // Public methods
  /// Gets the ID of the most similar face template as defined in the reference face template list used to perform the search.
  ///
  /// return ID of the most similar face template as defined in the reference face template list used to perform the search.
  /// throws FaceException An error has occurred during Face Library execution.
  String getId() {
    Pointer<Char> pId = nullptr;
    Pointer<Int> pIdSize = calloc.allocate(1);
    pIdSize[0] = -1;
    try {
      var err = faceSDK.id3FaceCandidate_GetId(_pHandle.value, pId, pIdSize);
      if (err == FaceError.insufficientBuffer.value) {
        pId = calloc.allocate(pIdSize.value);
        err = faceSDK.id3FaceCandidate_GetId(_pHandle.value, pId, pIdSize);
        if (err != FaceError.success.value) {
          throw FaceException(err);
        }
      }
      final vId = utf8.decode(Uint8List.fromList(pId.cast<Uint8>().asTypedList(pIdSize.value)));
      return vId;
    } finally {
      calloc.free(pId);
      calloc.free(pIdSize);
    }
  }

  /// Gets the match score between the face probe template and the most similar one in the reference face template list used to perform the search.
  ///
  /// return Match score between the face probe template and the most similar one in the reference face template list used to perform the search.
  /// throws FaceException An error has occurred during Face Library execution.
  int getScore() {
    Pointer<Int> pScore = calloc();
    try {
      var err = faceSDK.id3FaceCandidate_GetScore(_pHandle.value, pScore);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vScore = pScore.value;
      return vScore;
    } finally {
      calloc.free(pScore);
    }
  }

}

