#import "TGMessageViewModel.h"

#import "TGStringUtils.h"
#import "TGGeometry.h"

#import "WKInterfaceImage+Signals.h"
#import "WKInterfaceGroup+Signals.h"

#import "TGBridgeUser.h"
#import "TGBridgeChat.h"
#import "TGBridgeMessage.h"
#import "TGBridgeUserCache.h"

#import "TGBridgeContext.h"

#import "TGBridgeMediaSignals.h"

@implementation TGMessageViewModel

+ (void)imageBubbleSizeForImageSize:(CGSize)imageSize minSize:(CGSize)minSize maxSize:(CGSize)maxSize thumbnailSize:(out CGSize *)thumbnailSize renderSize:(out CGSize *)renderSize
{
    CGSize imageTargetMaxSize = maxSize;
    CGSize imageScalingMaxSize = CGSizeMake(imageTargetMaxSize.width - 18.0f, imageTargetMaxSize.height - 18.0f);
    CGSize imageTargetMinSize = minSize;
    
    CGFloat imageAspect = 1.0f;
    if (imageSize.width > 1.0f - FLT_EPSILON && imageSize.height > 1.0f - FLT_EPSILON)
        imageAspect = imageSize.width / imageSize.height;
    
    if (imageSize.width < imageScalingMaxSize.width || imageSize.height < imageScalingMaxSize.height)
    {
        if (imageSize.width <= FLT_EPSILON || imageSize.height <= FLT_EPSILON)
            imageSize = imageTargetMinSize;
    }
    else
    {
        if (imageSize.width > imageTargetMaxSize.width)
        {
            imageSize.width = imageTargetMaxSize.width;
            imageSize.height = floorf(imageTargetMaxSize.width / imageAspect);
        }
        
        if (imageSize.height > imageTargetMaxSize.height)
        {
            imageSize.width = floorf(imageTargetMaxSize.height * imageAspect);
            imageSize.height = imageTargetMaxSize.height;
        }
    }
    
    if (renderSize != NULL)
        *renderSize = imageSize;
    
    imageSize.width = MIN(imageTargetMaxSize.width, imageSize.width);
    imageSize.height = MIN(imageTargetMaxSize.height, imageSize.height);
    
    imageSize.width = MAX(imageTargetMinSize.width, imageSize.width);
    imageSize.height = MAX(imageTargetMinSize.height, imageSize.height);
    
    if (thumbnailSize != NULL)
        *thumbnailSize = imageSize;
}

+ (void)updateAuthorLabel:(WKInterfaceLabel *)authorLabel isOutgoing:(bool)isOutgoing isGroup:(bool)isGroup user:(TGBridgeUser *)user ownUserId:(int32_t)ownUserId
{
    if (isGroup && !isOutgoing)
    {
        authorLabel.hidden = false;
        authorLabel.text = user.displayName;
        authorLabel.textColor = [TGColor colorForUserId:user.identifier myUserId:ownUserId];
    }
    else
    {
        authorLabel.hidden = true;
    }
}

+ (void)updateMediaGroup:(WKInterfaceGroup *)mediaGroup activityIndicator:(WKInterfaceImage *)activityIndicator mediaAttachment:(TGBridgeMediaAttachment *)mediaAttachment currentPhoto:(int64_t *)currentPhoto standalone:(bool)standalone margin:(CGFloat)margin imageSize:(CGSize *)imageSize isVisible:(bool (^)(void))isVisible completion:(void (^)(void))completion
{
    CGSize targetImageSize = CGSizeZero;
    
    if ([mediaAttachment isKindOfClass:[TGBridgeImageMediaAttachment class]])
        [((TGBridgeImageMediaAttachment *)mediaAttachment).imageInfo imageUrlForLargestSize:&targetImageSize];
    else if ([mediaAttachment isKindOfClass:[TGBridgeVideoMediaAttachment class]])
        targetImageSize = ((TGBridgeVideoMediaAttachment *)mediaAttachment).dimensions;
    
    CGSize screenSize = TGWatchScreenSize();
    
    CGSize mediaGroupSize = CGSizeZero;
    if (standalone)
    {
        mediaGroupSize = TGFitSize(targetImageSize, CGSizeMake(screenSize.width - margin * 2, FLT_MAX));
    }
    else
    {
        CGSize maxSize = CGSizeMake(screenSize.width - 15, screenSize.width);
        CGSize minSize = CGSizeMake(screenSize.width / 1.25f, screenSize.width / 2);
        [self imageBubbleSizeForImageSize:targetImageSize minSize:minSize maxSize:maxSize thumbnailSize:&mediaGroupSize renderSize:NULL];
    }
    
    mediaGroupSize = CGSizeMake(ceilf(mediaGroupSize.width), ceilf(mediaGroupSize.height));
    
    if (imageSize != NULL)
        *imageSize = CGSizeMake(mediaGroupSize.width, mediaGroupSize.height);
    
    if ([mediaAttachment isKindOfClass:[TGBridgeImageMediaAttachment class]])
    {
        TGBridgeImageMediaAttachment *imageAttachment = (TGBridgeImageMediaAttachment *)mediaAttachment;
        
        if (currentPhoto == NULL || imageAttachment.imageId != *currentPhoto)
        {
            if (currentPhoto != NULL)
                *currentPhoto = imageAttachment.imageId;
            
            [mediaGroup setBackgroundImageSignal:[[[TGBridgeMediaSignals previewWithImageAttachment:imageAttachment size:mediaGroupSize] onNext:^(id next)
            {
                if (next != nil)
                    activityIndicator.hidden = true;
                
                if (completion != nil)
                    completion();
            }] onError:^(id error)
            {
                if (currentPhoto != NULL)
                    *currentPhoto = 0;
                
                if (completion != nil)
                    completion();
            }] isVisible:isVisible];
        }
    }
    else if ([mediaAttachment isKindOfClass:[TGBridgeVideoMediaAttachment class]])
    {
        activityIndicator.hidden = true;
        
        TGBridgeVideoMediaAttachment *videoAttachment = (TGBridgeVideoMediaAttachment *)mediaAttachment;
        
        if (currentPhoto == NULL || videoAttachment.videoId != *currentPhoto)
        {
            if (currentPhoto != NULL)
                *currentPhoto = videoAttachment.videoId;
            
            [mediaGroup setBackgroundImageSignal:[[[TGBridgeMediaSignals previewWithVideoAttachment:videoAttachment size:mediaGroupSize] onNext:^(id next)
            {
                if (next != nil)
                    activityIndicator.hidden = true;
                
                if (completion != nil)
                    completion();
            }] onError:^(id error)
            {
                if (currentPhoto != NULL)
                    *currentPhoto = 0;
                
                if (completion != nil)
                    completion();
            }] isVisible:isVisible];
        }
    }
}

+ (void)updateForwardHeaderGroup:(WKInterfaceGroup *)forwardHeaderGroup titleLabel:(WKInterfaceLabel *)titleLabel fromLabel:(WKInterfaceLabel *)fromLabel forwardAttachment:(TGBridgeForwardedMessageMediaAttachment *)forwardAttachment forwardPeer:(id)forwardPeer textColor:(UIColor *)textColor
{
    forwardHeaderGroup.hidden = (forwardAttachment == nil);
    if (forwardHeaderGroup.hidden)
        return;
    
    titleLabel.text = TGLocalized(@"Watch.Message.ForwardedFrom");

    NSString *authorName = nil;
    if ([forwardPeer isKindOfClass:[TGBridgeUser class]])
        authorName = ((TGBridgeUser *)forwardPeer).displayName;
    else if ([forwardPeer isKindOfClass:[TGBridgeChat class]])
        authorName = ((TGBridgeChat *)forwardPeer).groupTitle;
    
    NSMutableAttributedString *forwardAttributedText = [[NSMutableAttributedString alloc] initWithString:authorName attributes:@{ NSFontAttributeName: [UIFont systemFontOfSize:12], NSForegroundColorAttributeName:textColor }];
    
    NSRange formatNameRange = NSMakeRange(0, authorName.length);
    if (formatNameRange.location != NSNotFound)
    {
        [forwardAttributedText addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:12 weight:UIFontWeightMedium] range:NSMakeRange(formatNameRange.location, authorName.length)];
    }
    
    fromLabel.attributedText = forwardAttributedText;
}

+ (void)updateReplyHeaderGroup:(WKInterfaceGroup *)replyHeaderGroup authorLabel:(WKInterfaceLabel *)authorLabel imageGroup:(WKInterfaceGroup *)imageGroup textLabel:(WKInterfaceLabel *)textLabel titleColor:(UIColor *)titleColor subtitleColor:(UIColor *)subtitleColor replyAttachment:(TGBridgeReplyMessageMediaAttachment *)replyAttachment currentReplyPhoto:(int64_t *)currentReplyPhoto isVisible:(bool (^)(void))isVisible completion:(void (^)(void))completion
{
    TGBridgeMessage *message = replyAttachment.message;
    replyHeaderGroup.hidden = (message == nil);
    if (replyHeaderGroup.hidden)
        return;
    
    bool hasAttachment = false;
    bool hasImagePreview = false;
    NSString *messageText = nil;
    UIColor *textColor = nil;
    TGBridgeImageMediaAttachment *imageAttachment = nil;
    TGBridgeVideoMediaAttachment *videoAttachment = nil;
    
    for (TGBridgeMediaAttachment *attachment in message.media)
    {
        if ([attachment isKindOfClass:[TGBridgeImageMediaAttachment class]])
        {
            hasAttachment = true;
            hasImagePreview = true;
            messageText = TGLocalized(@"Message.Photo");
            imageAttachment = (TGBridgeImageMediaAttachment *)attachment;
        }
        else if ([attachment isKindOfClass:[TGBridgeVideoMediaAttachment class]])
        {
            hasAttachment = true;
            hasImagePreview = true;
            messageText = TGLocalized(@"Message.Video");
            videoAttachment = (TGBridgeVideoMediaAttachment *)attachment;
        }
        else if ([attachment isKindOfClass:[TGBridgeAudioMediaAttachment class]])
        {
            hasAttachment = true;
            messageText = TGLocalized(@"Message.Audio");
        }
        else if ([attachment isKindOfClass:[TGBridgeDocumentMediaAttachment class]])
        {
            hasAttachment = true;
            TGBridgeDocumentMediaAttachment *documentAttachment = (TGBridgeDocumentMediaAttachment *)attachment;
            
            if (documentAttachment.isSticker)
            {
                if (documentAttachment.stickerAlt.length > 0)
                    messageText = [NSString stringWithFormat:@"%@ %@", documentAttachment.stickerAlt, TGLocalized(@"Message.Sticker")];
                else
                    messageText = TGLocalized(@"Message.Sticker");
            }
            else
            {
                if (documentAttachment.fileName.length > 0)
                    messageText = documentAttachment.fileName;
                else
                    messageText = TGLocalized(@"Message.File");
            }
        }
        else if ([attachment isKindOfClass:[TGBridgeLocationMediaAttachment class]])
        {
            hasAttachment = true;
            messageText = TGLocalized(@"Message.Location");
        }
        else if ([attachment isKindOfClass:[TGBridgeContactMediaAttachment class]])
        {
            hasAttachment = true;
            messageText = TGLocalized(@"Message.Contact");
        }
        else if ([attachment isKindOfClass:[TGBridgeActionMediaAttachment class]])
        {
            hasAttachment = true;
            
            TGBridgeActionMediaAttachment *actionAttachment = (TGBridgeActionMediaAttachment *)attachment;
            [self stringForActionAttachment:actionAttachment message:message users:nil forChannel:false];
        }
    }
    
    if (!hasAttachment)
    {
        messageText = message.text;
        textColor = titleColor;
    }
    else
    {
        textColor = subtitleColor;
    }
    
    authorLabel.text = [[[TGBridgeUserCache instance] userWithId:(int32_t)message.fromUid] displayName];
    imageGroup.hidden = !hasImagePreview;
    textLabel.text = messageText;
    textLabel.textColor = textColor;
    
    if (imageAttachment != nil)
    {
        if (currentReplyPhoto == NULL || imageAttachment.imageId != *currentReplyPhoto)
        {
            if (currentReplyPhoto != NULL)
                *currentReplyPhoto = imageAttachment.imageId;
            
            [imageGroup setBackgroundImageSignal:[[[TGBridgeMediaSignals previewWithImageAttachment:imageAttachment size:CGSizeMake(26, 26)] onNext:^(id next)
            {
                if (completion != nil)
                    completion();
            }] onError:^(id error)
            {
                if (currentReplyPhoto != NULL)
                    *currentReplyPhoto = 0;
                
                if (completion != nil)
                    completion();
            }] isVisible:isVisible];
        }
    }
    else if (videoAttachment != nil)
    {
        if (currentReplyPhoto == NULL || videoAttachment.videoId != *currentReplyPhoto)
        {
            if (currentReplyPhoto != NULL)
                *currentReplyPhoto = videoAttachment.videoId;
            
            [imageGroup setBackgroundImageSignal:[[[TGBridgeMediaSignals previewWithVideoAttachment:videoAttachment size:CGSizeMake(26, 26)] onNext:^(id next)
            {
                if (completion != nil)
                    completion();
            }] onError:^(id error)
            {
                if (currentReplyPhoto != NULL)
                    *currentReplyPhoto = 0;
                
                if (completion != nil)
                    completion();
            }] isVisible:isVisible];
        }
    }
    else
    {
        if (completion != nil)
            completion();
    }
}

+ (NSString *)stringForActionAttachment:(TGBridgeActionMediaAttachment *)actionAttachment message:(TGBridgeMessage *)message users:(NSDictionary *)users forChannel:(bool)forChannel
{
    NSString *messageText = nil;
    TGBridgeUser *author = (users != nil) ? users[@(message.fromUid)] : [[TGBridgeUserCache instance] userWithId:(int32_t)message.fromUid];
    
    switch (actionAttachment.actionType)
    {
        case TGBridgeMessageActionChatEditTitle:
        {
            if (forChannel)
            {
                messageText = TGLocalized(@"Notification.RenamedChannel");
            }
            else
            {
                NSString *authorName = [TGStringUtils initialsForFirstName:author.firstName lastName:author.lastName single:false];
                NSString *formatString = TGLocalized(@"Notification.RenamedChat");
                
                messageText = [NSString stringWithFormat:formatString, authorName];
            }
        }
            break;
            
        case TGBridgeMessageActionChatEditPhoto:
        {
            NSString *authorName = [TGStringUtils initialsForFirstName:author.firstName lastName:author.lastName single:false];
            bool changed = actionAttachment.actionData[@"photo"];
            
            if (forChannel)
            {
                messageText = changed ? TGLocalized(@"Channel.MessagePhotoUpdated") : TGLocalized(@"Channel.MessagePhotoRemoved");
            }
            else
            {
                NSString *formatString = changed ? TGLocalized(@"Notification.ChangedGroupPhoto") : TGLocalized(@"Notification.RemovedGroupPhoto");
                
                messageText = [NSString stringWithFormat:formatString, authorName];
            }
        }
            break;
            
        case TGBridgeMessageActionUserChangedPhoto:
        {
            
        }
            break;
            
        case TGBridgeMessageActionChatAddMember:
        case TGBridgeMessageActionChatDeleteMember:
        {
            NSString *authorName = [TGStringUtils initialsForFirstName:author.firstName lastName:author.lastName single:false];
            TGBridgeUser *user = (users != nil) ? users[actionAttachment.actionData[@"uid"]] : [[TGBridgeUserCache instance] userWithId:[actionAttachment.actionData[@"uid"] int32Value]];
            
            if (user.identifier == author.identifier)
            {
                NSString *formatString = (actionAttachment.actionType == TGBridgeMessageActionChatAddMember) ? TGLocalized(@"Notification.JoinedChat") : TGLocalized(@"Notification.LeftChat");
                messageText = [[NSString alloc] initWithFormat:formatString, authorName];
            }
            else
            {
                NSString *userName = [TGStringUtils initialsForFirstName:user.firstName lastName:user.lastName single:false];
                NSString *formatString = (actionAttachment.actionType == TGBridgeMessageActionChatAddMember) ? TGLocalized(@"Notification.Invited") : TGLocalized(@"Notification.Kicked");
                messageText = [[NSString alloc] initWithFormat:formatString, authorName, userName];
            }
        }
            break;
            
        case TGBridgeMessageActionJoinedByLink:
        {
            NSString *authorName = [TGStringUtils initialsForFirstName:author.firstName lastName:author.lastName single:false];
            NSString *formatString = TGLocalizedStatic(@"Notification.JoinedGroupByLink");
            messageText = [[NSString alloc] initWithFormat:formatString, authorName, actionAttachment.actionData[@"title"]];
        }
            break;
            
        case TGBridgeMessageActionCreateChat:
        {
            NSString *authorName = [TGStringUtils initialsForFirstName:author.firstName lastName:author.lastName single:false];
            NSString *formatString = TGLocalizedStatic(@"Notification.CreatedChatWithTitle");
            messageText = [[NSString alloc] initWithFormat:formatString, authorName, actionAttachment.actionData[@"title"]];
        }
            break;
            
        case TGBridgeMessageActionContactRegistered:
        {
            messageText = TGLocalized(@"Watch.Notification.Joined");
        }
            break;
            
        case TGBridgeMessageActionChannelCreated:
        {
            messageText = TGLocalized(@"Notification.CreatedChannel");
        }
            break;
            
        case TGBridgeMessageActionChannelInviter:
        {
            TGBridgeUser *user = (users != nil) ? users[actionAttachment.actionData[@"uid"]] : [[TGBridgeUserCache instance] userWithId:[actionAttachment.actionData[@"uid"] int32Value]];
            NSString *authorName = [TGStringUtils initialsForFirstName:user.firstName lastName:user.lastName single:false];
            NSString *formatString = TGLocalizedStatic(@"Notification.ChannelInviter");
            
            messageText = [[NSString alloc] initWithFormat:formatString, authorName];
        }
            
        case TGBridgeMessageActionGroupMigratedTo:
        {
            messageText = TGLocalized(@"Notification.GroupMigratedToChannel");
        }
            break;
            
        case TGBridgeMessageActionGroupActivated:
        {
            messageText = TGLocalized(@"Notification.GroupActivated");
        }
            break;
            
        case TGBridgeMessageActionGroupDeactivated:
        {
            messageText = TGLocalized(@"Notification.GroupDeactivated");
        }
            break;
            
        case TGBridgeMessageActionChannelMigratedFrom:
        {
            messageText = TGLocalized(@"Notification.ChannelMigratedFrom");
        }
            break;
            
        default:
            break;
    }

    return messageText;
}

+ (NSAttributedString *)attributedTextForMessage:(TGBridgeMessage *)message fontSize:(CGFloat)fontSize textColor:(UIColor *)textColor
{
    NSArray *textCheckingResults = [message textCheckingResults];
    
    NSString *messageText = message.text ?: @"";
    
    NSMutableAttributedString *string = [[NSMutableAttributedString alloc] initWithString:messageText attributes:@{ NSFontAttributeName: [UIFont systemFontOfSize:fontSize], NSForegroundColorAttributeName: textColor }];
    
    for (TGBridgeTextCheckingResult *result in textCheckingResults)
    {
        if (result.type == TGBridgeTextCheckingResultTypeBold)
            [string addAttributes:@{ NSFontAttributeName: [UIFont systemFontOfSize:fontSize weight:UIFontWeightMedium] } range:result.range];
        else if (result.type == TGBridgeTextCheckingResultTypeItalic)
            [string addAttributes:@{ NSFontAttributeName: [UIFont italicSystemFontOfSize:fontSize] } range:result.range];
        else if (result.type == TGBridgeTextCheckingResultTypeCode || result.type == TGBridgeTextCheckingResultTypePre)
            [string addAttributes:@{ NSFontAttributeName: [UIFont fontWithName:@"Courier" size:fontSize] } range:result.range];
    }
    
    return string;
}

@end


@implementation TGStickerViewModel

+ (void)updateWithMessage:(TGBridgeMessage *)message isGroup:(bool)isGroup context:(TGBridgeContext *)context currentDocumentId:(int64_t *)currentDocumentId authorLabel:(WKInterfaceLabel *)authorLabel imageGroup:(WKInterfaceGroup *)imageGroup isVisible:(bool (^)(void))isVisible completion:(void (^)(void))completion
{
    [TGMessageViewModel updateAuthorLabel:authorLabel isOutgoing:message.outgoing isGroup:isGroup user:[[TGBridgeUserCache instance] userWithId:(int32_t)message.fromUid] ownUserId:context.userId];
    
    for (TGBridgeMediaAttachment *attachment in message.media)
    {
        if ([attachment isKindOfClass:[TGBridgeDocumentMediaAttachment class]])
        {
            TGBridgeDocumentMediaAttachment *documentAttachment = (TGBridgeDocumentMediaAttachment *)attachment;
            
            if (currentDocumentId == NULL || *currentDocumentId != documentAttachment.documentId)
            {
                if (currentDocumentId != NULL)
                    *currentDocumentId = documentAttachment.documentId;
                
                [imageGroup setBackgroundImageSignal:[[[TGBridgeMediaSignals stickerWithDocumentAttachment:documentAttachment type:TGMediaStickerImageTypeNormal] onNext:^(id next)
                {
                    if (completion != nil)
                        completion();
                }] onError:^(id error)
                {
                    if (currentDocumentId != NULL)
                        *currentDocumentId = 0;
                    
                    if (completion != nil)
                        completion();
                }] isVisible:isVisible];
            }
            break;
        }
    }
}

@end
