#!/usr/bin/env python3
#
# Copyright 2024 - The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the',  help="License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an',  help="AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging
from pathlib import Path
import platform

from environment import get_default_environment
from tasks.task import Task
from utils import (
    AOSP_ROOT,
    EMULATOR_ARTIFACT_PATH,
    binary_extension,
    run,
)

PYTEST_DIR = AOSP_ROOT / "external" / "adt-infra" / "pytest" / "test_embedded"
OBJS_DIR = AOSP_ROOT / "tools" / "netsim" / "objs"


class RunPyTestTask(Task):

  def __init__(self, args):
    super().__init__("RunPyTest")
    self.buildbot = args.buildbot
    self.pytest_input_dir = args.pytest_input_dir

  def do_run(self):
    run_pytest_manager = RunPytestManager(self.buildbot, self.pytest_input_dir)
    return run_pytest_manager.process()


class RunPytestManager:
  """Manager for running e2e integration pytests with Emulator

  The prerequisite is that the emulator installation has to be completed.
  RunPytestManager runs a run_tests shell script in external/adt-infra.
  It will take the emulator binary installed as the argument for the
  script.

  Attributes:

  buildbot: A boolean indicating if it's being invoked with Android Build
    Bots
  """

  def __init__(self, buildbot, pytest_input_dir):
    """Initializes the instances based on environment

    Args:
        buildbot: Defines if it's being invoked with Build Bots and defines
          self.dir as the directory of the emulator binary
        pytest_input_dir: Defined the directory that includes netsim and
          emulator binaries and libraries. Ignore if the string is empty.
    """
    # Default self.dir
    self.dir = EMULATOR_ARTIFACT_PATH / "emulator" if buildbot else OBJS_DIR

    # If pytest_input_dir is provided, set self.dir accordingly
    if pytest_input_dir:
      try:
        self.dir = AOSP_ROOT / "tools" / "netsim" / Path(pytest_input_dir)
      except Exception as e:
        logging.error(f"Invalid pytest_input_dir value: {e}")

  def _run_with_n_attempts(cmd, n):
    for attempt in range(1, n + 1):
      try:
        run(cmd, get_default_environment(AOSP_ROOT), "e2e_pytests")
        return
      except Exception as e:
        if attempt == n:
          raise e
        else:
          logging.error(f"PyTest Attempt {attempt} Error: {e}")

  def process(self) -> bool:
    """Process the emulator e2e pytests

    The process will check if the emulator installation occurred
    and run the run_tests.sh script.
    """
    emulator_bin = self.dir / binary_extension("emulator")
    if not (self.dir.exists() and emulator_bin.exists()):
      logging.info(
          "Please run 'scripts/build_tools.sh --InstallEmulator' "
          "before running RunPyTest"
      )
      return False
    if platform.system() == "Windows":
      run_tests_script = PYTEST_DIR / "run_tests.cmd"
    else:
      run_tests_script = PYTEST_DIR / "run_tests.sh"
    if platform.system() == "Linux":
      test_config = PYTEST_DIR / "cfg" / "netsim_linux_tests.json"
    else:
      test_config = PYTEST_DIR / "cfg" / "netsim_tests.json"
    cmd = [
        run_tests_script,
        "--emulator",
        emulator_bin,
        "--test_config",
        test_config,
    ]
    # TODO: Resolve Windows PyTest failure
    if platform.system() != "Windows":
      cmd.append("--failures_as_errors")
      run(cmd, get_default_environment(AOSP_ROOT), "e2e_pytests")
    return True
