#include "core/device_lifecycle.h"

namespace aptt {

const char* ToString(DeviceLifecycleState state) {
  switch (state) {
    case DeviceLifecycleState::kDiscovered:
      return "discovered";
    case DeviceLifecycleState::kReserved:
      return "reserved";
    case DeviceLifecycleState::kPrepared:
      return "prepared";
    case DeviceLifecycleState::kRunningSignal:
      return "running-signal";
    case DeviceLifecycleState::kRunningSilence:
      return "running-silence";
    case DeviceLifecycleState::kDraining:
      return "draining";
    case DeviceLifecycleState::kHeldOpen:
      return "held-open";
    case DeviceLifecycleState::kReleasing:
      return "releasing";
    case DeviceLifecycleState::kReleased:
      return "released";
    case DeviceLifecycleState::kFaulted:
      return "faulted";
  }
  return "unknown";
}

bool IsRunning(DeviceLifecycleState state) {
  return state == DeviceLifecycleState::kRunningSignal ||
         state == DeviceLifecycleState::kRunningSilence;
}

bool IsTerminal(DeviceLifecycleState state) {
  return state == DeviceLifecycleState::kReleased ||
         state == DeviceLifecycleState::kFaulted;
}

TransitionDecision EvaluateTransition(
    DeviceLifecycleState from,
    DeviceLifecycleState to,
    const LifecyclePolicy& policy) {
  if (from == to) {
    return {true, false, "same-state observation"};
  }

  if (from == DeviceLifecycleState::kFaulted) {
    return {to == DeviceLifecycleState::kReleased, true,
            "faulted devices may only be released"};
  }

  if (from == DeviceLifecycleState::kReleased) {
    if (to == DeviceLifecycleState::kDiscovered) {
      return {policy.allow_reinitialize_loop, true,
              "released-to-discovered is a reinitialize loop and needs an explicit policy"};
    }
    return {false, true, "released devices must not be reused directly"};
  }

  switch (from) {
    case DeviceLifecycleState::kDiscovered:
      if (to == DeviceLifecycleState::kReserved ||
          to == DeviceLifecycleState::kFaulted) {
        return {true, false, "device can be reserved or faulted during open"};
      }
      break;
    case DeviceLifecycleState::kReserved:
      if (to == DeviceLifecycleState::kPrepared ||
          to == DeviceLifecycleState::kReleasing ||
          to == DeviceLifecycleState::kFaulted) {
        return {true, false, "reserved device can prepare, release, or fault"};
      }
      break;
    case DeviceLifecycleState::kPrepared:
      if (to == DeviceLifecycleState::kRunningSignal ||
          to == DeviceLifecycleState::kRunningSilence ||
          to == DeviceLifecycleState::kHeldOpen ||
          to == DeviceLifecycleState::kReleasing ||
          to == DeviceLifecycleState::kFaulted) {
        return {true, false, "prepared device can run, hold, release, or fault"};
      }
      break;
    case DeviceLifecycleState::kRunningSignal:
      if (to == DeviceLifecycleState::kRunningSilence ||
          to == DeviceLifecycleState::kDraining ||
          to == DeviceLifecycleState::kFaulted) {
        return {true, false, "signal can switch to silence, drain, or fault"};
      }
      if (to == DeviceLifecycleState::kReleasing) {
        return {policy.allow_immediate_release, true,
                "running-to-releasing skips drain and requires explicit override"};
      }
      break;
    case DeviceLifecycleState::kRunningSilence:
      if (to == DeviceLifecycleState::kRunningSignal ||
          to == DeviceLifecycleState::kDraining ||
          to == DeviceLifecycleState::kHeldOpen ||
          to == DeviceLifecycleState::kFaulted) {
        return {true, false, "silence keep-alive can resume signal, drain, hold, or fault"};
      }
      if (to == DeviceLifecycleState::kReleasing) {
        return {!policy.known_problem_device && policy.allow_immediate_release,
                true,
                "known-problem devices should drain before release"};
      }
      break;
    case DeviceLifecycleState::kDraining:
      if (to == DeviceLifecycleState::kHeldOpen ||
          to == DeviceLifecycleState::kReleasing ||
          to == DeviceLifecycleState::kFaulted) {
        return {true, false, "drained stream can hold, release, or fault"};
      }
      break;
    case DeviceLifecycleState::kHeldOpen:
      if (to == DeviceLifecycleState::kRunningSignal ||
          to == DeviceLifecycleState::kRunningSilence ||
          to == DeviceLifecycleState::kReleasing ||
          to == DeviceLifecycleState::kFaulted) {
        return {true, false, "held device can resume, release, or fault"};
      }
      break;
    case DeviceLifecycleState::kReleasing:
      if (to == DeviceLifecycleState::kReleased ||
          to == DeviceLifecycleState::kFaulted) {
        return {true, false, "releasing completes or faults"};
      }
      break;
    case DeviceLifecycleState::kReleased:
    case DeviceLifecycleState::kFaulted:
      break;
  }

  return {false, true, "transition is not allowed by lifecycle policy"};
}

}  // namespace aptt

