#include <cstdlib>
#include <iostream>
#include <string_view>

#include "backends/mme_device_discovery.h"

namespace {

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

void TestMmeStableIds() {
  Expect(aptt::MmeDeviceStableId(aptt::kMmeWaveMapperId) == "mme:wave-mapper",
         "WAVE_MAPPER stable ID is explicit");
  Expect(aptt::MmeDeviceStableId(3) == "mme:waveout:3",
         "waveOut device ID is preserved");
  Expect(aptt::MmeDeviceIdFromStableId("mme:wave-mapper") ==
             aptt::kMmeWaveMapperId,
         "WAVE_MAPPER stable ID parses");
  Expect(aptt::MmeDeviceIdFromStableId("mme:waveout:3") == 3,
         "waveOut stable ID parses");
  Expect(!aptt::MmeDeviceIdFromStableId("wasapi:{endpoint}").has_value(),
         "foreign stable ID is rejected");
}

void TestMmeCandidateDefaultsAreConservativePcm() {
  const auto candidates = aptt::MmeDefaultPcmCandidates();
  Expect(candidates.size() == 65, "wide default MME PCM candidates");
  Expect(candidates.front().signal_mode == aptt::SignalMode::kPcm,
         "default MME candidate is PCM");
  Expect(candidates.front().sample_type == aptt::SampleType::kInt16,
         "default MME candidate is int16");
  Expect(candidates[1].sample_type == aptt::SampleType::kInt24Packed,
         "default MME candidates distinguish packed 24-bit");
  Expect(candidates[1].valid_bits_per_sample == 24 &&
             candidates[1].container_bits_per_sample == 24,
         "packed 24-bit MME candidate is 24/24");
  Expect(candidates[2].sample_type == aptt::SampleType::kInt24In32,
         "default MME candidates distinguish 24-in-32");
  Expect(candidates[2].valid_bits_per_sample == 24 &&
             candidates[2].container_bits_per_sample == 32,
         "24-in-32 MME candidate is 24/32");
  Expect(candidates.front().channels.channel_count == 2,
         "default MME candidate is stereo");
  Expect(candidates.back().sample_rate_hz == 1536000,
         "default MME candidates include 1536 kHz");
  Expect(candidates.back().sample_type == aptt::SampleType::kInt32,
         "default MME candidates include 32-bit integer");
}

void TestMmeSnapshotRepresentsMapperAndDevice() {
  const auto mapper = aptt::MakeMmeWaveOutDeviceSnapshot(
      aptt::kMmeWaveMapperId,
      "MME WAVE_MAPPER",
      0,
      0,
      true);
  Expect(mapper.device.backend == aptt::BackendApi::kMme,
         "mapper snapshot uses MME backend");
  Expect(mapper.device.is_default, "mapper is marked default");
  Expect(mapper.backend_fields.at("id_kind") == "mme-wave-mapper",
         "mapper ID kind is logged");
  Expect(mapper.probes.front().backend_fields.at("starts_stream") == "false",
         "mapper discovery does not start streams");

  const auto device = aptt::MakeMmeWaveOutDeviceSnapshot(
      2,
      "Fixture waveOut",
      0x0000000Fu,
      2,
      false);
  Expect(device.device.stable_id == "mme:waveout:2",
         "device stable ID is preserved");
  Expect(device.backend_fields.at("reported_channels") == "2",
         "reported channel count is logged");
  Expect(device.backend_fields.at("formats_mask") == "0x0000000F",
         "formats mask is logged");
}

void TestMmeFormatProbeRecordIsQueryOnly() {
  const auto candidate =
      aptt::MmePcmCandidate(44100, aptt::SampleType::kInt16, 2);
  const auto supported = aptt::MakeMmeFormatProbeRecord(candidate, 0);

  Expect(supported.kind == aptt::CapabilityProbeKind::kFormatSupport,
         "format probe record kind");
  Expect(supported.support == aptt::CapabilitySupport::kSupported,
         "zero MMRESULT is supported");
  Expect(supported.accepted_format.has_value(), "supported format is accepted");
  Expect(supported.backend_fields.at("flags") == "WAVE_FORMAT_QUERY",
         "query-only flag is logged");
  Expect(supported.backend_fields.at("callback") == "none",
         "no callback is registered");
  Expect(supported.backend_fields.at("starts_stream") == "false",
         "format query does not start stream");

  const auto failed = aptt::MakeMmeFormatProbeRecord(candidate, 999);
  Expect(failed.support == aptt::CapabilitySupport::kFailed,
         "unknown MMRESULT is failed");
  Expect(failed.error.has_value(), "failed MMRESULT is logged");
}

void TestMmeSnapshotRoundtripsThroughCommonModel() {
  aptt::DiscoverySnapshot discovery;
  discovery.backend = aptt::BackendApi::kMme;
  discovery.devices.push_back(aptt::MakeMmeWaveOutDeviceSnapshot(
      1,
      "Fixture waveOut",
      0x0000000Fu,
      2,
      false));
  discovery.devices.front().probes.push_back(aptt::MakeMmeFormatProbeRecord(
      aptt::MmePcmCandidate(48000, aptt::SampleType::kInt16, 2),
      0));

  const auto parsed = aptt::ParseDiscoverySnapshotJson(
      aptt::SerializeDiscoverySnapshotJson(discovery));

  Expect(parsed.has_value(), "MME discovery snapshot parses");
  Expect(aptt::DiscoverySnapshotIsSafeDryRun(*parsed),
         "MME snapshot remains dry-run safe");
  const auto device = aptt::FindDeviceByStableId(*parsed, "mme:waveout:1");
  Expect(device.has_value(), "MME device ID roundtrips");
  Expect(device->probes.size() == 2, "MME probes roundtrip");
}

}  // namespace

int main() {
  TestMmeStableIds();
  TestMmeCandidateDefaultsAreConservativePcm();
  TestMmeSnapshotRepresentsMapperAndDevice();
  TestMmeFormatProbeRecordIsQueryOnly();
  TestMmeSnapshotRoundtripsThroughCommonModel();

  std::cout << "MME device discovery tests passed\n";
  return 0;
}
