#import "TGVideoMediaAttachment.h"

#import "TGMessage.h"

@interface TGVideoMediaAttachment ()
{
    NSArray *_textCheckingResults;
}
@end

@implementation TGVideoMediaAttachment

@synthesize videoId = _videoId;
@synthesize accessHash = _accessHash;

@synthesize localVideoId = _localVideoId;

@synthesize duration = _duration;
@synthesize dimensions = _dimensions;

@synthesize videoInfo = _videoInfo;
@synthesize thumbnailInfo = _thumbnailInfo;

- (id)init
{
    self = [super init];
    if (self != nil)
    {
        self.type = TGVideoMediaAttachmentType;
    }
    return self;
}

- (id)copyWithZone:(NSZone *)__unused zone
{
    TGVideoMediaAttachment *videoAttachment = [[TGVideoMediaAttachment alloc] init];
    
    videoAttachment.videoId = _videoId;
    videoAttachment.accessHash = _accessHash;
    videoAttachment.localVideoId = _localVideoId;
    videoAttachment.duration = _duration;
    videoAttachment.dimensions = _dimensions;
    videoAttachment.videoInfo = _videoInfo;
    videoAttachment.thumbnailInfo = _thumbnailInfo;
    videoAttachment.caption = _caption;
    videoAttachment.hasStickers = _hasStickers;
    videoAttachment.embeddedStickerDocuments = _embeddedStickerDocuments;
    videoAttachment.loopVideo = _loopVideo;
    
    return videoAttachment;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super init];
    if (self != nil) {
        self.type = TGVideoMediaAttachmentType;
        
        _videoId = [aDecoder decodeInt64ForKey:@"videoId"];
        _accessHash = [aDecoder decodeInt64ForKey:@"accessHash"];
        _localVideoId = [aDecoder decodeInt64ForKey:@"localVideoId"];
        _duration = [aDecoder decodeInt32ForKey:@"duration"];
        _dimensions = [aDecoder decodeCGSizeForKey:@"dimensions"];
        _videoInfo = [aDecoder decodeObjectForKey:@"videoInfo"];
        _thumbnailInfo = [aDecoder decodeObjectForKey:@"thumbInfo"];
        _caption = [aDecoder decodeObjectForKey:@"caption"];
        _hasStickers = [aDecoder decodeBoolForKey:@"hasStickers"];
        _embeddedStickerDocuments = [aDecoder decodeObjectForKey:@"embeddedStickerDocuments"];
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder {
    [aCoder encodeInt64:_videoId forKey:@"videoId"];
    [aCoder encodeInt64:_accessHash forKey:@"accessHash"];
    [aCoder encodeInt64:_localVideoId forKey:@"localVideoId"];
    [aCoder encodeInt32:_duration forKey:@"duration"];
    [aCoder encodeCGSize:_dimensions forKey:@"dimensions"];
    [aCoder encodeObject:_videoInfo forKey:@"videoInfo"];
    [aCoder encodeObject:_thumbnailInfo forKey:@"thumbInfo"];
    [aCoder encodeObject:_caption forKey:@"caption"];
    [aCoder encodeBool:_hasStickers forKey:@"hasStickers"];
    if (_embeddedStickerDocuments != nil) {
        [aCoder encodeObject:_embeddedStickerDocuments forKey:@"embeddedStickerDocuments"];
    }
}

- (BOOL)isEqual:(id)object
{
    if (![object isKindOfClass:[TGVideoMediaAttachment class]])
        return false;
    
    TGVideoMediaAttachment *other = object;
    
    if (_videoId != other.videoId || _accessHash != other.accessHash || _localVideoId != other.localVideoId || _duration != other.duration || !CGSizeEqualToSize(_dimensions, other.dimensions))
        return false;
    
    if (!TGObjectCompare(_videoInfo, other.videoInfo))
        return false;
    
    if (!TGObjectCompare(_thumbnailInfo, other.thumbnailInfo))
        return false;
    
    if (!TGObjectCompare(_caption, other.caption))
        return false;
    
    if (_hasStickers != other.hasStickers) {
        return false;
    }
    
    return true;
}

- (void)serialize:(NSMutableData *)data
{
    int32_t modernTag = 0x7abacaf1;
    [data appendBytes:&modernTag length:4];
    
    uint8_t version = 3;
    [data appendBytes:&version length:1];
    
    int dataLengthPtr = (int)data.length;
    int zero = 0;
    [data appendBytes:&zero length:4];
    
    [data appendBytes:&_videoId length:8];
    [data appendBytes:&_accessHash length:8];
    
    [data appendBytes:&_localVideoId length:8];
    
    uint8_t hasVideoInfo = _videoInfo != nil ? 1 : 0;
    [data appendBytes:&hasVideoInfo length:1];
    if (hasVideoInfo != 0)
        [_videoInfo serialize:data];
    
    uint8_t hasThumbnailInfo = _thumbnailInfo != nil ? 1 : 0;
    [data appendBytes:&hasThumbnailInfo length:1];
    if (hasThumbnailInfo != 0)
        [_thumbnailInfo serialize:data];
    
    [data appendBytes:&_duration length:4];
    
    int dimension = (int)_dimensions.width;
    [data appendBytes:&dimension length:4];
    dimension = (int)_dimensions.height;
    [data appendBytes:&dimension length:4];
    
    NSData *captionData = [_caption dataUsingEncoding:NSUTF8StringEncoding];
    int32_t captionLength = (int32_t)captionData.length;
    [data appendBytes:&captionLength length:4];
    if (captionLength != 0)
        [data appendData:captionData];
    
    int8_t hasStickers = _hasStickers ? 1 : 0;
    [data appendBytes:&hasStickers length:1];
    
    if (_embeddedStickerDocuments.count == 0) {
        int32_t zero = 0;
        [data appendBytes:&zero length:4];
    } else {
        NSData *stickerData = [NSKeyedArchiver archivedDataWithRootObject:_embeddedStickerDocuments];
        int32_t length = (int32_t)stickerData.length;
        [data appendBytes:&length length:4];
        [data appendData:stickerData];
    }
    
    int dataLength = (int)(data.length - dataLengthPtr - 4);
    [data replaceBytesInRange:NSMakeRange(dataLengthPtr, 4) withBytes:&dataLength];
}

- (TGMediaAttachment *)parseMediaAttachment:(NSInputStream *)is
{
    int32_t dataLength = 0;
    [is read:(uint8_t *)&dataLength maxLength:4];
    
    uint8_t version = 1;
    if (dataLength == 0x7abacaf1)
    {
        [is read:(uint8_t *)&version maxLength:1];
        [is read:(uint8_t *)&dataLength maxLength:4];
    }
    
    TGVideoMediaAttachment *videoAttachment = [[TGVideoMediaAttachment alloc] init];
    
    int64_t videoId = 0;
    [is read:(uint8_t *)&videoId maxLength:8];
    videoAttachment.videoId = videoId;
    
    int64_t accessHash = 0;
    [is read:(uint8_t *)&accessHash maxLength:8];
    videoAttachment.accessHash = accessHash;
    
    int64_t localVideoId = 0;
    [is read:(uint8_t *)&localVideoId maxLength:8];
    videoAttachment.localVideoId = localVideoId;
    
    uint8_t hasVideoInfo = 0;
    [is read:&hasVideoInfo maxLength:1];
    
    if (hasVideoInfo != 0)
        videoAttachment.videoInfo = [TGVideoInfo deserialize:is];
    
    uint8_t hasThumbnailInfo = 0;
    [is read:&hasThumbnailInfo maxLength:1];
    
    if (hasThumbnailInfo != 0)
        videoAttachment.thumbnailInfo = [TGImageInfo deserialize:is];
    
    int duration = 0;
    [is read:(uint8_t *)&duration maxLength:4];
    videoAttachment.duration = duration;
    
    CGSize dimensions = CGSizeZero;
    int dimension = 0;
    [is read:(uint8_t *)&dimension maxLength:4];
    dimensions.width = dimension;
    dimension = 0;
    [is read:(uint8_t *)&dimension maxLength:4];
    dimensions.height = dimension;
    videoAttachment.dimensions = dimensions;
    
    if (version >= 2)
    {
        int32_t captionLength = 0;
        [is read:(uint8_t *)&captionLength maxLength:4];
        if (captionLength != 0)
        {
            uint8_t *captionBytes = malloc(captionLength);
            [is read:captionBytes maxLength:captionLength];
            videoAttachment.caption = [[NSString alloc] initWithBytesNoCopy:captionBytes length:captionLength encoding:NSUTF8StringEncoding freeWhenDone:true];
        }
    }
    
    if (version >= 3)
    {
        int8_t hasStickers = 0;
        [is read:(uint8_t *)&hasStickers maxLength:1];
        videoAttachment.hasStickers = hasStickers != 0;
        
        int32_t stickerDataLength = 0;
        [is read:(uint8_t *)&stickerDataLength maxLength:4];
        if (stickerDataLength != 0) {
            uint8_t *stickerBytes = malloc(stickerDataLength);
            [is read:stickerBytes maxLength:stickerDataLength];
            NSData *stickerData = [[NSData alloc] initWithBytesNoCopy:stickerBytes length:stickerDataLength freeWhenDone:true];
            videoAttachment.embeddedStickerDocuments = [NSKeyedUnarchiver unarchiveObjectWithData:stickerData];
        }
    }
    
    return videoAttachment;
}

- (NSArray *)textCheckingResults
{
    if (_caption.length < 2)
        _textCheckingResults = [NSArray array];
    
    if (_textCheckingResults == nil)
    {
        NSArray *textCheckingResults = [TGMessage textCheckingResultsForText:_caption highlightMentionsAndTags:true highlightCommands:true entities:nil];
        _textCheckingResults = textCheckingResults ?: [NSArray array];
    }
    
    return _textCheckingResults;
}

@end
