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

#import "ConversationViewItem.h"
#import <MobileCoreServices/MobileCoreServices.h>
#import <SignalServiceKit/SecurityUtils.h>
#import <SignalServiceKit/TSAttachmentStream.h>
#import <SignalServiceKit/TSOutgoingMessage.h>
#import <XCTest/XCTest.h>
#import <YapDatabase/YapDatabaseConnection.h>

@interface ConversationViewItem (Testing)

- (SEL)copyActionSelector;
- (SEL)saveActionSelector;
- (SEL)shareActionSelector;
- (SEL)deleteActionSelector;
- (SEL)metadataActionSelector;

@end

@interface ConversationViewItemTest : XCTestCase

@end

@implementation ConversationViewItemTest

- (void)setUp
{
    [super setUp];
}

- (void)tearDown
{
    // Put teardown code here. This method is called after the invocation of each test method in the class.
    [super tearDown];
}

// Test canPerformAction

- (NSString *)fakeTextMessageText
{
    return @"abc";
}

- (ConversationViewItem *)textViewItem
{
    TSOutgoingMessage *message =
        [[TSOutgoingMessage alloc] initWithTimestamp:1 inThread:nil messageBody:self.fakeTextMessageText];
    [message save];
    __block ConversationViewItem *viewItem = nil;
    [TSYapDatabaseObject.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
        viewItem = [[ConversationViewItem alloc] initWithInteraction:message isGroupThread:NO transaction:transaction];
    }];
    return viewItem;
}

- (ConversationViewItem *)viewItemWithAttachmentMimetype:(NSString *)mimeType filename:(NSString *)filename
{
    OWSAssert(filename.length > 0);

    NSString *resourcePath = [[NSBundle bundleForClass:[self class]] resourcePath];
    NSString *filePath = [resourcePath stringByAppendingPathComponent:filename];

    OWSAssert([[NSFileManager defaultManager] fileExistsAtPath:filePath]);

    DataSource *dataSource = [DataSourcePath dataSourceWithFilePath:filePath];
    TSAttachmentStream *attachment = [[TSAttachmentStream alloc] initWithContentType:mimeType
                                                                           byteCount:(UInt32)dataSource.dataLength
                                                                      sourceFilename:nil];
    BOOL success = [attachment writeDataSource:dataSource];
    OWSAssert(success);
    [attachment save];
    NSMutableArray<NSString *> *attachmentIds = [@[
        attachment.uniqueId,
    ] mutableCopy];
    TSOutgoingMessage *message =
        [[TSOutgoingMessage alloc] initWithTimestamp:1 inThread:nil messageBody:nil attachmentIds:attachmentIds];
    [message save];

    __block ConversationViewItem *viewItem = nil;
    [TSYapDatabaseObject.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
        viewItem = [[ConversationViewItem alloc] initWithInteraction:message isGroupThread:NO transaction:transaction];
    }];

    return viewItem;
}

- (ConversationViewItem *)stillImageViewItem
{
    return [self viewItemWithAttachmentMimetype:@"image/jpeg" filename:@"test-jpg.jpg"];
}

- (ConversationViewItem *)animatedImageViewItem
{
    return [self viewItemWithAttachmentMimetype:@"image/gif" filename:@"test-gif.gif"];
}

- (ConversationViewItem *)videoViewItem
{
    return [self viewItemWithAttachmentMimetype:@"video/mp4" filename:@"test-mp4.mp4"];
}

- (ConversationViewItem *)audioViewItem
{
    return [self viewItemWithAttachmentMimetype:@"audio/mp3" filename:@"test-mp3.mp3"];
}

- (void)testCanPerformEditingActionWithNonMediaMessage
{
    ConversationViewItem *viewItem = self.textViewItem;

    XCTAssertTrue([viewItem canPerformAction:viewItem.copyActionSelector]);
    XCTAssertFalse([viewItem canPerformAction:viewItem.saveActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.shareActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.deleteActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.metadataActionSelector]);
    XCTAssertFalse([viewItem canPerformAction:@selector(unknownAction:)]);
}

- (void)testCanPerformEditingActionWithPhotoMessage
{
    ConversationViewItem *viewItem = self.stillImageViewItem;

    XCTAssertTrue([viewItem canPerformAction:viewItem.copyActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.saveActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.shareActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.deleteActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.metadataActionSelector]);
    XCTAssertFalse([viewItem canPerformAction:@selector(unknownAction:)]);
}

- (void)testCanPerformEditingActionWithAnimatedMessage
{
    ConversationViewItem *viewItem = self.animatedImageViewItem;

    XCTAssertTrue([viewItem canPerformAction:viewItem.copyActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.saveActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.shareActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.deleteActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.metadataActionSelector]);
    XCTAssertFalse([viewItem canPerformAction:@selector(unknownAction:)]);
}

- (void)testCanPerformEditingActionWithVideoMessage
{
    ConversationViewItem *viewItem = self.videoViewItem;

    XCTAssertTrue([viewItem canPerformAction:viewItem.copyActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.saveActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.shareActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.deleteActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.metadataActionSelector]);
    XCTAssertFalse([viewItem canPerformAction:@selector(unknownAction:)]);
}

- (void)testCanPerformEditingActionWithAudioMessage
{
    ConversationViewItem *viewItem = self.audioViewItem;

    XCTAssertTrue([viewItem canPerformAction:viewItem.copyActionSelector]);
    XCTAssertFalse([viewItem canPerformAction:viewItem.saveActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.shareActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.deleteActionSelector]);
    XCTAssertTrue([viewItem canPerformAction:viewItem.metadataActionSelector]);
    XCTAssertFalse([viewItem canPerformAction:@selector(unknownAction:)]);
}

// Test Delete

- (void)testPerformDeleteEditingActionWithNonMediaMessage
{
    ConversationViewItem *viewItem = self.textViewItem;

    XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]);
    [viewItem deleteAction];
    XCTAssertNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]);
}

- (void)testPerformDeleteActionWithPhotoMessage
{
    ConversationViewItem *viewItem = self.stillImageViewItem;

    XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count);
    NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject;
    XCTAssertNotNil(attachmentId);
    TSAttachment *_Nullable attachment = [TSAttachment fetchObjectWithUniqueID:attachmentId];
    XCTAssertTrue([attachment isKindOfClass:[TSAttachmentStream class]]);
    TSAttachmentStream *_Nullable attachmentStream = (TSAttachmentStream *)attachment;
    NSString *_Nullable filePath = attachmentStream.filePath;
    XCTAssertNotNil(filePath);

    XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]);
    XCTAssertNotNil([TSAttachment fetchObjectWithUniqueID:attachmentId]);
    XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:filePath]);
    [viewItem deleteAction];
    XCTAssertNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]);
    XCTAssertNil([TSAttachment fetchObjectWithUniqueID:attachmentId]);
    XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:filePath]);
}

- (void)testPerformDeleteEditingActionWithAnimatedMessage
{
    ConversationViewItem *viewItem = self.animatedImageViewItem;

    XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count);
    NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject;
    XCTAssertNotNil(attachmentId);
    TSAttachment *_Nullable attachment = [TSAttachment fetchObjectWithUniqueID:attachmentId];
    XCTAssertTrue([attachment isKindOfClass:[TSAttachmentStream class]]);
    TSAttachmentStream *_Nullable attachmentStream = (TSAttachmentStream *)attachment;
    NSString *_Nullable filePath = attachmentStream.filePath;
    XCTAssertNotNil(filePath);

    XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]);
    XCTAssertNotNil([TSAttachment fetchObjectWithUniqueID:attachmentId]);
    XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:filePath]);
    [viewItem deleteAction];
    XCTAssertNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]);
    XCTAssertNil([TSAttachment fetchObjectWithUniqueID:attachmentId]);
    XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:filePath]);
}

- (void)testPerformDeleteEditingActionWithVideoMessage
{
    ConversationViewItem *viewItem = self.videoViewItem;

    XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count);
    NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject;
    XCTAssertNotNil(attachmentId);
    TSAttachment *_Nullable attachment = [TSAttachment fetchObjectWithUniqueID:attachmentId];
    XCTAssertTrue([attachment isKindOfClass:[TSAttachmentStream class]]);
    TSAttachmentStream *_Nullable attachmentStream = (TSAttachmentStream *)attachment;
    NSString *_Nullable filePath = attachmentStream.filePath;
    XCTAssertNotNil(filePath);

    XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]);
    XCTAssertNotNil([TSAttachment fetchObjectWithUniqueID:attachmentId]);
    XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:filePath]);
    [viewItem deleteAction];
    XCTAssertNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]);
    XCTAssertNil([TSAttachment fetchObjectWithUniqueID:attachmentId]);
    XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:filePath]);
}

- (void)testPerformDeleteEditingActionWithAudioMessage
{
    ConversationViewItem *viewItem = self.audioViewItem;

    XCTAssertEqual((NSUInteger)1, ((TSMessage *)viewItem.interaction).attachmentIds.count);
    NSString *_Nullable attachmentId = ((TSMessage *)viewItem.interaction).attachmentIds.firstObject;
    XCTAssertNotNil(attachmentId);
    TSAttachment *_Nullable attachment = [TSAttachment fetchObjectWithUniqueID:attachmentId];
    XCTAssertTrue([attachment isKindOfClass:[TSAttachmentStream class]]);
    TSAttachmentStream *_Nullable attachmentStream = (TSAttachmentStream *)attachment;
    NSString *_Nullable filePath = attachmentStream.filePath;
    XCTAssertNotNil(filePath);

    XCTAssertNotNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]);
    XCTAssertNotNil([TSAttachment fetchObjectWithUniqueID:attachmentId]);
    XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:filePath]);
    [viewItem deleteAction];
    XCTAssertNil([TSMessage fetchObjectWithUniqueID:viewItem.interaction.uniqueId]);
    XCTAssertNil([TSAttachment fetchObjectWithUniqueID:attachmentId]);
    XCTAssertFalse([[NSFileManager defaultManager] fileExistsAtPath:filePath]);
}

// Test Copy

- (void)testPerformCopyEditingActionWithNonMediaMessage
{
    // Reset the pasteboard.
    UIPasteboard.generalPasteboard.items = @[];
    XCTAssertNil(UIPasteboard.generalPasteboard.string);

    ConversationViewItem *viewItem = self.textViewItem;
    [viewItem copyTextAction];
    XCTAssertEqualObjects(self.fakeTextMessageText, UIPasteboard.generalPasteboard.string);
}

- (void)testPerformCopyEditingActionWithStillImageMessage
{
    // Reset the pasteboard.
    UIPasteboard.generalPasteboard.items = @[];
    XCTAssertNil(UIPasteboard.generalPasteboard.image);
    XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeJPEG]);

    ConversationViewItem *viewItem = self.stillImageViewItem;
    [viewItem copyMediaAction];
    NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeJPEG];
    XCTAssertTrue(copiedData.length > 0);
}

- (void)testPerformCopyEditingActionWithAnimatedImageMessage
{
    // Reset the pasteboard.
    UIPasteboard.generalPasteboard.items = @[];
    XCTAssertNil(UIPasteboard.generalPasteboard.image);
    XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeGIF]);

    ConversationViewItem *viewItem = self.animatedImageViewItem;
    [viewItem copyMediaAction];
    NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeGIF];
    XCTAssertTrue(copiedData.length > 0);
}

- (void)testPerformCopyEditingActionWithVideoMessage
{
    // Reset the pasteboard.
    UIPasteboard.generalPasteboard.items = @[];
    XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMPEG4]);

    ConversationViewItem *viewItem = self.videoViewItem;
    [viewItem copyMediaAction];
    NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMPEG4];
    XCTAssertTrue(copiedData.length > 0);
}

- (void)testPerformCopyEditingActionWithMp3AudioMessage
{
    // Reset the pasteboard.
    UIPasteboard.generalPasteboard.items = @[];
    XCTAssertNil([UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMP3]);

    ConversationViewItem *viewItem = self.audioViewItem;
    [viewItem copyMediaAction];
    NSData *_Nullable copiedData = [UIPasteboard.generalPasteboard dataForPasteboardType:(NSString *)kUTTypeMP3];
    XCTAssertTrue(copiedData.length > 0);
}

- (void)unknownAction:(id)sender
{
    // It's easier to create this stub method than to suppress the "unknown selector" build warnings.
}

@end