# -*- coding: UTF-8 -*-
import os
from typing import Union, Optional
from .plugin import PyTestRailPlugin
from .testrail_api import APIClient
from _pytest.config import Config
from _pytest.config.argparsing import Parser
import configparser


def pytest_addoption(parser: Parser) -> None:
    group = parser.getgroup("testrail")
    group.addoption(
        "--testrail",
        action="store_true",
        help="Create and update testruns with TestRail",
    )
    group.addoption(
        "--tr-config",
        action="store",
        default="testrail.cfg",
        help="Path to the config file containing information about the TestRail server (defaults to testrail.cfg)",
    )
    group.addoption(
        "--tr-url",
        action="store",
        help="TestRail address you use to access TestRail with your web browser (config file: url in API section)",
    )
    group.addoption(
        "--tr-email",
        action="store",
        help="Email for the account on the TestRail server (config file: email in API section)",
    )
    group.addoption(
        "--tr-password",
        action="store",
        help="Password for the account on the TestRail server (config file: password in API section)",
    )
    group.addoption(
        "--tr-timeout",
        action="store",
        help="Set timeout for connecting to TestRail server",
    )
    group.addoption(
        "--tr-testrun-assignedto-id",
        action="store",
        help="ID of the user assigned to the test run (config file: assignedto_id in TESTRUN section)",
    )
    group.addoption(
        "--tr-testrun-project-id",
        action="store",
        help="ID of the project the test run is in (config file: project_id in TESTRUN section)",
    )
    group.addoption(
        "--tr-testrun-suite-id",
        action="store",
        help="ID of the test suite containing the test cases (config file: suite_id in TESTRUN section)",
    )
    group.addoption(
        "--tr-testrun-suite-include-all",
        action="store_true",
        default=None,
        help="Include all test cases in specified test suite when creating test run (config file: include_all in TESTRUN section)",
    )
    group.addoption(
        "--tr-testrun-name",
        action="store",
        default=None,
        help="Name given to testrun, that appears in TestRail (config file: name in TESTRUN section)",
    )
    group.addoption(
        "--tr-testrun-description",
        action="store",
        default=None,
        help="Description given to testrun, that appears in TestRail (config file: description in TESTRUN section)",
    )
    group.addoption(
        "--tr-run-id",
        action="store",
        default=0,
        required=False,
        help='Identifier of testrun, that appears in TestRail. If provided, option "--tr-testrun-name" will be ignored',
    )
    group.addoption(
        "--tr-plan-id",
        action="store",
        required=False,
        help='Identifier of testplan, that appears in TestRail (config file: plan_id in TESTRUN section). If provided, option "--tr-testrun-name" will be ignored',
    )
    group.addoption(
        "--tr-version",
        action="store",
        default="",
        required=False,
        help="Indicate a version in Test Case result",
    )
    group.addoption(
        "--tr-no-ssl-cert-check",
        action="store_false",
        default=None,
        help="Do not check for valid SSL certificate on TestRail host",
    )
    group.addoption(
        "--tr-close-on-complete",
        action="store_true",
        default=False,
        required=False,
        help="Close a test run on completion",
    )
    group.addoption(
        "--tr-dont-publish-blocked",
        action="store_false",
        required=False,
        help='Determine if results of "blocked" testcases (in TestRail) are published or not',
    )
    group.addoption(
        "--tr-skip-missing",
        action="store_true",
        required=False,
        help="Skip test cases that are not present in testrun",
    )
    group.addoption(
        "--tr-milestone-id",
        action="store",
        default=None,
        required=False,
        help="Identifier of milestone, to be used in run creation (config file: milestone_id in TESTRUN section)",
    )
    group.addoption(
        "--tc-custom-comment",
        action="store",
        default=None,
        required=False,
        help="Custom comment, to be appended to default comment for test case (config file: custom_comment in TESTCASE section)",
    )


def pytest_configure(config: Config) -> None:
    if config.getoption("--testrail"):
        cfg_file_path = config.getoption("--tr-config")
        config_manager = ConfigManager(cfg_file_path, config)
        client = APIClient(
            config_manager.getoption("tr-url", "url", "API"),
            config_manager.getoption("tr-email", "email", "API"),
            config_manager.getoption("tr-password", "password", "API"),
            timeout=config_manager.getoption("tr-timeout", "timeout", "API"),
        )

        config.pluginmanager.register(
            PyTestRailPlugin(
                client=client,
                assign_user_id=int(
                    config_manager.getoption(
                        "tr-testrun-assignedto-id", "assignedto_id", "TESTRUN"
                    )
                    or 0
                ),
                project_id=int(
                    config_manager.getoption(
                        "tr-testrun-project-id", "project_id", "TESTRUN"
                    )
                    or 0
                ),
                suite_id=int(
                    config_manager.getoption(
                        "tr-testrun-suite-id", "suite_id", "TESTRUN"
                    )
                    or 0
                ),
                include_all=bool(
                    config_manager.getoption(
                        "tr-testrun-suite-include-all",
                        "include_all",
                        "TESTRUN",
                        is_bool=True,
                        default=False,
                    )
                ),
                cert_check=bool(
                    config_manager.getoption(
                        "tr-no-ssl-cert-check",
                        "no_ssl_cert_check",
                        "API",
                        is_bool=True,
                        default=True,
                    )
                ),
                tr_name=str(
                    config_manager.getoption("tr-testrun-name", "name", "TESTRUN") or ""
                ),
                tr_description=str(
                    config_manager.getoption(
                        "tr-testrun-description", "description", "TESTRUN"
                    )
                    or ""
                ),
                run_id=config.getoption("--tr-run-id"),
                plan_id=int(
                    config_manager.getoption("tr-plan-id", "plan_id", "TESTRUN") or 0
                ),
                version=config.getoption("--tr-version"),
                close_on_complete=config.getoption("--tr-close-on-complete"),
                publish_blocked=config.getoption("--tr-dont-publish-blocked"),
                skip_missing=config.getoption("--tr-skip-missing"),
                milestone_id=int(
                    config_manager.getoption(
                        "tr-milestone-id", "milestone_id", "TESTRUN"
                    )
                    or 0
                ),
                custom_comment=str(
                    config_manager.getoption(
                        "tc-custom-comment", "custom_comment", "TESTCASE"
                    )
                    or ""
                ),
            ),
            # Name of plugin instance (allow to be used by other plugins)
            name="pytest-testrail-instance",
        )


class ConfigManager(object):
    def __init__(self, cfg_file_path: Optional[str], config: Config) -> None:
        """
        Handles retrieving configuration values. Config options set in flags are given preferance over options set in the
        config file.

        :param cfg_file_path: Path to the config file containing information about the TestRail server.
        :type cfg_file_path: str or None
        :param config: Config object containing commandline flag options.
        :type config: _pytest.config.Config
        """
        self.cfg_file = None
        if cfg_file_path is not None and (
            os.path.isfile(cfg_file_path) or os.path.islink(cfg_file_path)
        ):
            self.cfg_file = configparser.ConfigParser()
            self.cfg_file.read(cfg_file_path)

        self.config = config

    def getoption(
        self,
        flag: str,
        cfg_name: str,
        section: Optional[str] = None,
        is_bool: bool = False,
        default: Optional[Union[str, bool]] = None,
    ) -> Optional[Union[str, bool]]:
        # priority: cli > config file > default

        # 1. return cli option (if set)
        value = self.config.getoption("--{}".format(flag))
        if value is not None:
            return value

        # 2. return default if not config file path is specified
        if section is None or self.cfg_file is None:
            return default

        if self.cfg_file.has_option(section, cfg_name):
            # 3. return config file value
            return (
                self.cfg_file.getboolean(section, cfg_name)
                if is_bool
                else self.cfg_file.get(section, cfg_name)
            )
        else:
            # 4. if entry not found in config file
            return default
