//--------------------------------------------------------------------------------------------------
// 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 'bioseal_sdk_generated_bindings.dart';
import 'bioseal_native.dart';

import '../id3_bioseal.dart';

final _finalizer = NativeFinalizer(biosealSDK.addresses.id3BiosealLotl_Dispose.cast());

/// Provides information about the LoTL (List of Trust List).
class Lotl implements Finalizable {
  /// Native handle.
  late Pointer<Pointer<id3BiosealLotl>> _pHandle;
  bool _disposable = true;

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

  /// Creates a new instance of the Lotl class.
  ///
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  Lotl() {
    _pHandle = calloc();
    try {
      var err = biosealSDK.id3BiosealLotl_Initialize(_pHandle);
      if (err != BiosealError.success.value) {
        throw BiosealException(err);
      }
      _finalizer.attach(this, _pHandle.cast(), detach: this);
    } finally {}
  }

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

  /// Releases all resources used by this Lotl.
  void dispose() {
    if (_disposable) {
      biosealSDK.id3BiosealLotl_Dispose(_pHandle);
      calloc.free(_pHandle);
      _finalizer.detach(this);
    }
  }


  ///
  /// Get the log.
  ///
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  Log get log => getLog();

  ///
  /// True if the LoTL is a TLS.
  ///
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  bool get isTsl => getIsTsl();

  // Public methods
  /// Gets the get the log.
  ///
  /// return Get the log.
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  Log getLog() {
    Log log = Log();
    var err = biosealSDK.id3BiosealLotl_GetLog(_pHandle.value, log.handle);
    if (err != BiosealError.success.value) {
      log.dispose();
      throw BiosealException(err);
    }
    return log;
  }

  /// Gets the true if the LoTL is a TLS.
  ///
  /// return True if the LoTL is a TLS.
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  bool getIsTsl() {
    Pointer<Bool> pIsTsl = calloc();
    try {
      var err = biosealSDK.id3BiosealLotl_GetIsTsl(_pHandle.value, pIsTsl);
      if (err != BiosealError.success.value) {
        throw BiosealException(err);
      }
      final vIsTsl = pIsTsl.value;
      return vIsTsl;
    } finally {
      calloc.free(pIsTsl);
    }
  }

  /// Returns the URL to the TSL or the next LoTL.
  ///
  /// param lotlData The LotL data.
  /// param manifestId The Manifest ID in ISO 22385 format (hexadecimal string).
  /// param iac The IAC (optional).
  /// return The TSL url.
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  String getUrl(Uint8List? lotlData, String? manifestId, String? iac) {
    Pointer<UnsignedChar>? pLotlData;
    if (lotlData != null) {
    	pLotlData = calloc.allocate<UnsignedChar>(lotlData.length);
    	pLotlData.cast<Uint8>().asTypedList(lotlData.length).setAll(0, lotlData);
    }
    Pointer<Char>? pManifestId = manifestId?.toNativeUtf8().cast<Char>();
    Pointer<Char>? pIac = iac?.toNativeUtf8().cast<Char>();
    Pointer<Char> pUrl = nullptr;
    Pointer<Int> pUrlSize = calloc.allocate(1);
    pUrlSize[0] = -1;
    try {
      var err = biosealSDK.id3BiosealLotl_GetUrl(_pHandle.value, pLotlData ?? nullptr, lotlData?.length ?? 0, pManifestId ?? nullptr, pIac ?? nullptr, pUrl, pUrlSize);
      if (err == BiosealError.insufficientBuffer.value) {
        pUrl = calloc.allocate(pUrlSize.value);
        err = biosealSDK.id3BiosealLotl_GetUrl(_pHandle.value, pLotlData ?? nullptr, lotlData?.length ?? 0, pManifestId ?? nullptr, pIac ?? nullptr, pUrl, pUrlSize);
        if (err != BiosealError.success.value) {
          throw BiosealException(err);
        }
      }
      final vUrl = utf8.decode(Uint8List.fromList(pUrl.cast<Uint8>().asTypedList(pUrlSize.value)));
      return vUrl;
    } finally {
      if (pLotlData != null) {
        calloc.free(pLotlData);
      }
      if (pManifestId != null) {
        calloc.free(pManifestId);
      }
      if (pIac != null) {
        calloc.free(pIac);
      }
      calloc.free(pUrl);
      calloc.free(pUrlSize);
    }
  }

  /// Returns the URL to the manifest.
  ///
  /// param tslData The TSL data.
  /// return The manifest url.
  /// throws BiosealException An error has occurred during Bioseal Library execution.
  String getManifestUrl(Uint8List? tslData) {
    Pointer<UnsignedChar>? pTslData;
    if (tslData != null) {
    	pTslData = calloc.allocate<UnsignedChar>(tslData.length);
    	pTslData.cast<Uint8>().asTypedList(tslData.length).setAll(0, tslData);
    }
    Pointer<Char> pUrl = nullptr;
    Pointer<Int> pUrlSize = calloc.allocate(1);
    pUrlSize[0] = -1;
    try {
      var err = biosealSDK.id3BiosealLotl_GetManifestUrl(_pHandle.value, pTslData ?? nullptr, tslData?.length ?? 0, pUrl, pUrlSize);
      if (err == BiosealError.insufficientBuffer.value) {
        pUrl = calloc.allocate(pUrlSize.value);
        err = biosealSDK.id3BiosealLotl_GetManifestUrl(_pHandle.value, pTslData ?? nullptr, tslData?.length ?? 0, pUrl, pUrlSize);
        if (err != BiosealError.success.value) {
          throw BiosealException(err);
        }
      }
      final vUrl = utf8.decode(Uint8List.fromList(pUrl.cast<Uint8>().asTypedList(pUrlSize.value)));
      return vUrl;
    } finally {
      if (pTslData != null) {
        calloc.free(pTslData);
      }
      calloc.free(pUrl);
      calloc.free(pUrlSize);
    }
  }

}

