import json
import os
import shutil
import sys
import tempfile
from typing import List
from typing import Tuple
from unittest.mock import patch

import pytest
from expected_download import _get_files_in_directory

from ytdl_sub.cli.main import main
from ytdl_sub.config.config_file import ConfigFile
from ytdl_sub.subscriptions.subscription import Subscription
from ytdl_sub.subscriptions.subscription_download import SubscriptionDownload
from ytdl_sub.utils.file_handler import FileHandlerTransactionLog
from ytdl_sub.utils.logger import Logger
from ytdl_sub.utils.yaml import load_yaml

logger = Logger.get("test")


@pytest.fixture
def working_directory() -> str:
    """
    Any time the working directory is used, ensure no files remain on cleaning it up
    """
    with tempfile.TemporaryDirectory() as temp_dir:

        def _assert_working_directory_empty(self, is_error: bool = False):
            files = [str(file_path) for file_path in _get_files_in_directory(temp_dir)]
            num_files = len(files)
            if os.path.isdir(temp_dir):
                shutil.rmtree(temp_dir)

            if not is_error:
                if num_files > 0:
                    logger.error("left-over files in working dir:\n%s", "\n".join(files))
                assert num_files == 0

        with patch.object(
            SubscriptionDownload,
            "_delete_working_directory",
            new=_assert_working_directory_empty,
        ):
            yield temp_dir


@pytest.fixture()
def music_video_config_path():
    return "examples/music_videos_config.yaml"


def _load_config(config_path: str, working_directory: str) -> ConfigFile:
    config_dict = load_yaml(file_path=config_path)
    config_dict["configuration"]["working_directory"] = working_directory

    return ConfigFile.from_dict(config_dict)


@pytest.fixture()
def music_video_config(music_video_config_path, working_directory) -> ConfigFile:
    return _load_config(music_video_config_path, working_directory)


@pytest.fixture()
def music_video_config_for_cli(music_video_config) -> str:
    with tempfile.NamedTemporaryFile(suffix=".yaml") as tmp_file:
        tmp_file.write(json.dumps(music_video_config._value).encode("utf-8"))
        tmp_file.flush()
        yield tmp_file.name


@pytest.fixture()
def channel_as_tv_show_config(working_directory) -> ConfigFile:
    return _load_config(
        config_path="examples/tv_show_config.yaml", working_directory=working_directory
    )


@pytest.fixture()
def music_audio_config(working_directory) -> ConfigFile:
    return _load_config(
        config_path="examples/music_audio_config.yaml", working_directory=working_directory
    )


@pytest.fixture
def timestamps_file_path():
    timestamps = [
        "0:00 Intro\n",
        "00:10 Part 1\n",
        "0:20 Part 2\n",
        "00:30 Part 3\n",
        "0:00:40 Part 4\n",
        "00:01:01 Part 5\n",
    ]

    with tempfile.NamedTemporaryFile(mode="w", encoding="utf-8", suffix=".txt") as tmp:
        tmp.writelines(timestamps)
        tmp.seek(0)
        yield tmp.name


def mock_run_from_cli(args: str) -> List[Tuple[Subscription, FileHandlerTransactionLog]]:
    args_list = ["ytdl-sub"] + args.split()
    with patch.object(sys, "argv", args_list):
        return main()
