//
//  CdmWrapper.h
//  CastlabsWidevine
//
//  Created by Luca Niccoli on 22/02/2021.
//

#ifndef CdmWrapper_h
#define CdmWrapper_h

#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN

typedef NS_ENUM(int, WVMessageType) {
    WVMessageTypeLicenseRequest = 0,
    WVMessageTypeLicenseRenewal = 1,
    WVMessageTypeLicenseRelease = 2,
    WVMessageTypeIndividualizationRequest = 3, // Not used. Direct Individualization is used instead of App-Assisted
};

typedef NS_ENUM(int, WVSessionType) {
    WVSessionTypeTemporary = 0,
    WVSessionTypePersistentLicense = 1,
    WVSessionTypePersistent = WVSessionTypePersistentLicense,  // deprecated name from June 1 draft
    WVSessionTypePersistentUsageRecord = 2,
};

typedef NS_ENUM(int, WVStatus) {
    WVStatusSuccess = 0,
    WVStatusTypeError = 1,
    WVStatusNotSupported = 2,
    WVStatusInvalidState = 3,
    WVStatusQuotaExceeded = 4,
    WVStatusNeedsDeviceCertificate = 101,
    WVStatusSessionNotFound = 102,
    WVStatusDecryptError = 103,
    WVStatusNoKey = 104,
    WVStatusKeyUsageBlockedByPolicy = 105,
    WVStatusRangeError = 106,
    WVStatusResourceContention = 107,  // Recoverable
    WVStatusSessionStateLost = 108,    // Recoverable
    WVStatusSystemStateLost = 109,     // Recoverable
    WVStatusOutputTooLarge = 109,      // Recoverable
    WVStatusNeedsServiceCertificate = 111,
    WVStatusUnexpectedError = 99999,
};

typedef NS_ENUM(int, WVServiceRole) {
    WVServiceRoleAllServices = 0,
    WVServiceRoleProvisioningService = 1,
    WVServiceRoleLicensingService = 2,
} ServiceRole;

typedef NS_ENUM(int, WVInitDataType) {
    WVInitDataTypeCenc = 0,
    WVInitDataTypeKeyIds = 1,
    WVInitDataTypeWebM = 2,
    WVInitDataTypeHls = 10000,
};

typedef NS_ENUM(int, WVKeyStatus) {
    WVKeyStatusUsable = 0,
    WVKeyStatusExpired = 1,
    WVKeyStatusOutputRestricted = 2,
    WVKeyStatusOutputNotAllowed = WVKeyStatusOutputRestricted,  // deprecated name from June 1 draft
    WVKeyStatusStatusPending = 3,
    WVKeyStatusInternalError = 4,
    WVKeyStatusReleased = 5,
};

typedef NS_ENUM(int, WVEncryptionScheme) {
    WVEncryptionSchemeClear = 0,
    WVEncryptionSchemeAesCtr = 1,
    WVEncryptionSchemeAesCbc = 2,
};

typedef void (^TimerCallback)(void*,void* _Nullable);

@interface WVClientInfo : NSObject
@property NSString* productName;
@property NSString* companyName;
@property NSString* deviceName;
@property NSString* modelName;
@property NSString* archName;
@property NSString* buildInfo;
@end

@protocol WVDelegate

- (nullable NSData *) readFile:(NSString *)name;
- (BOOL) writeFile:(NSString *)name data:(NSData *)data;
- (BOOL) existsFile:(NSString *)name;
- (BOOL) removeFile:(NSString *)name;
- (int) fileSize:(NSString *)name;
- (NSArray<NSString*>*) listFiles;

- (long long) now;

- (void) setTimeout:(long long) delay_ms client:(void*) client context:(nullable void*)context callback:(TimerCallback)callback;
- (void) cancelTimeout:(void*) client;

@end

@protocol WVEventListener
- (void) onMessageForSessionId:(NSString *)sessionId type:(WVMessageType)type message:(NSData *)message;
- (void) onKeyStatusesChangeForSessionId:(NSString *)sessionId hasNewUsableKey:(BOOL)hasNewUsableKey;
- (void) onRemoveCompleteForSessionId:(NSString *)sessionId;
- (void) onDeferredCompleteForSessionId:(NSString *)sessionId result:(WVStatus) result;
@end

@interface WVInputBuffer: NSObject
@property NSData *key;
@property NSData *iv;
@property int patternEncryptedBlocks;
@property int patternClearBlocks;
@property NSData *data;
@property int block_offset;
@property WVEncryptionScheme encryptionScheme;
@property BOOL isVideo;
@property BOOL firstSubsample;
@property BOOL lastSubsample;
@end

@interface WVCdm : NSObject
+ (BOOL) initCdmWithWVDelegate:(id<WVDelegate>)delegate withWVClientInfo: (WVClientInfo*) clientInfo;
+ (NSData*) getDeviceCert;

- (id) initWithWVDelegate:(id<WVDelegate>)delegate listener:(id<WVEventListener>)listener;
- (WVStatus) setServiceCertificate:(WVServiceRole) role certificate:(NSData*) certificate;
- (WVStatus) getServiceCertificateRequest:(NSData * _Nonnull * _Nonnull) message;
- (WVStatus) parseAndLoadServiceCertificateResponse:(WVServiceRole) role response:(NSData*) response certificate:(NSData * _Nonnull * _Nonnull) certificate;
- (WVStatus) createSession:(WVSessionType) sessionType sessionId:(NSString * _Nonnull * _Nonnull) sessionId;
- (WVStatus) generateRequest:(NSString*) sessionId initDataType:(WVInitDataType) initDataType initData:(NSData*) initData;
- (WVStatus) load:(NSString*) sessionId;
- (WVStatus) update:(NSString*) sessionId response:(NSData*) response;
- (WVStatus) getExpiration:(NSString*) sessionId expiration:(int64_t*) expiration;
- (WVStatus) getKeyStatuses:(NSString*) sessionId statuses:(NSDictionary<NSUUID*,NSNumber*> * _Nonnull * _Nonnull) statuses;
- (WVStatus) close:(NSString*) sessionId;
- (WVStatus) remove:(NSString*) sessionId;

- (WVStatus) decrypt:(WVInputBuffer*) input output:(NSMutableData *)output outOffset:(NSInteger) offset ;
- (WVStatus) decryptSession:(NSString*) session input:(WVInputBuffer*) input output:(NSMutableData *)output outOffset:(NSInteger) offset;
@end
NS_ASSUME_NONNULL_END
#endif /* CdmWrapper_h */
