import pickle
import base64
import json
import os
import re
from urllib.parse import urlparse, urlunparse
from InstagramGrabber import exceptions
from typing import Any, Dict
from uuid import uuid4


def get_uuid() -> Dict:
    if not os.path.exists(os.path.join(os.getcwd(), ".temp", "uuid.json")):
        with open(os.path.join(os.getcwd(), ".temp","uuid.json"), "w") as f:
            json.dump({
                "device_id": str(uuid4()),
                "phone_id": str(uuid4())
            }, f)
    with open(os.path.join(os.getcwd(), ".temp","uuid.json"), "rb") as f:
        data = json.load(f)
    return data

def save_cookies(cookies, cookies_name) -> None:
    if not os.path.exists(os.path.join(os.getcwd(), ".temp")):
        os.makedirs(os.path.join(os.getcwd(), ".temp"))
    with open(os.path.join(os.getcwd(), ".temp", f'{cookies_name}_cookies'), 'wb') as f:
        pickle.dump(cookies, f)

def load_cookies(cookies_name) -> Any:
    try:
        if not os.path.exists(os.path.join(os.getcwd(), ".temp")):
            os.makedirs(os.path.join(os.getcwd(), ".temp"))
        with open(os.path.join(os.getcwd(), ".temp", f'{cookies_name}_cookies'), 'rb') as f:
            cookies = pickle.load(f)
    except Exception as e:
        cookies = None
    return cookies

def extract_shortcode_from_url(url) -> str:
    remove_query_and_trailing_slash = lambda url: urlunparse(urlparse(url)._replace(query="")._replace(path=urlparse(url).path.rstrip("/")))
    parsed_url = urlparse(remove_query_and_trailing_slash(url))
    path_segments = parsed_url.path.split('/')
    if len(path_segments) <= 2:
        raise exceptions.InstagramException(f'can\'t find shortcode')
    return path_segments[2]
    
def extract_username_from_url(url) -> str:
    remove_query_and_trailing_slash = lambda url: urlunparse(urlparse(url)._replace(query="")._replace(path=urlparse(url).path.rstrip("/")))
    parsed_url = urlparse(remove_query_and_trailing_slash(url))
    path_segments = parsed_url.path.split('/')
    if len(path_segments) <= 1:
        raise exceptions.InstagramException(f'invalid instagram URL {url}')
    
    return path_segments[1]

def instagram_shortcode_to_media_id(code) -> int:
    if len(code) > 11:
        return None
    code = 'A' * (12 - len(code)) + code
    return int.from_bytes(base64.b64decode(code.encode(), b'-_'), 'big')

def get_best_quality(data) -> Dict:
    best_image = max(data, key=lambda x: x["width"] * x["height"])
    return {
        "width": best_image['width'],
        "height": best_image['height'],
        "url": best_image['url'],
    }

def extract_json(data) -> Dict:
    return json.loads(data)

def is_url(url) -> bool:
    regex = re.compile(
        r'^(?:http|ftp)s?://' # http:// or https://
        r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' #domain...
        r'localhost|' #localhost...
        r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
        r'(?::\d+)?' # optional port
        r'(?:/?|[/?]\S+)$', re.IGNORECASE)
    return re.match(regex, url) is not None

def extract_all_media(items) -> Dict:
    all_media = []
    for item in items:
        media = None
        try:
            media = item["media"]
        except KeyError:
            media = item
        media_id = media['pk']
        shortcode = media['code']
        product_type = media["product_type"]
        captions = None
        if media["caption"] is not None and media["caption"]["text"] is not None:
            captions = media["caption"]["text"]
        result = {
            "media_id": media_id,
            "shortcode": shortcode,
            "product_type": product_type,
            "caption": captions,
        }
        if product_type == "carousel_container":
            carousel_media = []
            for carousel in media["carousel_media"]:
                try:
                    choose_media = get_best_quality(carousel["video_versions"])
                    thumbnail = get_best_quality(carousel["image_versions2"]["candidates"])["url"]
                    choose_media.update({"thumbnail": thumbnail, "type": "video"})
                except KeyError:
                    choose_media = get_best_quality(carousel["image_versions2"]["candidates"])
                    choose_media.update({"type": "image"})
                carousel_media.append({
                    "media_id": carousel["pk"],
                    "product_type": carousel["product_type"],
                    "media": choose_media,
                })
            result.update({
                "carousel_media": carousel_media
            })
        else:
            try:
                choose_media = get_best_quality(media["video_versions"])
                thumbnail = get_best_quality(media["image_versions2"]["candidates"])["url"]
                choose_media.update({"thumbnail": thumbnail, "type": "video"})
            except KeyError:
                choose_media = get_best_quality(media["image_versions2"]["candidates"])
                choose_media.update({"type": "image"})
            result.update({
                "media": choose_media
            })
        all_media.append(result)
    return all_media