#pragma once

#include <filesystem>
#include <cstddef>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <vector>

#include "backends/directsound_device_discovery.h"
#include "backends/directsound_pcm_backend.h"
#include "backends/asio_driver_discovery.h"
#include "backends/asio_native_dsd_backend.h"
#include "backends/asio_pcm_backend.h"
#include "backends/kernel_streaming_pcm_backend.h"
#include "backends/mme_device_discovery.h"
#include "backends/mme_pcm_backend.h"
#include "backends/wasapi_endpoint_discovery.h"
#include "backends/wasapi_exclusive_pcm_backend.h"
#include "backends/wasapi_format_probe.h"
#include "backends/wasapi_shared_pcm_backend.h"
#include "core/audio_types.h"
#include "core/device_discovery.h"
#include "core/diagnostic_bundle.h"
#include "core/diagnostic_planner.h"
#include "core/pcm_diagnostics.h"
#include "diagnostics/null_diagnostic_session.h"

namespace aptt {

enum class DiagnosticLogFormat {
  kJsonl,
  kText,
  kCsv,
};

enum class DiagnosticLogLevel {
  kNormal,
  kVerbose,
  kCallbackTrace,
};

enum class DiagnosticCallbackMode {
  kTimerDriven,
  kEventDriven,
  kDriverCallback,
};

enum class AcceptedFormatSelectionKind {
  kNone,
  kRequestedExact,
  kUserFallback,
  kUserMixFormat,
  kUserClosestMatch,
};

enum class CapabilityCellStatus {
  kAvailable,
  kDataRangeMatch,
  kPinCreateVerified,
  kStartVerified,
  kUnsupported,
  kUnchecked,
  kInUse,
  kReferenceInfo,
  kWarning,
  kError,
  kNotApplicable,
};

std::optional<std::string> PlaybackCompletionStatusText(
    BackendApi backend,
    DeviceLifecycleState state);

struct AppCloseGuardDecision {
  bool should_block_quit = false;
  bool has_kernel_streaming_release_timeout_warning = false;
  std::string japanese_message;
  std::string english_message;
};

AppCloseGuardDecision EvaluateAppCloseGuard(
    std::optional<BackendApi> active_backend,
    std::optional<DeviceLifecycleState> lifecycle_state,
    std::string_view last_backend_error_summary);

const char* ToString(CapabilityCellStatus status);

struct DiagnosticUiSettings {
  BackendApi requested_backend = BackendApi::kWasapiShared;
  SignalMode requested_signal = SignalMode::kPcm;
  SampleType requested_sample_type = SampleType::kFloat32;
  std::uint32_t requested_sample_rate_hz = 48000;
  std::uint32_t requested_valid_bits = 32;
  std::uint32_t requested_container_bits = 32;
  std::uint32_t requested_channel_count = 2;
  std::uint32_t requested_channel_mask = 3;
  std::uint32_t requested_dsd_rate_multiplier = 64;
  double frequency_hz = 1000.0;
  double amplitude_dbfs = -20.0;
  std::uint32_t duration_ms = 1000;
  bool continuous = false;
  std::uint32_t fade_in_ms = 10;
  std::uint32_t fade_out_ms = 10;
  std::uint32_t silence_preroll_ms = 0;
  std::uint32_t silence_postroll_ms = 0;
  bool left_channel_enabled = true;
  bool right_channel_enabled = true;
  bool invert_right_phase = false;
  double phase_offset_degrees = 0.0;
  std::uint32_t mme_buffer_count = 4;
  std::uint32_t mme_buffer_duration_ms = 20;
  std::uint32_t directsound_secondary_buffer_duration_ms = 250;
  std::uint32_t directsound_write_chunk_ms = 20;
  std::uint32_t directsound_cursor_poll_interval_ms = 5;
  std::uint32_t wasapi_shared_buffer_duration_ms = 100;
  std::uint32_t wasapi_shared_render_poll_interval_ms = 5;
  std::uint32_t wasapi_exclusive_buffer_duration_ms = 100;
  std::uint32_t wasapi_exclusive_periodicity_ms = 100;
  std::uint32_t wasapi_exclusive_render_poll_interval_ms = 5;
  bool wasapi_exclusive_event_callback_enabled = true;
  bool wasapi_exclusive_alignment_retry_enabled = true;
  std::uint32_t wasapi_exclusive_event_timeout_ms = 2000;
  bool audio_thread_mmcss_enabled = true;
  std::string audio_thread_mmcss_task_name = "Pro Audio";
  std::int32_t audio_thread_mmcss_priority = 0;
  bool asio_use_output_ready_if_supported = true;
  bool high_load_diagnostics_enabled = false;
  bool high_load_risk_acknowledged = false;
  std::uint32_t high_load_render_delay_ms = 30;
  std::uint32_t high_load_delay_every_callbacks = 1;
  HoldMode hold_mode = HoldMode::kKeepWarmAfterStop;
  bool keep_alive_stream_enabled = true;
  bool drain_before_stop = true;
  std::uint32_t drain_timeout_ms = 2000;
  std::uint32_t release_cooldown_ms = 1000;
  std::uint32_t reacquire_cooldown_ms = 2000;
  std::uint32_t max_reacquire_attempts = 1;
  bool rapid_format_cycle_guard = true;
  bool manual_known_problem_device = false;
  bool expert_unsafe_release_ack = false;
  std::filesystem::path log_directory = "diagnostic_bundles";
  DiagnosticLogFormat log_format = DiagnosticLogFormat::kJsonl;
  DiagnosticLogLevel log_level = DiagnosticLogLevel::kNormal;
  bool initialization_dump_enabled = true;
  bool callback_event_logging = false;
  std::uint32_t callback_trace_limit = 8;
  std::uint32_t periodic_summary_interval_ms = 1000;
  bool overwrite_logs = false;
  bool automatic_format_matrix_enabled = false;
  bool automatic_buffer_ramp_enabled = false;
  bool automatic_start_stop_stress_enabled = false;
  bool automatic_reinitialize_enabled = false;
};

struct CapabilityCell {
  BackendApi backend = BackendApi::kNull;
  std::string backend_device_id;
  std::string backend_device_name;
  FormatDescriptor requested_format;
  std::optional<FormatDescriptor> accepted_format;
  CapabilityCellStatus result_status = CapabilityCellStatus::kUnchecked;
  bool selectable = false;
  std::string disabled_reason;
  bool reference_only = false;
  bool stale = false;
  std::vector<std::string> warning_flags;
  std::string error_symbol;
  std::string error_code_hex;
  std::map<std::string, std::string> raw_backend_fields;
  AcceptedFormatSelectionKind selection_kind =
      AcceptedFormatSelectionKind::kRequestedExact;
  std::optional<std::size_t> probe_index;
};

struct DeviceCapabilityMatrix {
  std::string target_device_group_id;
  BackendApi target_backend = BackendApi::kNull;
  std::uint64_t scan_revision = 0;
  std::vector<FormatDescriptor> rows;
  std::vector<std::uint32_t> sample_rate_columns;
  std::vector<CapabilityCell> cells;
  bool stale = false;
};

struct SelectedTestCondition {
  DeviceInfo target_device;
  BackendApi backend = BackendApi::kNull;
  std::string backend_device_id;
  std::string backend_device_name;
  FormatDescriptor requested_format;
  FormatDescriptor accepted_playback_format;
  double signal_frequency_hz = 1000.0;
  double signal_amplitude_dbfs = -20.0;
  std::uint32_t duration_ms = 1000;
  HoldMode hold_mode = HoldMode::kKeepWarmAfterStop;
  CapabilityCellStatus capability_status = CapabilityCellStatus::kUnchecked;
  std::map<std::string, std::string> raw_backend_fields;
  std::uint64_t matrix_scan_revision = 0;
  std::size_t matrix_row = 0;
  std::size_t matrix_column = 0;
};

class DiagnosticUiState {
 public:
  const char* status_text() const { return status_text_.c_str(); }
  const RealtimeStats& stats() const { return stats_; }
  const std::vector<std::string>& log_lines() const { return log_lines_; }
  const std::optional<std::filesystem::path>& bundle_path() const { return bundle_path_; }
  const DiscoverySnapshot& discovery_snapshot() const { return discovery_snapshot_; }
  const std::optional<DeviceInfo>& selected_device() const { return selected_device_; }
  const std::optional<FormatDescriptor>& selected_playback_format() const {
    return selected_playback_format_;
  }
  std::optional<BackendApi> selected_playback_backend() const {
    return selected_playback_backend_;
  }
  const std::optional<PcmRunSummary>& last_pcm_summary() const {
    return last_pcm_summary_;
  }
  const std::optional<DiagnosticPlan>& last_automatic_plan() const {
    return last_automatic_plan_;
  }
  const std::optional<DiagnosticRunScore>& last_diagnostic_score() const {
    return last_diagnostic_score_;
  }
  const FormatProbeResult& last_format_probe() const { return last_format_probe_; }
  const DiagnosticUiSettings& settings() const { return settings_; }
  const std::optional<DeviceCapabilityMatrix>& device_capability_matrix() const {
    return device_capability_matrix_;
  }
  const std::optional<SelectedTestCondition>& selected_test_condition() const {
    return selected_test_condition_;
  }
  const std::string& last_backend_error_summary() const {
    return last_backend_error_summary_;
  }
  std::uint64_t format_revision() const { return format_revision_; }
  std::uint64_t run_config_revision() const { return run_config_revision_; }
  std::optional<std::uint64_t> last_probe_format_revision() const {
    return last_probe_format_revision_;
  }
  bool last_probe_rows_are_stale() const;
  std::optional<std::uint64_t> accepted_format_settings_revision() const {
    return accepted_format_settings_revision_;
  }
  AcceptedFormatSelectionKind accepted_format_selection_kind() const {
    return accepted_format_selection_kind_;
  }
  bool accepted_format_is_stale() const;
  bool selected_test_condition_is_stale() const;
  std::string accepted_format_state_text() const;
  std::string accepted_format_state_text_japanese() const;
  std::vector<std::string> settings_warnings() const;
  bool last_run_ok() const { return last_run_ok_; }
  bool has_exportable_diagnostic() const {
    return last_playback_config_.has_value() && !last_diagnostic_events_.empty();
  }

  void UpdateSettings(DiagnosticUiSettings settings);
  FormatDescriptor BuildRequestedPcmFormatFromSettings() const;
  FormatDescriptor BuildRequestedDopCarrierFromSettings() const;
  FormatDescriptor BuildRequestedNativeDsdFormatFromSettings() const;
  FormatDescriptor requested_format_from_settings() const;
  void Tick();
  void RunNullSession(std::optional<std::filesystem::path> bundle_path = std::nullopt);
  void ExportDiagnosticBundle();
  void PlanAutomaticSingleDeviceDiagnostic();
  void RunAutomaticSingleDeviceDiagnostic();
  void LoadDiscoverySnapshot(DiscoverySnapshot snapshot);
  void LoadProbeSnapshotForCurrentFormat(DiscoverySnapshot snapshot);
  void RefreshDirectSoundDevices();
  void RefreshMmeDevices();
  void RefreshAsioDrivers();
  void RefreshKernelStreamingDevices();
  void RefreshWasapiEndpoints();
  void ProbeSelectedMmeFormats();
  void ProbeSelectedDirectSoundFormats();
  void ProbeSelectedAsioPcmFormats();
  void ProbeSelectedAsioDopFormats();
  void ProbeSelectedAsioNativeDsdFormats();
  void ProbeSelectedWasapiFormats(bool exclusive_mode = false);
  void ProbeSelectedWasapiDopFormats();
  void BuildDeviceCapabilityMatrix();
  bool SelectAcceptedFormatFromProbeIndex(std::size_t probe_index);
  bool SelectCapabilityMatrixCell(std::size_t row_index,
                                  std::size_t column_index);
  void StartDirectSoundPcm();
  void StartAsioPcm();
  void StartAsioDop();
  void StartAsioNativeDsd();
  void StartKernelStreamingPcm();
  void StartMmePcm();
  void StartWasapiSharedPcm();
  void StartWasapiExclusivePcm();
  void StartWasapiExclusiveDop();
  void StopDirectSoundPcm();
  void StopAsioNativeDsd();
  void StopAsioPcm();
  void StopKernelStreamingPcm();
  void StopMmePcm();
  void StopWasapiSharedPcm();
  void StopWasapiExclusivePcm();
  void ReleaseDirectSoundPcm();
  void ReleaseAsioNativeDsd();
  void ReleaseAsioPcm();
  void ReleaseKernelStreamingPcm();
  void ReleaseMmePcm();
  void ReleaseWasapiSharedPcm();
  void ReleaseWasapiExclusivePcm();
  bool SelectDiscoveredDeviceById(const std::string& stable_id);
  bool HasAnyActiveBackend() const;
  std::optional<BackendApi> active_backend_api() const;
  std::optional<DeviceLifecycleState> active_backend_lifecycle_state() const;
  AppCloseGuardDecision app_close_guard_decision() const;
  void InjectActiveBackendForTesting(BackendApi backend);
  void ClearInjectedActiveBackendForTesting();
  bool has_active_wasapi_shared_backend() const {
    return wasapi_shared_backend_ != nullptr;
  }
  bool has_active_wasapi_exclusive_backend() const {
    return wasapi_exclusive_backend_ != nullptr;
  }
  bool has_active_mme_backend() const {
    return mme_backend_ != nullptr;
  }
  bool has_active_directsound_backend() const {
    return directsound_backend_ != nullptr;
  }
  bool has_active_asio_backend() const {
    return asio_backend_ != nullptr;
  }
  bool has_active_asio_native_dsd_backend() const {
    return asio_native_dsd_backend_ != nullptr;
  }
  bool has_active_kernel_streaming_backend() const {
    return kernel_streaming_backend_ != nullptr;
  }

 private:
  void ApplySettingsToConfig(PlaybackConfig& config) const;
  bool EnsureStartSafety(const char* action_label);
  bool RejectIfActive(const char* action_label);
  void ResetAcceptedFormatSelection();
  void ClearProbeRows();
  void ClearDeviceCapabilityMatrix();
  void MarkDeviceCapabilityMatrixStale(std::string_view reason);
  void MarkProbeRowsFreshForCurrentFormat();
  bool SelectedSnapshotHasFormatProbeRows() const;
  bool ProbeRowsAreFreshForCurrentFormat() const;
  bool RejectIfProbeRowsStale(const char* action_label);
  bool RejectIfRequestedSignalIsNot(SignalMode signal,
                                    const char* action_label);
  bool RejectIfRequestedBackendIsNot(BackendApi backend,
                                     const char* action_label);
  bool RejectIfSelectedDeviceIsNotWasapiEndpoint(const char* action_label);
  void AcceptPlaybackFormat(FormatDescriptor format,
                            BackendApi backend,
                            AcceptedFormatSelectionKind kind,
                            std::string_view reason);
  void StoreSelectedTestCondition(BackendApi backend,
                                  FormatDescriptor requested_format,
                                  FormatDescriptor accepted_format,
                                  std::uint64_t matrix_scan_revision,
                                  std::size_t matrix_row,
                                  std::size_t matrix_column,
                                  std::string backend_device_id,
                                  std::string backend_device_name,
                                  CapabilityCellStatus capability_status,
                                  std::map<std::string, std::string> raw_backend_fields);
  void AutoSelectExactRequestedFormatFromSelectedSnapshot();
  void AppendRequestedSettingsLog(const PlaybackConfig& config,
                                  const char* action_label);
  void RecordLastRun(const PlaybackConfig& config,
                     const FormatProbeResult& format_probe,
                     const std::vector<DiagnosticEvent>& events);
  void RecordLastEvents(const std::vector<DiagnosticEvent>& events);
  std::optional<DiagnosticBundleInput> BuildCurrentBundleInput() const;
  std::optional<DiagnosticPlanRequest> BuildAutomaticPlanRequest() const;
  void AppendAsioEvents();
  void AppendAsioNativeDsdEvents();
  void AppendKernelStreamingEvents();
  void AppendDirectSoundEvents();
  void AppendMmeEvents();
  void AppendWasapiSharedEvents();
  void AppendWasapiExclusiveEvents();
  void UpdatePlaybackCompletionStatus(BackendApi backend,
                                      DeviceLifecycleState state,
                                      const RealtimeStats& stats);
  void UpdatePcmSummaryFromEvents(BackendApi backend,
                                  const std::vector<DiagnosticEvent>& events,
                                  const RealtimeStats& stats);
  void UpdateLastBackendError(const BackendError& error,
                              const char* backend_label);
  void RecordReleaseResult(BackendApi backend, const OperationResult& result);

  std::string status_text_ = "idle";
  RealtimeStats stats_{};
  std::vector<std::string> log_lines_;
  std::optional<std::filesystem::path> bundle_path_;
  DiscoverySnapshot discovery_snapshot_{};
  std::optional<DeviceInfo> selected_device_;
  std::optional<FormatDescriptor> selected_playback_format_;
  std::optional<BackendApi> selected_playback_backend_;
  std::optional<PcmRunSummary> last_pcm_summary_;
  std::optional<PlaybackConfig> last_playback_config_;
  FormatProbeResult last_format_probe_{};
  bool last_release_attempted_ = false;
  bool last_release_ok_ = false;
  std::string last_release_backend_ = "none";
  std::string last_release_status_ = "not-attempted";
  std::string last_release_error_;
  RealtimeStats last_release_stats_{};
  std::optional<std::uint64_t> last_probe_format_revision_;
  bool last_probe_has_format_rows_ = false;
  std::vector<DiagnosticEvent> last_diagnostic_events_;
  std::optional<DiagnosticPlan> last_automatic_plan_;
  std::optional<DiagnosticRunScore> last_diagnostic_score_;
  std::optional<DeviceCapabilityMatrix> device_capability_matrix_;
  std::optional<SelectedTestCondition> selected_test_condition_;
  DiagnosticUiSettings settings_;
  std::uint64_t format_revision_ = 0;
  std::uint64_t run_config_revision_ = 0;
  std::uint64_t capability_matrix_revision_ = 0;
  std::optional<std::uint64_t> accepted_format_settings_revision_;
  AcceptedFormatSelectionKind accepted_format_selection_kind_ =
      AcceptedFormatSelectionKind::kNone;
  std::string last_backend_error_summary_ = "none";
  std::unique_ptr<MmePcmBackend> mme_backend_;
  std::unique_ptr<AsioPcmBackend> asio_backend_;
  std::unique_ptr<AsioNativeDsdBackend> asio_native_dsd_backend_;
  std::unique_ptr<KernelStreamingPcmBackend> kernel_streaming_backend_;
  std::unique_ptr<DirectSoundPcmBackend> directsound_backend_;
  std::unique_ptr<WasapiSharedPcmBackend> wasapi_shared_backend_;
  std::unique_ptr<WasapiExclusivePcmBackend> wasapi_exclusive_backend_;
  std::size_t mme_event_count_ = 0;
  std::size_t asio_event_count_ = 0;
  std::size_t asio_native_dsd_event_count_ = 0;
  std::size_t kernel_streaming_event_count_ = 0;
  std::size_t directsound_event_count_ = 0;
  std::size_t wasapi_shared_event_count_ = 0;
  std::size_t wasapi_exclusive_event_count_ = 0;
  std::optional<std::string> last_playback_completion_status_;
  std::optional<BackendApi> injected_active_backend_for_testing_;
  bool last_run_ok_ = true;
};

}  // namespace aptt
