#!/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
from time import time
from .messagePaths import getMessageFilePaths
from .model.messenger import Messenger
from .plot.messages import (
    plotTopXBusyChats,
    plotTopXPrivateChatsWithHighestContributonFromYou,
    plotTopChatThreadEachWeek
)
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 v0.8.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)))),
            plotTopChatThreadEachWeek(
                messenger,
                'Weekly Top Private Facebook Chat Thread for {}'
                .format(reactions.reactions[0].actor),
                join(
                    sink,
                    'weeklyTopPrivateFacebookChatThreadFor{}.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()
