//
//  Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//

#import "OWSProvisioningMessage.h"
#import "OWSProvisioningCipher.h"
#import <SessionAxolotlKit/NSData+keyVersionByte.h>
#import <SessionCurve25519Kit/Curve25519.h>
#import <SessionHKDFKit/HKDFKit.h>
#import <SessionServiceKit/SessionServiceKit-Swift.h>

NS_ASSUME_NONNULL_BEGIN

@interface OWSProvisioningMessage ()

@property (nonatomic, readonly) NSData *myPublicKey;
@property (nonatomic, readonly) NSData *myPrivateKey;
@property (nonatomic, readonly) NSString *accountIdentifier;
@property (nonatomic, readonly) NSData *theirPublicKey;
@property (nonatomic, readonly) NSData *profileKey;
@property (nonatomic, readonly) BOOL areReadReceiptsEnabled;
@property (nonatomic, readonly) NSString *provisioningCode;

@end

@implementation OWSProvisioningMessage

- (instancetype)initWithMyPublicKey:(NSData *)myPublicKey
                       myPrivateKey:(NSData *)myPrivateKey
                     theirPublicKey:(NSData *)theirPublicKey
                  accountIdentifier:(NSString *)accountIdentifier
                         profileKey:(NSData *)profileKey
                readReceiptsEnabled:(BOOL)areReadReceiptsEnabled
                   provisioningCode:(NSString *)provisioningCode
{
    self = [super init];
    if (!self) {
        return self;
    }

    _myPublicKey = myPublicKey;
    _myPrivateKey = myPrivateKey;
    _theirPublicKey = theirPublicKey;
    _accountIdentifier = accountIdentifier;
    _profileKey = profileKey;
    _areReadReceiptsEnabled = areReadReceiptsEnabled;
    _provisioningCode = provisioningCode;

    return self;
}

- (nullable NSData *)buildEncryptedMessageBody
{
    ProvisioningProtoProvisionMessageBuilder *messageBuilder =
        [ProvisioningProtoProvisionMessage builderWithIdentityKeyPublic:self.myPublicKey
                                                     identityKeyPrivate:self.myPrivateKey
                                                                 number:self.accountIdentifier
                                                       provisioningCode:self.provisioningCode
                                                              userAgent:@"OWI"
                                                             profileKey:self.profileKey
                                                           readReceipts:self.areReadReceiptsEnabled];

    NSError *error;
    NSData *_Nullable plainTextProvisionMessage = [messageBuilder buildSerializedDataAndReturnError:&error];
    if (!plainTextProvisionMessage || error) {
        OWSFailDebug(@"could not serialize proto: %@.", error);
        return nil;
    }

    OWSProvisioningCipher *cipher = [[OWSProvisioningCipher alloc] initWithTheirPublicKey:self.theirPublicKey];
    NSData *_Nullable encryptedProvisionMessage = [cipher encrypt:plainTextProvisionMessage];
    if (encryptedProvisionMessage == nil) {
        OWSFailDebug(@"Failed to encrypt provision message");
        return nil;
    }

    // Note that this is a one-time-use *cipher* public key, not our Signal *identity* public key
    ProvisioningProtoProvisionEnvelopeBuilder *envelopeBuilder =
        [ProvisioningProtoProvisionEnvelope builderWithPublicKey:[cipher.ourPublicKey prependKeyType]
                                                            body:encryptedProvisionMessage];

    NSData *_Nullable envelopeData = [envelopeBuilder buildSerializedDataAndReturnError:&error];
    if (!envelopeData || error) {
        OWSFailDebug(@"could not serialize proto: %@.", error);
        return nil;
    }

    return envelopeData;
}

@end

NS_ASSUME_NONNULL_END
