import json
import os
from json.decoder import JSONDecodeError
import click
import logging

from argus.client.base import TestStatus
from argus.client.generic.client import ArgusGenericClient

LOGGER = logging.getLogger(__name__)


def validate_extra_headers(ctx, param, value):
    if isinstance(value, dict):
        return value

    try:
        return json.loads(value)
    except JSONDecodeError as ex:
        raise click.BadParameter(f"--extra-headers should be in json format:\n\n{value}\n\n{ex}")


@click.group
def cli():
    pass


@click.command("submit")
@click.option("--api-key", help="Argus API key for authorization", required=True, envvar='ARGUS_AUTH_TOKEN')
@click.option("--base-url", default="https://argus.scylladb.com", help="Base URL for argus instance")
@click.option("--use-tunnel/--no-use-tunnel", default=None, help="Route API calls through SSH tunnel")
@click.option("--log-dir", default=".", show_default=True, help="Directory for the argus_replay_log JSONL file")
@click.option("--id", required=True, help="UUID (v4 or v1) unique to the job")
@click.option("--build-id", required=True, help="Unique job identifier in the build system, e.g. scylla-master/group/job for jenkins (The full path)")
@click.option("--build-url", required=True, help="Job URL in the build system")
@click.option("--started-by", required=True, help="Username of the user who started the job")
@click.option("--sub-type", required=False, help="Sub-type of the generic test: pytest, dtest")
@click.option("--scylla-version", required=False, default=None, help="Version of Scylla used for this job")
@click.option("--extra-headers", default={}, type=click.UNPROCESSED, callback=validate_extra_headers, help="extra headers to pass to argus, should be in json format", envvar='ARGUS_EXTRA_HEADERS')
def submit_run(api_key: str, base_url: str, use_tunnel: bool | None, log_dir: str, id: str, build_id: str, build_url: str, started_by: str,
               sub_type: str = None, scylla_version: str = None, extra_headers: dict | None = None):
    LOGGER.info("Submitting %s (%s) to Argus...", build_id, id)
    with ArgusGenericClient(
        auth_token=api_key,
        base_url=base_url,
        log_dir=log_dir,
        extra_headers=extra_headers,
        use_tunnel=use_tunnel,
    ) as client:
        client.submit_generic_run(build_id=build_id, run_id=id, started_by=started_by,
                                  build_url=build_url, scylla_version=scylla_version, sub_type=sub_type)
    LOGGER.info("Done.")


@click.command("finish")
@click.option("--api-key", help="Argus API key for authorization", required=True, envvar='ARGUS_AUTH_TOKEN')
@click.option("--base-url", default="https://argus.scylladb.com", help="Base URL for argus instance")
@click.option("--use-tunnel/--no-use-tunnel", default=None, help="Route API calls through SSH tunnel")
@click.option("--log-dir", default=".", show_default=True, help="Directory for the argus_replay_log JSONL file")
@click.option("--id", required=True, help="UUID (v4 or v1) unique to the job")
@click.option("--status", required=True, help="Resulting job status")
@click.option("--scylla-version", required=False, default=None, help="Version of Scylla used for this job")
@click.option("--extra-headers", default={}, type=click.UNPROCESSED, callback=validate_extra_headers, help="extra headers to pass to argus, should be in json format", envvar='ARGUS_EXTRA_HEADERS')
def finish_run(api_key: str, base_url: str, use_tunnel: bool | None, log_dir: str, id: str, status: str,
               scylla_version: str = None, extra_headers: dict | None = None):
    with ArgusGenericClient(
        auth_token=api_key,
        base_url=base_url,
        log_dir=log_dir,
        extra_headers=extra_headers,
        use_tunnel=use_tunnel,
    ) as client:
        status = TestStatus(status)
        client.finalize_generic_run(run_id=id, status=status, scylla_version=scylla_version)


@click.command("trigger-jobs")
@click.option("--api-key", help="Argus API key for authorization", required=True, envvar='ARGUS_AUTH_TOKEN')
@click.option("--base-url", default="https://argus.scylladb.com", help="Base URL for argus instance")
@click.option("--use-tunnel/--no-use-tunnel", default=None, help="Route API calls through SSH tunnel")
@click.option("--log-dir", default=".", show_default=True, help="Directory for the argus_replay_log JSONL file")
@click.option("--version", help="Scylla version to filter plans by", default=None, required=False)
@click.option("--plan-id", help="Specific plan id for filtering", default=None, required=False)
@click.option("--release", help="Release name to filter plans by", default=None, required=False)
@click.option("--job-info-file", required=True, help="JSON file with trigger information (see detailed docs)")
@click.option("--extra-headers", default={}, type=click.UNPROCESSED, callback=validate_extra_headers, help="extra headers to pass to argus, should be in json format", envvar='ARGUS_EXTRA_HEADERS')
def trigger_jobs(api_key: str, base_url: str, use_tunnel: bool | None, log_dir: str, job_info_file: str, version: str,
                 plan_id: str, release: str, extra_headers: dict | None = None):
    if not os.path.exists(job_info_file):
        LOGGER.error("File not found: %s", job_info_file)
        exit(128)
    with open(job_info_file, "rt", encoding="utf-8") as fh:
        payload = json.load(fh)
    with ArgusGenericClient(
        auth_token=api_key,
        base_url=base_url,
        log_dir=log_dir,
        extra_headers=extra_headers,
        use_tunnel=use_tunnel,
    ) as client:
        client.trigger_jobs({"release": release, "version": version, "plan_id": plan_id, **payload})


cli.add_command(submit_run)
cli.add_command(finish_run)
cli.add_command(trigger_jobs)


if __name__ == "__main__":
    cli()
