#!/usr/bin/env python3
import argparse
import time
import json
import os
import sys
from logging import DEBUG, ERROR
from pathlib import Path, PurePath
import spotipy
from spotipy.oauth2 import SpotifyClientCredentials

from spotify_dl.constants import VERSION
from spotify_dl.scaffold import log, setLogLevel, console, get_tokens
from spotify_dl.spotify import (
    fetch_tracks,
    parse_spotify_url,
    validate_spotify_urls,
    get_item_name,
)

from spotify_dl.youtube import (
    download_songs,
    default_filename,
    playlist_num_filename,
    dump_json,
)


def spotify_dl():
    """Main entry point of the script."""
    parser = argparse.ArgumentParser(prog="spotify_dl")
    parser.add_argument(
        "-l",
        "--url",
        action="store",
        help="Spotify Playlist link URL",
        type=str,
        nargs="+",
        required=False,  # this has to be set to false to prevent useless prompt for url when all user wants is the script version
    )
    parser.add_argument(
        "-o",
        "--output",
        type=str,
        action="store",
        help="Specify download directory.",
        required=False,
        default=".",
    )
    parser.add_argument(
        "-d",
        "--download",
        action="store_true",
        help="Download using youtube-dl",
        default=True,
    )
    parser.add_argument(
        "-j",
        "--dump-json",
        action="store_true",
        help="Dump info-json using youtube-dl",
        default=False,
    )
    parser.add_argument(
        "-f",
        "--format_str",
        type=str,
        action="store",
        help="Specify youtube-dl format string.",
        default="bestaudio/best",
    )
    parser.add_argument(
        "-k",
        "--keep_playlist_order",
        default=False,
        action="store_true",
        help="Whether to keep original playlist ordering or not.",
    )
    parser.add_argument(
        "-m",
        "--skip_mp3",
        action="store_true",
        help="Don't convert downloaded songs to mp3",
    )
    parser.add_argument(
        "-s",
        "--use_sponsorblock",
        default="no",
        action="store",
        help="Whether to skip non-music sections using SponsorBlock API. Pass y or yes to skip using SponsorBlock",
    )
    parser.add_argument(
        "-w",
        "--no-overwrites",
        action="store_true",
        help="Whether we should avoid overwriting the target audio file if it already exists",
        default=False,
    )
    parser.add_argument(
        "-r",
        "--remove-trailing-tracks",
        default="no",
        action="store",
        help="Whether we should delete tracks that were previously downloaded but are not longer in the playlist",
    )
    parser.add_argument(
        "-V",
        "--verbose",
        action="store_true",
        help="Show more information on what" "s happening.",
    )
    parser.add_argument(
        "-v",
        "--version",
        action="store_true",
        help="Shows current version of the program",
    )
    parser.add_argument(
        "-mc",
        "--multi_core",
        action="store",
        type=str,
        default=0,
        help="Use multiprocessing [-m [int:numcores]",
    )
    parser.add_argument(
        "-p",
        "--proxy",
        action="store",
        type=str,
        default="",
        help="Download through a proxy. Support HTTP & SOCKS5. Use 'http://username:password@hostname:port' or 'http://hostname:port'",
    )
    args = parser.parse_args()
    num_cores = os.cpu_count()
    args.multi_core = int(args.multi_core)

    if args.dump_json:
        setLogLevel(ERROR)
    if args.verbose:
        setLogLevel(DEBUG)

    log.info("Starting spotify_dl v%s", VERSION)
    log.debug("Setting debug mode on spotify_dl")

    if args.multi_core > (num_cores - 1):
        log.info(
            "Requested cores %d exceeds available %d, using %d cores.",
            args.multi_core,
            num_cores,
            num_cores - 1,
        )
        args.multi_core = num_cores - 1
    if args.version:
        console.print(f"spotify_dl [bold green]v{VERSION}[/bold green]")
        sys.exit(0)

    if os.path.isfile(os.path.expanduser("~/.spotify_dl_settings")):
        with open(os.path.expanduser("~/.spotify_dl_settings")) as file:
            config = json.load(file)
            print(config)

        for key, value in config.items():
            if (isinstance(value, bool) and value) or (
                isinstance(value, str) and value and value.lower() in ["true", "t"]
            ):
                setattr(args, key, True)
            else:
                setattr(args, key, value)

    if not args.url:
        raise (Exception("No playlist url provided:"))

    tokens = get_tokens()
    if tokens is None:
        sys.exit(1)
    client_id, client_secret = tokens

    sp = spotipy.Spotify(
        auth_manager=SpotifyClientCredentials(
            client_id=client_id, client_secret=client_secret
        )
    )
    log.debug("Arguments: %s ", args)
    log.info("Sponsorblock enabled?: %s", args.use_sponsorblock)
    valid_urls = validate_spotify_urls(args.url)
    if not valid_urls:
        sys.exit(1)

    url_data = {"urls": []}
    start_time = time.time()
    for url in valid_urls:
        url_dict = {}
        item_type, item_id = parse_spotify_url(url)
        directory_name = get_item_name(sp, item_type, item_id)
        url_dict["save_path"] = Path(
            PurePath.joinpath(Path(args.output), Path(directory_name))
        )
        url_dict["save_path"].mkdir(parents=True, exist_ok=True)
        log.info("Saving songs to %s directory", directory_name)
        url_dict["songs"] = fetch_tracks(sp, item_type, item_id)
        url_data["urls"].append(url_dict.copy())
    if args.dump_json is True:
        dump_json(url_dict["songs"])
    elif args.download is True:
        file_name_f = default_filename
        if args.keep_playlist_order:
            file_name_f = playlist_num_filename

        download_songs(
            songs=url_data,
            output_dir=args.output,
            format_str=args.format_str,
            skip_mp3=args.skip_mp3,
            keep_playlist_order=args.keep_playlist_order,
            no_overwrites=args.no_overwrites,
            remove_trailing_tracks=(args.remove_trailing_tracks[0].lower()),
            use_sponsorblock=args.use_sponsorblock,
            file_name_f=file_name_f,
            multi_core=args.multi_core,
            proxy=args.proxy,
        )
    log.info("Download completed in %.2f seconds.", time.time() - start_time)


if __name__ == "__main__":
    spotify_dl()
