import json
import random
import time
from pathlib import Path
from typing import Dict, List
from urllib.parse import urlparse

from aiograpi_fixed import config
from aiograpi_fixed.exceptions import HighlightNotFound
from aiograpi_fixed.extractors import extract_highlight_v1
from aiograpi_fixed.types import Highlight
from aiograpi_fixed.utils import dumps


class HighlightMixin:
    async def highlight_pk_from_url(self, url: str) -> str:
        """
        Get Highlight PK from URL

        Parameters
        ----------
        url: str
            URL of highlight

        Returns
        -------
        str
            Highlight PK

        Examples
        --------
        https://www.instagram.com/stories/highlights/17895485201104054/ -> 17895485201104054
        """
        assert "/highlights/" in url, 'URL must contain "/highlights/"'
        path = urlparse(url).path
        parts = [p for p in path.split("/") if p and p.isdigit()]
        return str(parts[0])

    async def user_highlights_v1(
        self, user_id: int, amount: int = 0
    ) -> List[Highlight]:
        """
        Get a user's highlight

        Parameters
        ----------
        user_id: int
        amount: int, optional
            Maximum number of highlight to return, default is 0 (all highlights)

        Returns
        -------
        List[Highlight]
            A list of objects of Highlight
        """
        amount = int(amount)
        user_id = int(user_id)
        params = {
            "supported_capabilities_new": json.dumps(config.SUPPORTED_CAPABILITIES),
            "phone_id": self.phone_id,
            "battery_level": random.randint(25, 100),
            "is_charging": random.randint(0, 1),
            "will_sound_on": random.randint(0, 1),
        }
        result = await self.private_request(
            f"highlights/{user_id}/highlights_tray/", params=params
        )
        return [extract_highlight_v1(highlight) for highlight in result.get("tray", [])]

    async def user_highlights(self, user_id: int, amount: int = 0) -> List[Highlight]:
        """
        Get a user's highlights

        Parameters
        ----------
        user_id: int
        amount: int, optional
            Maximum number of highlight to return, default is 0 (all highlights)

        Returns
        -------
        List[Highlight]
            A list of objects of Highlight
        """
        return await self.user_highlights_v1(user_id, amount)

    async def highlight_info_v1(self, highlight_pk: str) -> Highlight:
        """
        Get Highlight by pk or id (by Private Mobile API)

        Parameters
        ----------
        highlight_pk: str
            Unique identifier of Highlight

        Returns
        -------
        Highlight
            An object of Highlight type
        """
        highlight_id = f"highlight:{highlight_pk}"
        data = {
            "exclude_media_ids": "[]",
            "supported_capabilities_new": json.dumps(config.SUPPORTED_CAPABILITIES),
            "source": "profile",
            "_uid": str(self.user_id),
            "_uuid": self.uuid,
            "user_ids": [highlight_id],
        }
        result = await self.private_request("feed/reels_media/", data)
        data = result["reels"]
        if str(highlight_pk) not in (k.split(":")[-1] for k in data.keys()):
            raise HighlightNotFound(highlight_pk=highlight_pk, **data)
        item = next(item for item in data.values() if isinstance(item, dict))
        return extract_highlight_v1(item)

    async def highlight_info(self, highlight_pk: str) -> Highlight:
        """
        Get Highlight by pk or id

        Parameters
        ----------
        highlight_pk: str
            Unique identifier of Highlight

        Returns
        -------
        Highlight
            An object of Highlight type
        """
        return await self.highlight_info_v1(highlight_pk)

    async def highlight_create(
        self,
        title: str,
        story_ids: List[str],
        cover_story_id: str = "",
        crop_rect: List[float] = [0.0, 0.21830457, 1.0, 0.78094524],
    ) -> Highlight:
        """
        Create highlight

        Parameters
        ----------
        title: str
            Title
        story_ids: List[str]
            List of story ids
        cover_story_id: str
            User story as cover, default is first of story_ids

        Returns
        -------
        Highlight
            An object of Highlight type
        """
        if not cover_story_id:
            cover_story_id = story_ids[0]
        data = {
            "supported_capabilities_new": json.dumps(config.SUPPORTED_CAPABILITIES),
            "source": "self_profile",
            "creation_id": str(int(time.time())),
            "_uid": str(self.user_id),
            "_uuid": self.uuid,
            "cover": dumps(
                {
                    "media_id": await self.media_id(cover_story_id),
                    "crop_rect": dumps(crop_rect),
                }
            ),
            "title": title,
            "media_ids": dumps([await self.media_id(sid) for sid in story_ids]),
        }
        result = await self.private_request("highlights/create_reel/", data=data)
        return extract_highlight_v1(result["reel"])

    async def highlight_edit(
        self,
        highlight_pk: str,
        title: str = "",
        cover: Dict = {},
        added_media_ids: List[str] = [],
        removed_media_ids: List[str] = [],
    ):
        data = {
            "supported_capabilities_new": json.dumps(config.SUPPORTED_CAPABILITIES),
            "source": "self_profile",
            "_uid": str(self.user_id),
            "_uuid": self.uuid,
            "added_media_ids": dumps(added_media_ids),
            "removed_media_ids": dumps(removed_media_ids),
        }
        if title:
            data["title"] = title
        if cover:
            data["cover"] = dumps(cover)
        result = await self.private_request(
            f"highlights/highlight:{highlight_pk}/edit_reel/", data=data
        )
        return extract_highlight_v1(result["reel"])

    async def highlight_change_title(self, highlight_pk: str, title: str) -> Highlight:
        """
        Change title for highlight

        Parameters
        ----------
        highlight_pk: str
            Unique identifier of Highlight
        title: str
            Title of Highlight

        Returns
        -------
        Highlight
        """
        return await self.highlight_edit(highlight_pk, title=title)

    async def highlight_change_cover(
        self, highlight_pk: str, cover_path: Path
    ) -> Highlight:
        """
        Change cover for highlight

        Parameters
        ----------
        highlight_pk: str
            Unique identifier of Highlight
        cover_path: Path
            Path to photo

        Returns
        -------
        Highlight
        """
        upload_id, width, height = await self.photo_rupload(Path(cover_path))
        cover = {"upload_id": str(upload_id), "crop_rect": "[0.0,0.0,1.0,1.0]"}
        return await self.highlight_edit(highlight_pk, cover=cover)

    async def highlight_add_stories(
        self, highlight_pk: str, added_media_ids: List[str]
    ) -> Highlight:
        """
        Add stories to highlight

        Parameters
        ----------
        highlight_pk: str
            Unique identifier of Highlight
        removed_media_ids: List[str]
            Remove stories from highlight

        Returns
        -------
        Highlight
        """
        return await self.highlight_edit(highlight_pk, added_media_ids=added_media_ids)

    async def highlight_remove_stories(
        self, highlight_pk: str, removed_media_ids: List[str]
    ) -> Highlight:
        """
        Remove stories from highlight

        Parameters
        ----------
        highlight_pk: str
            Unique identifier of Highlight
        removed_media_ids: List[str]
            Remove stories from highlight

        Returns
        -------
        Highlight
        """
        return self.highlight_edit(highlight_pk, removed_media_ids=removed_media_ids)

    async def highlight_delete(self, highlight_pk: str) -> bool:
        """
        Delete highlight

        Parameters
        ----------
        highlight_pk: str
            Unique identifier of Highlight

        Returns
        -------
        bool
        """
        data = {"_uid": str(self.user_id), "_uuid": self.uuid}
        result = await self.private_request(
            f"highlights/highlight:{highlight_pk}/delete_reel/", data=data
        )
        return result.get("status") == "ok"
