// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
/// Compatibility trait mirroring `rodio::fixed_source::FixedSource`.
///
/// Unlike `Source`, a `FixedSource` never changes channel count and sample rate.
pub(open) trait FixedSource {
  next(Self) -> Sample?
  channels(Self) -> ChannelCount
  sample_rate(Self) -> SampleRate
  total_duration(Self) -> @moon_cpal.Duration?
}

///|
pub struct FixedSourceAdapter {
  inner : DynSource
}

///|
pub fn[S : FixedSource] FixedSourceAdapter::new(
  source : S,
) -> FixedSourceAdapter {
  {
    inner: DynSource::new(
      fn() { source.next() },
      source.channels(),
      source.sample_rate(),
      current_span_len=source_default_current_span_len,
      total_duration=fn() { source.total_duration() },
      try_seek=fn(_pos : @moon_cpal.Duration) { Err(SeekError::NotSupported) },
    ),
  }
}

///|
pub fn FixedSourceAdapter::inner(self : FixedSourceAdapter) -> DynSource {
  self.inner
}

///|
pub fn FixedSourceAdapter::next(self : FixedSourceAdapter) -> Sample? {
  self.inner.next()
}

///|
pub fn FixedSourceAdapter::channels(self : FixedSourceAdapter) -> ChannelCount {
  self.inner.channels()
}

///|
pub fn FixedSourceAdapter::sample_rate(self : FixedSourceAdapter) -> SampleRate {
  self.inner.sample_rate()
}

///|
pub impl Source for FixedSourceAdapter with next(self : FixedSourceAdapter) {
  self.next()
}

///|
pub impl Source for FixedSourceAdapter with channels(self : FixedSourceAdapter) {
  self.channels()
}

///|
pub impl Source for FixedSourceAdapter with sample_rate(
  self : FixedSourceAdapter,
) {
  self.sample_rate()
}

///|
pub impl Source for FixedSourceAdapter with current_span_len(
  _self : FixedSourceAdapter,
) {
  None
}

///|
pub impl Source for FixedSourceAdapter with total_duration(
  _self : FixedSourceAdapter,
) {
  _self.inner.total_duration()
}

///|
pub impl Source for FixedSourceAdapter with try_seek(
  _self : FixedSourceAdapter,
  pos : @moon_cpal.Duration,
) -> Unit raise SeekError {
  _self.inner.try_seek(pos)
}

///|
pub struct FixedSamplesBuffer {
  channels : ChannelCount
  sample_rate : SampleRate
  samples : Array[Sample]
  cursor : Ref[Int]
  duration : @moon_cpal.Duration?
}

///|
pub fn FixedSamplesBuffer::new(
  channels : ChannelCount,
  sample_rate : SampleRate,
  samples : Array[Sample],
) -> FixedSamplesBuffer {
  guard channels > 0 else { panic() }
  guard sample_rate > 0 else { panic() }
  let duration = duration_from_sample_count(
    samples.length(),
    channels,
    sample_rate,
  )
  { channels, sample_rate, samples, cursor: @ref.new(0), duration }
}

///|
pub impl FixedSource for FixedSamplesBuffer with next(self : FixedSamplesBuffer) {
  if self.cursor.val >= self.samples.length() {
    None
  } else {
    let v = self.samples[self.cursor.val]
    self.cursor.val += 1
    Some(v)
  }
}

///|
pub impl FixedSource for FixedSamplesBuffer with channels(
  self : FixedSamplesBuffer,
) {
  self.channels
}

///|
pub impl FixedSource for FixedSamplesBuffer with sample_rate(
  self : FixedSamplesBuffer,
) {
  self.sample_rate
}

///|
pub impl FixedSource for FixedSamplesBuffer with total_duration(
  self : FixedSamplesBuffer,
) {
  self.duration
}