#
# Copyright (C) 2024 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "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 "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.
#

from abc import ABC, abstractmethod
from command_executor import ProfilerCommandExecutor, \
  UserSwitchCommandExecutor, BootCommandExecutor, AppStartupCommandExecutor, \
  ConfigCommandExecutor, WEB_UI_ADDRESS
from validation_error import ValidationError
from open_ui import open_trace

ANDROID_SDK_VERSION_T = 33

class Command(ABC):
  """
  Abstract base class representing a command.
  """
  def __init__(self, type):
    self.type = type
    self.command_executor = None

  def get_type(self):
    return self.type

  def execute(self, device):
    return self.command_executor.execute(self, device)

  @abstractmethod
  def validate(self, device):
    raise NotImplementedError


class ProfilerCommand(Command):
  """
  Represents commands which profile and trace the system.
  """
  def __init__(self, type, event, profiler, out_dir, dur_ms, app, runs,
      simpleperf_event, perfetto_config, between_dur_ms, ui,
      excluded_ftrace_events, included_ftrace_events, from_user, to_user,
      scripts_path, symbols):
    super().__init__(type)
    self.event = event
    self.profiler = profiler
    self.out_dir = out_dir
    self.dur_ms = dur_ms
    self.app = app
    self.runs = runs
    self.simpleperf_event = simpleperf_event
    self.perfetto_config = perfetto_config
    self.between_dur_ms = between_dur_ms
    self.use_ui = ui
    self.excluded_ftrace_events = excluded_ftrace_events
    self.included_ftrace_events = included_ftrace_events
    self.from_user = from_user
    self.to_user = to_user
    self.scripts_path = scripts_path
    self.symbols = symbols
    match event:
      case "custom":
        self.command_executor = ProfilerCommandExecutor()
      case "user-switch":
        self.original_user = None
        self.command_executor = UserSwitchCommandExecutor()
      case "boot":
        self.command_executor = BootCommandExecutor()
      case "app-startup":
        self.command_executor = AppStartupCommandExecutor()
      case _:
        raise ValueError("Invalid event name was used.")

  def validate(self, device):
    print("Further validating arguments of ProfilerCommand.")
    if self.simpleperf_event is not None:
      error = device.simpleperf_event_exists(self.simpleperf_event)
      if error is not None:
        return error
    match self.event:
      case "user-switch":
        return self.validate_user_switch(device)
      case "boot":
        return self.validate_boot(device)
      case "app-startup":
        return self.validate_app_startup(device)

  def validate_user_switch(self, device):
    error = device.user_exists(self.to_user)
    if error is not None:
      return error
    self.original_user = device.get_current_user()
    if self.from_user is None:
      self.from_user = self.original_user
    else:
      error = device.user_exists(self.from_user)
      if error is not None:
        return error
    if self.from_user == self.to_user:
      return ValidationError("Cannot perform user-switch to user %s because"
                             " the current user on device %s is already %s."
                             % (self.to_user, device.serial, self.from_user),
                             "Choose a --to-user ID that is different than"
                             " the --from-user ID.")
    return None

  @staticmethod
  def validate_boot(device):
    if device.get_android_sdk_version() < ANDROID_SDK_VERSION_T:
      return ValidationError(
          ("Cannot perform trace on boot because only devices with version Android 13"
           " (T) or newer can be configured to automatically start recording traces on"
           " boot."), ("Update your device or use a different device with"
                      " Android 13 (T) or newer."))
    return None

  def validate_app_startup(self, device):
    packages = device.get_packages()
    if self.app not in packages:
      return ValidationError(("Package %s does not exist on device with serial"
                              " %s." % (self.app, device.serial)),
                             ("Select from one of the following packages on"
                              " device with serial %s: \n\t %s"
                              % (device.serial, (",\n\t ".join(packages)))))
    if device.is_package_running(self.app):
      return ValidationError(("Package %s is already running on device with"
                              " serial %s." % (self.app, device.serial)),
                             ("Run 'adb -s %s shell am force-stop %s' to close"
                              " the package %s before trying to start it."
                              % (device.serial, self.app, self.app)))
    return None


class ConfigCommand(Command):
  """
  Represents commands which get information about the predefined configs.
  """
  def __init__(self, type, config_name, file_path, dur_ms,
      excluded_ftrace_events, included_ftrace_events):
    super().__init__(type)
    self.config_name = config_name
    self.file_path = file_path
    self.dur_ms = dur_ms
    self.excluded_ftrace_events = excluded_ftrace_events
    self.included_ftrace_events = included_ftrace_events
    self.command_executor = ConfigCommandExecutor()

  def validate(self, device):
    raise NotImplementedError


class OpenCommand(Command):
  """
  Represents commands which open traces.
  """
  def __init__(self, file_path):
    super().__init__(type)
    self.file_path = file_path

  def validate(self, device):
    raise NotImplementedError

  def execute(self, device):
    open_trace(self.file_path, WEB_UI_ADDRESS)
