#!/usr/bin/python3

from argparse import ArgumentParser
from typing import Tuple, List
from os.path import exists, abspath, join
from .extract import (
    makeDir,
    extractAll
)
from .model.reactions import Reactions
from .plot.reactions import (
    plotReactionCount,
    plotPeerToReactionCount,
    plotReactionsOverTimeAsHeatMap,
    plotWeeklyReactionHeatMap,
    plotTopXPeersByMonth,
    plotAccumulatedUserActivityInEachMinuteOfDay
)
from .model.friends import Friends
from .plot.friends import plotMonthlyFriendsCreated
from .model.comments import Comments
from .plot.comments import plotTopXPeersWithMostCommentedPostsByUser
from .plot.extra import (
    plotWeeklyHeatMapWithLikesReactionsComments,
    plotTopXHighlyInteractedFacebookPeers
)
from time import time
from .messagePaths import getMessageFilePaths
from .model.messenger import Messenger
from .plot.messages import (
    plotTopXBusyChats,
    plotTopXPrivateChatsWithHighestContributonFromYou,
    plotTopChatThreadEachWeek,
    plotPrivateChatThreadsWithLowestContributonFromYou
)
import warnings
# ignores all warnings generated by dependencies
warnings.filterwarnings('ignore')


def _splitAndJoinActorName(name: str) -> str:
    '''
        Splits actor name at whitespaces and joins them by `_`
    '''
    return '_'.join(name.split())


def _calculateSuccess(arr: List[bool]) -> float:
    '''
        Calculates percentage of success
    '''
    return (arr.count(True) / len(arr)) * 100


def _getBanner():
    '''
        Prints banner of scipt
    '''
    print('\x1b[1;6;36;49m[+]fviz v1.0.0 - Facebook data visualizer\x1b[0m\n\n\t\x1b[3;30;47m$ fviz `path-to-exported-facebook-data.zip` `path-for-zip-extraction`  `path-to-sink-directory`\x1b[0m\n\n[+]Author: Anjan Roy < anjanroy@yandex.com >\n[+]Source: https://github.com/itzmeanjan/fviz ( MIT Licensed )\n')


def _getCMD() -> Tuple[str, str, str]:
    '''
        Parses command line args, passed while invoking script
    '''
    parser = ArgumentParser()
    parser.add_argument('src',
                        type=str,
                        help='Exported compressed Facebook data as zip file')
    parser.add_argument('extractAt',
                        type=str,
                        help='Extraction location of zip')
    parser.add_argument('sink',
                        type=str,
                        help='Sink directory path, where plots to be placed')
    args = parser.parse_args()

    if not (args.src and args.extractAt and args.sink):
        return None, None, None
    if not (args.src.endswith('.zip') and exists(args.src) and makeDir(abspath(args.sink))):
        return None, None, None

    return tuple(map(lambda e: abspath(e), [args.src, args.extractAt, args.sink]))


def main():
    _getBanner()

    try:
        src, extractAt, sink = _getCMD()
        if not (src and extractAt and sink):
            raise Exception('Bad CMD args')

        if not extractAll(src, extractAt):
            raise Exception('Failed to extract zip')

        print('[+]Working ...')
        _starTm = time()
        reactions = Reactions.fromJSON(
            join(extractAt,
                 'likes_and_reactions/posts_and_comments.json'))

        if not reactions:
            raise Exception('Failed to parse reactions')

        friends = Friends.fromJSON(
            join(extractAt,
                 'friends/friends.json'
                 )
        )

        if not friends:
            raise Exception('Failed to parse friends data')

        comments = Comments.fromJSON(
            join(extractAt,
                 'comments/comments.json'
                 )
        )

        if not comments:
            raise Exception('Failed to parse comments data')

        messenger = Messenger.fromJSON(
            getMessageFilePaths(
                join(
                    extractAt,
                    'messages/inbox')))

        if not messenger:
            raise Exception('Failed to parse messages')

        _success = [
            plotReactionCount(
                reactions.reactionTypeToCount,
                'Reactions by {} [ {} - {} ]'.format(
                    reactions.reactions[0].actor,
                    *[i.strftime('%d %b, %Y') for i in reactions.getTimeFrame]
                ),
                join(
                    sink,
                    'reactionTypeToCountBy{}.png'.format(
                        _splitAndJoinActorName(reactions.reactions[0].actor)
                    ))),
            plotPeerToReactionCount(
                reactions.getTopXPeerToReactionCount(10),
                'Top 10 profiles, whose posts were mostly reacted by {} [ {} - {} ]'.format(
                    reactions.reactions[0].actor,
                    *[i.strftime('%d %b, %Y') for i in reactions.getTimeFrame]
                ),
                join(
                    sink,
                    'top10ProfilesWithMostlyReactedPostsBy{}.png'.format(
                        _splitAndJoinActorName(reactions.reactions[0].actor)
                    ))),
            plotReactionsOverTimeAsHeatMap(
                reactions,
                'Reaction HeatMap for {}'.format(reactions.reactions[0].actor),
                join(
                    sink,
                    'reactionHeatMapFor{}'.format(
                        _splitAndJoinActorName(reactions.reactions[0].actor)
                    ))),
            plotWeeklyReactionHeatMap(
                reactions,
                'Weekly Accumulated Reaction HeatMap for {}'.format(
                    reactions.reactions[0].actor),
                join(
                    sink,
                    'weeklyAccumulatedReactionHeatMapFor{}.svg'.format(
                        _splitAndJoinActorName(reactions.reactions[0].actor)
                    ))),
            plotTopXPeersByMonth(
                reactions,
                'Top 3 profiles with highest liked and reacted post by {}'.format(
                    reactions.reactions[0].actor),
                join(
                    sink,
                    'top3ProfilesWithMonthlyMostReactedPostsBy{}.svg'.format(
                        _splitAndJoinActorName(reactions.reactions[0].actor)
                    ))),
            plotAccumulatedUserActivityInEachMinuteOfDay(
                reactions,
                'Accumulated Likes & Reactions in each minute of Day by {}'.format(
                    reactions.reactions[0].actor),
                join(
                    sink,
                    'accumulatedAcivityInEachMinuteOfDayBy{}.svg'.format(
                        _splitAndJoinActorName(reactions.reactions[0].actor)
                    ))),
            plotWeeklyHeatMapWithLikesReactionsComments(
                reactions,
                comments,
                'Facebook Activity on each Quarter of Day by {}'.format(
                    reactions.reactions[0].actor),
                join(
                    sink,
                    'facebookActivityOnEachQuarterOfDayBy{}.svg'.format(
                        _splitAndJoinActorName(
                            reactions.reactions[0].actor)
                    ))),
            plotMonthlyFriendsCreated(
                friends,
                'Monthly Friending Rate of {}'.format(
                    reactions.reactions[0].actor),
                join(
                    sink,
                    'monthlyFriendingRateOf{}.svg'.format(
                        _splitAndJoinActorName(
                            reactions.reactions[0].actor)
                    ))),
            plotTopXPeersWithMostCommentedPostsByUser(
                comments,
                'Top 10 Facebook Profiles, with whom {} mostly interacted in Facebook Comments'.format(
                    reactions.reactions[0].actor),
                join(
                    sink,
                    'top10ProfilesWithMostlyCommentedPostsBy{}.svg'.format(
                        _splitAndJoinActorName(
                            reactions.reactions[0].actor)
                    ))),
            plotTopXBusyChats(
                messenger.topXBusiestChats(),
                'Top 15 busiest Facebook Chats of {}'
                .format(reactions.reactions[0].actor),
                join(
                    sink,
                    'top15FacebookChatsWithMostMessages{}.svg'.format(
                        _splitAndJoinActorName(
                            reactions.reactions[0].actor)
                    ))),
            plotTopXPrivateChatsWithHighestContributonFromYou(
                messenger,
                10,
                reactions.reactions[0].actor,
                'Top 10 Private Facebook Chats with highest contributions from {}'
                .format(reactions.reactions[0].actor),
                join(
                    sink,
                    'top10PrivateFacebookChatsWithHighestContributionFrom{}.svg'.format(
                        _splitAndJoinActorName(reactions.reactions[0].actor)))),
            plotPrivateChatThreadsWithLowestContributonFromYou(
                messenger,
                10,
                reactions.reactions[0].actor,
                'Top 10 Private Facebook Chat Threads with lowest contribution from {}'
                .format(reactions.reactions[0].actor),
                join(
                    sink,
                    'top10PrivateFacebookChatThreadsWithLowestContributionFrom{}.svg'.format(
                        _splitAndJoinActorName(reactions.reactions[0].actor)))),
            plotTopChatThreadEachWeek(
                messenger,
                'Weekly Top Private Facebook Chat Thread for {}'
                .format(reactions.reactions[0].actor),
                join(
                    sink,
                    'weeklyTopPrivateFacebookChatThreadFor{}.svg'.format(
                        _splitAndJoinActorName(reactions.reactions[0].actor)))),
            plotTopXHighlyInteractedFacebookPeers(
                reactions, comments, messenger,
                [reactions.reactions[0].actor, 'self'], 10,
                'Top 10 Highly Interacted with Facebook Profiles for {} [ {} - {} ]'
                .format(reactions.reactions[0].actor,
                        *[i.strftime('%d %b, %Y') for i in reactions.getTimeFrame]),
                join(sink,
                     'topXHighlyInteractedFacebookProfilesFor{}.svg'.format(
                         _splitAndJoinActorName(reactions.reactions[0].actor))))
        ]
        print('[+]Completed in \x1b[1;6;35;48m{} s\x1b[0m with \x1b[1;6;35;48m{}%\x1b[0m success'.format(
            time() - _starTm,
            _calculateSuccess(_success)))
    except KeyboardInterrupt:
        print('\n[!] Terminated')
    except Exception as e:
        print('[!] {}'.format(e))


if __name__ == '__main__':
    main()
