class MusicFromBeginningCommand(Command):
    """
    Command /music_from_beginning @username
    Gets the links sent by an specific username of the chat from the beginning
    """
    COMMAND = 'music_from_beginning'

    def __init__(self, update: Update, context: CallbackContext):
        super().__init__(update, context)
        self.telegram_api_client = TelegramAPIClient()

    def get_response(self):
        if self.args:
            links = self._get_links_from_user()
            all_time_links = self._group_links_by_user(links)
            return self._build_message(all_time_links), None
        else:
            msg = 'Command usage /music_from_beginning @username'
            return msg, None

    @staticmethod
    def _build_message(all_time_links):
        msg = '<strong>Music from the beginning of time:</strong> \n'
        for user, sent_links in all_time_links.items():
            msg += '- {} <strong>{}:</strong>\n'.format(emojis.EMOJI_USER, user)
            for sent_link in sent_links:
                link = sent_link.get('link')
                genres = Link.get_genres(link)
                msg += '    {}  <a href="{}">{}</a> {}\n'.format(
                    emojis.get_music_emoji(link.get('link_type')),
                    f'[{datetime.datetime.fromisoformat(sent_link.get("sent_at")).strftime(OUTPUT_DATE_FORMAT)}]',
                    link.get('url'),
                    Link.get_name(link),
                    '({})'.format(', '.join(genres)) if genres else ''
                )
            msg += '\n'
        return msg

    def _get_links_from_user(self):
        username = self.args[0]
        username = username.replace('@', '')
        links = self.telegram_api_client.get_sent_links(
            chat_id=self.update.message.chat_id,
            user_username=username
        )
        return links

    @staticmethod
    def _group_links_by_user(links):
        all_time_links = defaultdict(list)
        for link in links:
            all_time_links[
                link.get('sent_by').get('username') if link.get('sent_by').get('username') else link.get('sent_by').get(
                    'first_name')].append(link)
        return dict(all_time_links)
class MyMusicCommand(Command):
    """
    Command /mymusic
    It can only be called from a private conversation
    Returns a list of the links sent by the caller user in all the chats from the beginning of time
    """
    COMMAND = 'mymusic'

    def __init__(self, update: Update, context: CallbackContext):
        super().__init__(update, context)
        self.telegram_api_client = TelegramAPIClient()

    def get_response(self):
        all_time_links = self._get_all_time_links_from_user()
        return self._build_message(all_time_links), None

    @staticmethod
    def _build_message(all_time_links):
        msg = '<strong>Music sent in all your chats from the beginning of time:</strong> \n'
        for sent_link in all_time_links:
            link = sent_link.get('link')
            genres = Link.get_genres(link)
            msg += '    {}  {} <a href="{}">{}</a> {}\n'.format(
                emojis.get_music_emoji(link.get('type')),
                '[{}@{}]'.format(
                    datetime.datetime.fromisoformat(sent_link.get('sent_at')).strftime(OUTPUT_DATE_FORMAT),
                    sent_link.get('chat').get('name')
                ),
                link.get('url'),
                Link.get_name(link),
                '({})'.format(', '.join(genres)) if genres else ''
            )
        msg += '\n'
        return msg

    def _get_all_time_links_from_user(self):
        links = self.telegram_api_client.get_sent_links(
            user_id=self.update.message.from_user.id
        )
        return links
class MusicCommand(Command):
    """
    Command /music
    Gets the links sent by all the users of the chat in the last week
    and group them by user>links
    """
    COMMAND = 'music'
    DAYS = 7
    LAST_WEEK = datetime.datetime.now() - datetime.timedelta(days=DAYS)

    def __init__(self, update: Update, context: CallbackContext):
        super().__init__(update, context)
        self.telegram_api_client = TelegramAPIClient()

    def get_response(self):
        if self.args:
            links = self._get_links_from_user()
        else:
            links = self._get_links()
        last_week_links = self._group_links_by_user(links)
        return self._build_message(last_week_links), None

    @staticmethod
    def _build_message(last_week_links):
        msg = '<strong>Music from the last week:</strong> \n'
        for user, sent_links in last_week_links.items():
            msg += '- {} <strong>{}:</strong>\n'.format(emojis.EMOJI_USER, user)
            for sent_link in sent_links:
                link = sent_link.get('link')
                genres = Link.get_genres(link)
                msg += '    {} <a href="{}">{}</a> {}\n'.format(
                    emojis.get_music_emoji(link.get('link_type')),
                    link.get('url'),
                    Link.get_name(link),
                    '({})'.format(', '.join(genres)) if genres else ''
                )
            msg += '\n'
        return msg

    def _get_links(self):
        links = self.telegram_api_client.get_sent_links(
            chat_id=self.update.message.chat_id,
            since_date=self.LAST_WEEK
        )
        return links

    def _get_links_from_user(self):
        username = self.args[0]
        username = username.replace('@', '')
        links = self.telegram_api_client.get_sent_links(
            chat_id=self.update.message.chat_id,
            user_username=username,
            since_date=self.LAST_WEEK
        )
        return links

    @staticmethod
    def _group_links_by_user(links):
        last_week_links = defaultdict(list)
        for link in links:
            last_week_links[
                link.get('sent_by').get('username') if link.get('sent_by').get('username') else link.get('sent_by').get(
                    'first_name')].append(link)
        return dict(last_week_links)