#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <string>
#include <string_view>
#include <vector>

#include "core/pcm_diagnostics.h"

namespace {

void Expect(bool condition, std::string_view message) {
  if (!condition) {
    std::cerr << "FAILED: " << message << "\n";
    std::exit(1);
  }
}

aptt::DiagnosticEvent RuntimeEvent(aptt::BackendApi backend,
                                   std::string key,
                                   std::string value) {
  aptt::DiagnosticEvent event;
  event.type = aptt::DiagnosticEventType::kRuntimeStats;
  event.backend = backend;
  event.device_id = "fixture-device";
  event.backend_fields.emplace(std::move(key), std::move(value));
  return event;
}

void TestMetricAvailabilityIsBackendSpecific() {
  const auto mme = aptt::PcmMetricAvailabilityForBackend(aptt::BackendApi::kMme);
  Expect(mme.queue_depth, "MME exposes queue depth");
  Expect(!mme.padding_frames, "MME padding is unsupported");

  const auto wasapi =
      aptt::PcmMetricAvailabilityForBackend(aptt::BackendApi::kWasapiShared);
  Expect(wasapi.padding_frames, "WASAPI exposes padding");
  Expect(wasapi.device_invalidation, "WASAPI exposes invalidation");
  Expect(!wasapi.lock_unlock_timing, "WASAPI lock timing is unsupported");

  const auto directsound =
      aptt::PcmMetricAvailabilityForBackend(aptt::BackendApi::kDirectSound);
  Expect(directsound.play_write_cursor, "DirectSound exposes cursors");
  Expect(directsound.lock_unlock_timing, "DirectSound exposes lock timing");
  Expect(directsound.lost_buffer_events, "DirectSound exposes lost buffers");
}

void TestPcmSummaryPreservesCommonCountersAndUnsupportedMetrics() {
  aptt::RealtimeStats stats;
  stats.frames_generated = 100;
  stats.frames_submitted = 120;
  stats.frames_accepted = 120;
  stats.callback_count = 4;
  std::vector<aptt::DiagnosticEvent> events;
  events.push_back(RuntimeEvent(aptt::BackendApi::kMme, "queue_depth", "3"));

  const auto summary = aptt::BuildPcmRunSummary(
      aptt::BackendApi::kMme,
      "mme:waveout:1",
      events,
      stats);

  Expect(summary.common_counters.frames_generated == 100,
         "common frame counter is preserved");
  Expect(summary.backend_fields.at("queue_depth") == "3",
         "MME queue depth is preserved");
  Expect(!summary.auto_retry_attempted, "summary does not imply auto retry");
  Expect(!summary.auto_backend_switch_attempted,
         "summary does not imply backend switch");
  Expect(std::find(summary.unsupported_metrics.begin(),
                   summary.unsupported_metrics.end(),
                   "padding_frames") != summary.unsupported_metrics.end(),
         "unsupported padding metric is explicit");
}

void TestDirectSoundSummaryPreservesCursorAndRestoreFields() {
  aptt::RealtimeStats stats;
  stats.frames_generated = 200;
  stats.frames_submitted = 240;
  stats.frames_accepted = 240;
  stats.callback_count = 6;
  stats.discontinuity_count = 1;

  std::vector<aptt::DiagnosticEvent> events;
  events.push_back(RuntimeEvent(
      aptt::BackendApi::kDirectSound,
      "play_cursor_bytes",
      "1024"));
  events.push_back(RuntimeEvent(
      aptt::BackendApi::kDirectSound,
      "write_cursor_bytes",
      "2048"));
  events.push_back(RuntimeEvent(
      aptt::BackendApi::kDirectSound,
      "lock_duration_ms",
      "0.25"));
  aptt::DiagnosticEvent restore;
  restore.type = aptt::DiagnosticEventType::kError;
  restore.backend = aptt::BackendApi::kDirectSound;
  restore.backend_fields["api"] = "IDirectSoundBuffer::Restore";
  events.push_back(restore);

  const auto summary = aptt::BuildPcmRunSummary(
      aptt::BackendApi::kDirectSound,
      "directsound:{fixture}",
      events,
      stats);
  const auto json = aptt::SerializePcmRunSummaryJson(summary);

  Expect(summary.backend_fields.at("play_cursor_bytes") == "1024",
         "DirectSound play cursor is preserved");
  Expect(summary.backend_fields.at("write_cursor_bytes") == "2048",
         "DirectSound write cursor is preserved");
  Expect(summary.backend_fields.at("lock_duration_ms") == "0.25",
         "DirectSound lock timing is preserved");
  Expect(summary.backend_fields.at("lost_buffer_restore_event") == "true",
         "DirectSound restore event is preserved");
  Expect(json.find("\"auto_backend_switch_attempted\": false") !=
             std::string::npos,
         "JSON records no automatic backend switch");
}

void TestWasapiDopSummaryPreservesCarrierFields() {
  aptt::RealtimeStats stats;
  stats.frames_generated = 1764;
  stats.frames_submitted = 1764;
  stats.frames_accepted = 1764;
  stats.callback_count = 2;

  aptt::DiagnosticEvent init;
  init.type = aptt::DiagnosticEventType::kFormatProbe;
  init.backend = aptt::BackendApi::kWasapiExclusive;
  init.backend_fields["signal_mode"] = "DoP";
  init.backend_fields["keep_alive_format"] = "valid-dop-silence";
  init.backend_fields["dop_dsd_rate_multiplier"] = "64";
  init.backend_fields["dop_marker_first"] = "0x05";
  init.backend_fields["dop_dsd_byte_order"] = "dsd1-lsb-first";

  aptt::DiagnosticEvent runtime = RuntimeEvent(
      aptt::BackendApi::kWasapiExclusive,
      "dop_next_marker_frame",
      "128");

  const auto summary = aptt::BuildPcmRunSummary(
      aptt::BackendApi::kWasapiExclusive,
      "wasapi:{fixture}",
      {init, runtime},
      stats);
  const auto json = aptt::SerializePcmRunSummaryJson(summary);

  Expect(summary.backend_fields.at("signal_mode") == "DoP",
         "DoP signal mode is preserved");
  Expect(summary.backend_fields.at("keep_alive_format") == "valid-dop-silence",
         "DoP keep-alive format is preserved");
  Expect(summary.backend_fields.at("dop_dsd_rate_multiplier") == "64",
         "DoP DSD rate is preserved");
  Expect(summary.backend_fields.at("dop_next_marker_frame") == "128",
         "DoP marker continuity field is preserved");
  Expect(json.find("valid-dop-silence") != std::string::npos,
         "DoP keep-alive field is serialized");
}

void TestComparisonCsvMarksUnsupportedMetrics() {
  aptt::RealtimeStats stats;
  stats.frames_generated = 10;
  stats.frames_submitted = 10;
  stats.frames_accepted = 10;
  stats.callback_count = 1;

  auto wasapi = aptt::BuildPcmRunSummary(
      aptt::BackendApi::kWasapiShared,
      "wasapi:{fixture}",
      {RuntimeEvent(aptt::BackendApi::kWasapiShared, "padding_frames", "128")},
      stats);
  auto directsound = aptt::BuildPcmRunSummary(
      aptt::BackendApi::kDirectSound,
      "directsound:{fixture}",
      {RuntimeEvent(aptt::BackendApi::kDirectSound, "play_cursor_bytes", "64")},
      stats);

  const auto csv = aptt::SerializePcmComparisonCsv({wasapi, directsound});
  Expect(csv.find("WASAPI Shared") != std::string::npos,
         "CSV includes WASAPI row");
  Expect(csv.find("DirectSound") != std::string::npos,
         "CSV includes DirectSound row");
  Expect(csv.find("unsupported") != std::string::npos,
         "CSV marks unsupported backend metrics explicitly");
}

}  // namespace

int main() {
  TestMetricAvailabilityIsBackendSpecific();
  TestPcmSummaryPreservesCommonCountersAndUnsupportedMetrics();
  TestDirectSoundSummaryPreservesCursorAndRestoreFields();
  TestWasapiDopSummaryPreservesCarrierFields();
  TestComparisonCsvMarksUnsupportedMetrics();

  std::cout << "PCM diagnostics tests passed\n";
  return 0;
}
