import os
from typing import Union

import jinja2
from loguru import logger

from httprunner import exceptions
from httprunner.exceptions import TestCaseFormatError
from httprunner.new_loader import load_testcase_file, load_folder_files

__TMPL__ = """# NOTICE: Generated By HttpRunner. DO'NOT EDIT!
import unittest

from httprunner.runner import HttpRunner
from httprunner.schema import TConfig, TStep


class {{ class_name }}(unittest.TestCase):
    config = TConfig(**{{ config }})

    teststeps = [
        {% for teststep in teststeps %}
            TStep(**{{ teststep }}),
        {% endfor %}
    ]

    def test_start(self):
        HttpRunner(self.config, self.teststeps).run()

"""


def make_testcase(testcase_path: str) -> Union[str, None]:
    logger.info(f"start to make testcase: {testcase_path}")
    try:
        testcase, _ = load_testcase_file(testcase_path)
    except TestCaseFormatError:
        return None

    template = jinja2.Template(__TMPL__)

    raw_file_name, _ = os.path.splitext(os.path.basename(testcase_path))
    # convert title case, e.g. request_with_variables => RequestWithVariables
    name_in_title_case = raw_file_name.title().replace("_", "")

    testcase_dir = os.path.dirname(testcase_path)
    testcase_python_path = os.path.join(testcase_dir, f"{raw_file_name}_test.py")

    config = testcase["config"]
    config["path"] = testcase_python_path
    data = {
        "class_name": f"TestCase{name_in_title_case}",
        "config": config,
        "teststeps": testcase["teststeps"],
    }
    content = template.render(data)

    with open(testcase_python_path, "w") as f:
        f.write(content)

    logger.info(f"generated testcase: {testcase_python_path}")
    return testcase_python_path


def main_make(tests_path: str) -> list:
    testcases = []
    if os.path.isdir(tests_path):
        files_list = load_folder_files(tests_path)
        testcases.extend(files_list)
    elif os.path.isfile(tests_path):
        testcases.append(tests_path)
    else:
        raise exceptions.TestcaseNotFound(f"Invalid tests path: {tests_path}")

    testcase_path_list = []
    for testcase_path in testcases:
        testcase_path = make_testcase(testcase_path)
        if not testcase_path:
            continue
        testcase_path_list.append(testcase_path)

    return testcase_path_list


def init_make_parser(subparsers):
    """ make testcases: parse command line options and run commands.
    """
    parser = subparsers.add_parser(
        "make",
        help="Convert YAML/JSON testcases to Python unittests.",
    )
    parser.add_argument("testcase_path", nargs="?", help="Specify YAML/JSON testcase path")

    return parser
