import ipaddress
import json
import socket
import tempfile
import time
from pathlib import Path

import click
import ifaddr


def echo_warning(msg):
    click.secho("Warning: ", fg="red", nl=False, err=True)
    click.echo("{}.".format(msg), err=True)


def echo_json(data_dict):
    click.echo(json.dumps(data_dict, indent=4, default=str))


def echo_status(status):
    if status.get("title"):
        click.echo("Title: {}".format(status["title"]))

    if status.get("current_time"):
        current = human_time(status["current_time"])
        if status.get("duration"):
            duration = human_time(status["duration"])
            remaining = human_time(status["remaining"])
            click.echo("Time: {} / {} ({}%)".format(current, duration, status["progress"]))
            click.echo("Remaining time: {}".format(remaining))
        else:
            click.echo("Time: {}".format(current))

    if status.get("player_state"):
        click.echo("State: {}".format(status["player_state"]))

    click.echo("Volume: {}".format(status["volume_level"]))
    click.echo("Volume muted: {}".format(status["volume_muted"]))


def guess_mime(path):
    # source: https://developers.google.com/cast/docs/media
    extension = Path(path).suffix.lower()
    extensions = {
        ".mp4": "video/mp4",
        ".m4a": "audio/mp4",
        ".mp3": "audio/mp3",
        ".mpa": "audio/mpeg",
        ".webm": "video/webm",
        ".mkv": "video/x-matroska",
        ".bmp": "image/bmp",
        ".jpg": "image/jpeg",
        ".jpeg": "image/jpeg",
        ".gif": "image/gif",
        ".png": "image/png",
        ".webp": "image/web",
    }
    return extensions.get(extension, "video/mp4")


def hunt_subtitles(video):
    """Searches for subtitles in the current folder"""

    video_path = Path(video)
    video_path_stem_lower = video_path.stem.lower()
    for entry_path in video_path.parent.iterdir():
        if entry_path.is_dir():
            continue
        if entry_path.stem.lower().startswith(video_path_stem_lower) and entry_path.suffix.lower() in [".vtt", ".srt"]:
            return str(entry_path.resolve())
    return None


def create_temp_file(content):
    with tempfile.NamedTemporaryFile(mode="w+b", suffix=".vtt", delete=False) as tfile:
        tfile.write(content.encode())
        return tfile.name


def human_time(seconds: int):
    return time.strftime("%H:%M:%S", time.gmtime(seconds))


def get_local_ip(host):
    """
    The primary ifaddr based approach, tries to guess the local ip from the cc ip,
    by comparing the subnet of ip-addresses of all the local adapters to the subnet of the cc ip.
    This should work on all platforms, but requires the catt box and the cc to be on the same subnet.
    As a fallback we use a socket based approach, that does not suffer from this limitation, but
    might not work on all platforms.
    """

    host_ipversion = type(ipaddress.ip_address(host))
    for adapter in ifaddr.get_adapters():
        for adapter_ip in adapter.ips:
            aip = adapter_ip.ip[0] if isinstance(adapter_ip.ip, tuple) else adapter_ip.ip
            try:
                if not isinstance(ipaddress.ip_address(aip), host_ipversion):
                    continue
            except ValueError:
                continue
            ipt = [(ip, adapter_ip.network_prefix) for ip in (aip, host)]
            catt_net, cc_net = [ipaddress.ip_network("{0}/{1}".format(*ip), strict=False) for ip in ipt]
            if catt_net == cc_net:
                return aip
            else:
                continue

    try:
        return [
            (s.connect(("8.8.8.8", 53)), s.getsockname()[0], s.close())
            for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]
        ][0][1]
    except OSError:
        return None


def is_ipaddress(device):
    try:
        ipaddress.ip_address(device)
    except ValueError:
        return False
    else:
        return True
