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

#include "backends/kernel_streaming_discovery.h"

namespace {

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

void TestDefaultPcmCandidatesCoverWideScanRange() {
  const auto candidates = aptt::KernelStreamingDefaultPcmCandidates();

  Expect(candidates.size() == 65, "KS PCM scan has 13 rates x 5 formats");
  Expect(candidates.front().sample_rate_hz == 44100,
         "KS PCM scan begins at 44.1 kHz");
  Expect(candidates.front().sample_type == aptt::SampleType::kInt16,
         "KS PCM scan includes int16");
  Expect(candidates[1].sample_type == aptt::SampleType::kInt24Packed,
         "KS PCM scan distinguishes packed 24-bit");
  Expect(candidates[1].valid_bits_per_sample == 24 &&
             candidates[1].container_bits_per_sample == 24,
         "packed 24-bit is represented as 24/24");
  Expect(candidates[2].sample_type == aptt::SampleType::kInt24In32,
         "KS PCM scan distinguishes 24-in-32");
  Expect(candidates[2].valid_bits_per_sample == 24 &&
             candidates[2].container_bits_per_sample == 32,
         "24-in-32 is represented as 24/32");
  Expect(candidates.back().sample_rate_hz == 1536000,
         "KS PCM scan reaches 1536 kHz");
  Expect(candidates.back().sample_type == aptt::SampleType::kInt32,
         "KS PCM scan includes int32");
}

void TestStableIdRoundtripAllowsDevicePathSeparators() {
  const std::string filter = R"(\\?\SWD#MMDEVAPI#{fixture-filter})";
  const auto stable_id = aptt::KernelStreamingStableId(filter, 17);
  const auto parsed = aptt::ParseKernelStreamingStableId(stable_id);

  Expect(parsed.has_value(), "KS stable ID parses");
  Expect(parsed->filter_symbolic_link == filter,
         "KS stable ID preserves filter symbolic link");
  Expect(parsed->pin_id == 17, "KS stable ID preserves pin ID");
  Expect(!aptt::ParseKernelStreamingStableId("wasapi:{fixture}").has_value(),
         "non-KS stable ID is rejected");
  Expect(!aptt::ParseKernelStreamingStableId("ks:\\\\?\\fixture#pin:x").has_value(),
         "non-numeric KS pin ID is rejected");
}

void TestStatusClassificationSeparatesUnsupportedFromFailures() {
  Expect(aptt::KernelStreamingSupportFromNtStatus(0) ==
             aptt::CapabilitySupport::kSupported,
         "STATUS_SUCCESS is supported");
  Expect(aptt::KernelStreamingSupportFromNtStatus(
             static_cast<std::int32_t>(0xC00000BBu)) ==
             aptt::CapabilitySupport::kUnsupported,
         "STATUS_NOT_SUPPORTED is unsupported");
  Expect(aptt::KernelStreamingSupportFromNtStatus(
             static_cast<std::int32_t>(0xC0000184u)) ==
             aptt::CapabilitySupport::kFailed,
         "device state errors remain failures");
}

void TestPinSnapshotRecordsRequiredSafetyFields() {
  auto snapshot = aptt::MakeKernelStreamingPinSnapshot(
      R"(\\?\SWD#MMDEVAPI#{fixture-filter})",
      3,
      "render",
      "sink",
      2,
      aptt::DeviceAvailability::kActive);

  Expect(snapshot.device.backend == aptt::BackendApi::kKernelStreaming,
         "KS snapshot has backend identity");
  Expect(snapshot.backend_fields.at("ks_pin_id") == "3",
         "KS snapshot records pin ID");
  Expect(snapshot.backend_fields.at("ks_pin_dataflow") == "render",
         "KS snapshot records dataflow");
  Expect(snapshot.backend_fields.at("ks_pin_communication") == "sink",
         "KS snapshot records communication");
  Expect(snapshot.backend_fields.at("ks_data_range_count") == "2",
         "KS snapshot records data range count");
  Expect(snapshot.backend_fields.at("opens_filter") == "true",
         "KS snapshot records filter open");
  Expect(snapshot.backend_fields.at("creates_pin") == "false",
         "KS discovery snapshot does not create pins");
  Expect(snapshot.backend_fields.at("starts_stream") == "false",
         "KS discovery snapshot never starts streams");
}

void TestStreamingModelMetadataClassificationFixtures() {
  struct Case {
    const char* name;
    bool supports_standard_streaming;
    bool supports_looped_streaming;
    const char* supports_wavert_rtaudio_properties;
    const char* accepts_wavert_notification_buffer;
    const char* expected_model;
    const char* expected_implementation;
  };

  const Case cases[] = {
      {"standard only", true, false, "unknown", "unknown", "standard_packet",
       "implemented"},
      {"looped only", false, true, "unknown", "unknown", "standard_looped",
       "unimplemented"},
      {"standard and looped", true, true, "unknown", "unknown", "standard_packet",
       "implemented"},
      {"WaveRT property only", false, true, "true", "unknown", "standard_looped",
       "unimplemented"},
      {"WaveRT buffer rejected", false, true, "true", "false", "standard_looped",
       "unimplemented"},
      {"WaveRT notification accepted without looped interface", false, false,
       "true", "true", "unknown", "unimplemented"},
      {"WaveRT notification buffer accepted", false, true, "true", "true", "wavert_cyclic",
       "implemented"},
      {"unknown", false, false, "unknown", "unknown", "unknown", "unimplemented"},
  };

  for (const auto& test_case : cases) {
    const auto metadata = aptt::ClassifyKernelStreamingStreamingModel(
        test_case.supports_standard_streaming,
        test_case.supports_looped_streaming,
        test_case.supports_wavert_rtaudio_properties,
        "{fixture-interface-set}",
        "7",
        test_case.accepts_wavert_notification_buffer);

    Expect(metadata.supports_standard_streaming ==
               test_case.supports_standard_streaming,
           "KS streaming model preserves standard support");
    Expect(metadata.supports_looped_streaming ==
               test_case.supports_looped_streaming,
           "KS streaming model preserves looped support");
    Expect(metadata.supports_wavert_rtaudio_properties ==
               test_case.supports_wavert_rtaudio_properties,
           "KS streaming model preserves WaveRT support");
    Expect(metadata.accepts_wavert_notification_buffer ==
               test_case.accepts_wavert_notification_buffer,
           "KS streaming model preserves WaveRT notification-buffer support");
    Expect(metadata.streaming_model == test_case.expected_model,
           "KS streaming model classification matches fixture");
    Expect(metadata.playback_implementation ==
               test_case.expected_implementation,
           "KS streaming model implementation status matches fixture");
    Expect(metadata.pin_interface_set == "{fixture-interface-set}",
           "KS streaming model preserves interface set");
    Expect(metadata.pin_interface_id == "7",
           "KS streaming model preserves interface ID");
  }
}

void TestProbeRejectsMissingExplicitPinBeforeApiUse() {
  aptt::KernelStreamingFormatProbeRequest request;
  request.stable_id = R"(ks:\\?\SWD#MMDEVAPI#{fixture-filter})";
  request.candidate_formats.push_back(
      aptt::KernelStreamingPcmCandidate(48000, aptt::SampleType::kFloat32, 2));

  const auto snapshot = aptt::ProbeKernelStreamingPinFormats(request);

  Expect(snapshot.discovery_error.has_value(),
         "missing KS pin ID is rejected");
  Expect(snapshot.discovery_error->symbol == "E_INVALIDARG",
         "missing KS pin ID is rejected before API use");
  Expect(snapshot.backend_fields.at("opens_filter") == "false",
         "invalid KS stable ID does not open a filter");
  Expect(snapshot.probes.empty(),
         "invalid KS stable ID does not create probe rows");
}

}  // namespace

int main() {
  TestDefaultPcmCandidatesCoverWideScanRange();
  TestStableIdRoundtripAllowsDevicePathSeparators();
  TestStatusClassificationSeparatesUnsupportedFromFailures();
  TestPinSnapshotRecordsRequiredSafetyFields();
  TestStreamingModelMetadataClassificationFixtures();
  TestProbeRejectsMissingExplicitPinBeforeApiUse();

  std::cout << "Kernel Streaming discovery tests passed\n";
  return 0;
}
