"""LICENSE
Copyright 2020 Hermann Krumrey <hermann@krumreyh.com>

This file is part of otaku-info.

otaku-info is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

otaku-info is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with otaku-info.  If not, see <http://www.gnu.org/licenses/>.
LICENSE"""

from typing import Dict, Any, Optional
from otaku_info.enums import ListService, ReleasingState
from otaku_info.mappings import mangadex_external_id_names, \
    list_service_id_types


class MangadexItem:
    """
    Class that models a general anilist list item
    Represents the information fetched using anilist's API
    """
    def __init__(
            self,
            mangadex_id: str,
            external_ids: Dict[ListService, str],
            english_title: str,
            romaji_title: str,
            cover_url: str,
            total_chapters: Optional[int],
            latest_chapter: Optional[int],
            releasing_state: ReleasingState
    ):
        """
        Initializes the MangadexItem object
        :param mangadex_id: The mangadex ID of the series
        :param external_ids: IDs for other services
        :param english_title: The title of the series in English
        :param romaji_title: The title of the series in Japanese
        :param cover_url: URL to a cover image for this series
        :param total_chapters: The total amount of chapters
        :param latest_chapter: The latest chapter
        :param releasing_state: The releasing state
        """
        self.mangadex_id = mangadex_id
        self.external_ids = external_ids
        self.english_title = english_title
        self.romaji_title = romaji_title
        self.cover_url = cover_url
        self.total_chapters = total_chapters
        self.latest_chapter = latest_chapter
        self.releasing_state = releasing_state

    @classmethod
    def from_json(cls, raw_data: Dict[str, Any]) \
            -> "MangadexItem":
        """
        Generates a MangadexItem from a dictionary generated by an API query
        :param raw_data: The data to use
        :return: The generated MangadexItem
        """
        data = raw_data["data"]
        relations = {x["type"]: x["id"] for x in raw_data["relationships"]}

        ids = {ListService.MANGADEX: data["id"]}
        links = data["attributes"]["links"]
        if links is not None:
            for service, identifier in mangadex_external_id_names.items():
                if identifier in links:
                    _id = links[identifier]
                    id_type = list_service_id_types[service]
                    if id_type == int:
                        _id = "".join([x for x in _id if x.isdigit()])
                    try:
                        ids[service] = str(id_type(_id))
                    except ValueError:
                        pass

        total_chapters: Optional[int] = None
        last_chapter: Optional[str] = data["attributes"]["lastChapter"]
        if last_chapter is not None:
            try:
                total_chapters = int(float(last_chapter.split("-")[0]))
            except ValueError:
                pass
        if total_chapters == 0:
            total_chapters = None

        releasing_state = cls.resolve_releasing_state(
            data["attributes"]["status"]
        )

        default_lang, default_title = \
            list(data["attributes"]["title"].items())[0]
        alt_titles = data["attributes"]["altTitles"]
        en_titles = [x for x in alt_titles if "en" in x]
        jp_titles = [x for x in alt_titles if "jp" in x]
        english_title = default_title
        romaji_title = default_title

        if default_lang == "jp" and len(en_titles) > 0:
            english_title = en_titles[0]["en"]
        elif default_lang == "en" and len(jp_titles) > 0:
            romaji_title = jp_titles[0]["jp"]

        return MangadexItem(
            data["id"],
            ids,
            english_title,
            romaji_title,
            relations.get("cover_art", ""),
            total_chapters,
            total_chapters,
            releasing_state
        )

    @staticmethod
    def resolve_releasing_state(state: str) -> ReleasingState:
        """
        Translates mangadex status tags to releasing states
        :param state: The status tag to translate
        :return: The releasing state
        """
        return {
            "ongoing": ReleasingState.RELEASING,
            "completed": ReleasingState.FINISHED,
            "cancelled": ReleasingState.CANCELLED,
            "hiatus": ReleasingState.UNKNOWN
        }[state]
