# Copyright 2024-2025 Ping Identity Corporation. All Rights Reserved
#
# This code is to be used exclusively in connection with Ping Identity
# Corporation software or services. Ping Identity Corporation only offers
# such software or services to legal entities who have entered into a
# binding license agreement with Ping Identity Corporation.

# -*- coding: utf-8 -*-

# load tasks used by configuration file

# Python imports
import os

# Framework imports
from pyrock.lib.scheduler.tasks.StepTask import StepTask
from pyrock.lib.PyRockRun import get_pyrock_run
from pyrock.tasks.scenario.ds_sdk import DSModRateTask, DSAddRateTask
from pyrock.tasks.ds.replication import CheckReplicationTask
from pyrock.tasks.scenario.ds_sdk import GenerateDSAddRateTemplateTask
from pyrock.tasks.deployment.installation import DeployOverseerTask
from pyrock.tasks.ds.add_entries import AddEntries
from pyrock.tasks.ds.display_num_entries import DisplayNumEntries
from pyrock.lib.scheduler.tasks.ScaleTask import ScaleTask
from shared.lib.utils.cmd.cmd import run_command
from shared.lib.utils.utilities import running_in_venv
from shared.lib.chaos import Chaos

pyrock_run = get_pyrock_run()


class ChaosStepTask(StepTask):

    DATE = run_command("date +%Y-%m-%d-%H-%M-%S").stdout
    _chaos_instance = None

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        if self._chaos_instance is None:
            self._chaos_instance = Chaos()

    @property
    def chaos(self):
        return self._chaos_instance


class PrepareEnvironment(ChaosStepTask):

    def step1(self):
        pyrock_run.log("Install Python requirements")

        pip = "pip3" if not running_in_venv() else "python3 -m pip"

        # do not use --user param when virtual environment is used
        user_param = "" if "VIRTUAL_ENV" in os.environ and os.environ["VIRTUAL_ENV"] != "" else "--user"

        run_command(
            f"{pip} install "
            f"--requirement {self.chaos.repo_path}/scripts/requirements.txt "
            "--index-url https://pypi.python.org/simple/ "
            "--no-cache-dir "
            "--no-warn-script-location "
            f"{user_param} "
        )


class InstallPackages(ChaosStepTask):

    def step1(self):
        pyrock_run.log('Install package "go"')

        self.chaos.chaos_script(
            script_name="pkg_go.py",
            script_options="install "
            # Need to specify temporary directory out of {self.chaos.repo_path}/work
            # Because the work directory will be removed in the next run,
            # So the link to the command 'go' will be broken
            f"--tmp-dir {self.chaos.repo_work_dir}/tmp --log-file-name pkg-install-go.log",
        )

    def step2(self):
        pyrock_run.log('Install package "litmusctl"')

        self.chaos.chaos_script(
            script_name="pkg_litmusctl.py",
            script_options="install "
            f"--tmp-dir {self.chaos.repo_work_dir}/tmp "
            "--log-file-name pkg-install-litmusctl.log",
        )


class InstallNamespaces(ChaosStepTask):

    def step1(self):
        pyrock_run.log('Install namespace "litmuschaos"')

        self.chaos.chaos_script(
            script_name="ns_litmuschaos.py",
            script_options="install "
            f"--clusters-dir {self.chaos.repo_work_dir}/clusters "
            "--log-file-name ns-install-litmuschaos.log "
            "--non-interactive",
        )


class PrepareLitmusChaos(ChaosStepTask):

    @property
    def common_litmusctl_options(self):
        return (
            f"--work-dir {self.chaos.repo_work_dir}/litmusctl "
            f"--config {self.chaos.repo_work_dir}/litmusctl/.litmusctl-connections "
            "--non-interactive"
        )

    def step1(self):
        pyrock_run.log("Start LitmusChaos")

        self.chaos.chaos_script(
            script_name="ns_litmuschaos.py",
            script_options="start "
            f"--clusters-dir {self.chaos.repo_work_dir}/clusters "
            "--log-file-name ns-start-litmuschaos.log "
            "--non-interactive",
        )

    def step2(self):
        pyrock_run.log("Connect to LitmusChaos")

        run_command(
            "litmusctl user connection login "
            '--url "http://127.0.0.1:9494" '
            '--user-username "admin" '
            '--user-password "litmus" '
            f"{self.common_litmusctl_options}"
        )

        run_command(
            "litmusctl user connection set "
            '--url "http://127.0.0.1:9494" '
            '--user-username "admin" '
            f"{self.common_litmusctl_options}"
        )

    def step3(self):
        pyrock_run.log("Configure LitmusChaos resources")

        run_command(f'litmusctl project create --project-name "{self.DATE}-project" {self.common_litmusctl_options}')

        run_command(
            "litmusctl environment create "
            f'--project-name "{self.DATE}-project" '
            f'--environment-name "{self.DATE}-environment" '
            '--environment-type "Non-Production" '
            f"{self.common_litmusctl_options}"
        )

        run_command(
            "litmusctl infrastructure create "
            f'--project-name "{self.DATE}-project" '
            f'--environment-name "{self.DATE}-environment" '
            f'--infrastructure-name "{self.DATE}-infrastructure" '
            '--infrastructure-scope "Cluster" '
            f'--infrastructure-namespace "{self.DATE}-infrastructure-ns" '
            f'--infrastructure-service-account "{self.DATE}-infrastructure-sa" '
            '--infrastructure-platform-name "Others" '
            '--skipSSL "true" '
            f"{self.common_litmusctl_options}"
        )

    def step4(self):
        pyrock_run.log("Create LitmusChaos probes")

        for target_pod in ["ds-idrepo-0", "ds-idrepo-1", "ds-idrepo-2", "ds-idrepo-3"]:
            run_command(
                "litmusctl probe create "
                f'--project-name "{self.DATE}-project" '
                f'--probe-name "{self.DATE}-probe-{target_pod}" '
                '--probe-type "K8S" '
                '--probe-timeout "10m" '
                '--probe-interval "1m" '
                '--probe-k8s-resource-group "apps" '
                '--probe-k8s-resource-version "v1" '
                '--probe-k8s-resource "statefulsets" '
                f'--probe-k8s-namespace "{pyrock_run.get_namespace()}" '
                f'--probe-k8s-resource-names "{target_pod}" '
                '--probe-k8s-operation "Present" '
                f"{self.common_litmusctl_options}"
            )


class RunChaosExperiment(ChaosStepTask):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.exp_name = None
        self.exp_template = None
        self.exp_duration = None
        self.target_pod = None

    def pre(self):
        self.is_option("name", required=True)
        self.is_option("template", required=True)
        self.is_option("duration", required=True)
        self.is_option("target-pod", required=True)

        self.exp_name = self.get_option("name")
        self.exp_template = self.get_option("template")
        self.exp_duration = self.get_option("duration")
        self.target_pod = self.get_option("target-pod")

    def step1(self):
        pyrock_run.log("Run chaos experiment")

        replacements = {"EXPERIMENT_DATE": self.DATE, "EXPERIMENT_TARGET_POD": self.target_pod}

        self.chaos.chaos_script(
            script_name="experiment_litmuschaos.py",
            script_options="run-experiment "
            f"--clusters-dir {self.chaos.repo_work_dir}/clusters "
            f"--litmusctl-connections-file {self.chaos.repo_work_dir}/litmusctl/.litmusctl-connections "
            f"--litmus-project-name {self.DATE}-project "
            f"--litmus-environment-name {self.DATE}-environment "
            f"--litmus-infrastructure-name {self.DATE}-infrastructure "
            f"--litmus-infrastructure-ns-name {self.DATE}-infrastructure-ns "
            f"--exp-template {pyrock_run.get_test_path()}/config/{self.exp_template} "
            f"--exp-name {self.DATE}-{self.exp_name} "
            f"--exp-duration {self.exp_duration} "
            f'--template-replacements {",".join([f"{k}={v}" for k, v in replacements.items()])} '
            f"--template-exp-ns-name {pyrock_run.get_namespace()} "
            f"--log-file-name exp-run-{self.DATE}-{self.exp_name}.log "
            "--non-interactive",
        )

    def step2(self):
        pyrock_run.log("Analyze chaos experiment")

        self.chaos.chaos_script(
            script_name="experiment_litmuschaos.py",
            script_options="analyze-experiment "
            f"--clusters-dir {self.chaos.repo_work_dir}/clusters "
            f"--litmusctl-connections-file {self.chaos.repo_work_dir}/litmusctl/.litmusctl-connections "
            f"--litmus-project-name {self.DATE}-project "
            f"--litmus-environment-name {self.DATE}-environment "
            f"--litmus-infrastructure-name {self.DATE}-infrastructure "
            f"--litmus-infrastructure-ns-name {self.DATE}-infrastructure-ns "
            f"--exp-name {self.DATE}-{self.exp_name} "
            f"--log-file-name exp-analyze-{self.DATE}-{self.exp_name}.log "
            "--non-interactive",
        )
