// 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.

///|
pub struct Pausable {
  input : DynSource
  paused_channels : Ref[ChannelCount?]
  remaining_paused_samples : Ref[Int]
}

///|
pub fn[S : Source] pausable(source : S, paused : Bool) -> Pausable {
  let input = to_dyn(source)
  {
    input,
    paused_channels: @ref.new(
      if paused {
        Some(input.channels())
      } else {
        None
      },
    ),
    remaining_paused_samples: @ref.new(0),
  }
}

///|
pub fn Pausable::set_paused(self : Pausable, paused : Bool) -> Unit {
  match (self.paused_channels.val, paused) {
    (None, true) => self.paused_channels.val = Some(self.input.channels())
    (Some(_), false) => self.paused_channels.val = None
    _ => ()
  }
}

///|
pub fn Pausable::is_paused(self : Pausable) -> Bool {
  self.paused_channels.val is Some(_)
}

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

///|
pub fn Pausable::inner_mut(self : Pausable) -> DynSource {
  self.input
}

///|
pub fn Pausable::into_inner(self : Pausable) -> DynSource {
  self.input
}

///|
pub fn Pausable::next(self : Pausable) -> Sample? {
  if self.remaining_paused_samples.val > 0 {
    self.remaining_paused_samples.val -= 1
    return Some(0.0)
  }

  match self.paused_channels.val {
    Some(paused_channels) => {
      self.remaining_paused_samples.val = paused_channels - 1
      Some(0.0)
    }
    None => self.input.next()
  }
}

///|
pub fn Pausable::channels(self : Pausable) -> ChannelCount {
  self.input.channels()
}

///|
pub fn Pausable::sample_rate(self : Pausable) -> SampleRate {
  self.input.sample_rate()
}

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

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

///|
pub impl Source for Pausable with fn sample_rate(self : Pausable) {
  self.sample_rate()
}

///|
pub impl Source for Pausable with fn current_span_len(_self : Pausable) {
  _self.input.current_span_len()
}

///|
pub impl Source for Pausable with fn total_duration(_self : Pausable) {
  _self.input.total_duration()
}

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

///|
pub struct Stoppable {
  input : DynSource
  stopped : Ref[Bool]
}

///|
pub fn[S : Source] stoppable(source : S) -> Stoppable {
  { input: to_dyn(source), stopped: @ref.new(false) }
}

///|
pub fn Stoppable::stop(self : Stoppable) -> Unit {
  self.stopped.val = true
}

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

///|
pub fn Stoppable::inner_mut(self : Stoppable) -> DynSource {
  self.input
}

///|
pub fn Stoppable::into_inner(self : Stoppable) -> DynSource {
  self.input
}

///|
pub fn Stoppable::next(self : Stoppable) -> Sample? {
  if self.stopped.val {
    None
  } else {
    self.input.next()
  }
}

///|
pub fn Stoppable::channels(self : Stoppable) -> ChannelCount {
  self.input.channels()
}

///|
pub fn Stoppable::sample_rate(self : Stoppable) -> SampleRate {
  self.input.sample_rate()
}

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

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

///|
pub impl Source for Stoppable with fn sample_rate(self : Stoppable) {
  self.sample_rate()
}

///|
pub impl Source for Stoppable with fn current_span_len(_self : Stoppable) {
  _self.input.current_span_len()
}

///|
pub impl Source for Stoppable with fn total_duration(_self : Stoppable) {
  _self.input.total_duration()
}

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

///|
pub struct Skippable {
  input : DynSource
  do_skip : Ref[Bool]
}

///|
pub fn[S : Source] skippable(source : S) -> Skippable {
  { input: to_dyn(source), do_skip: @ref.new(false) }
}

///|
pub fn Skippable::skip(self : Skippable) -> Unit {
  self.do_skip.val = true
}

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

///|
pub fn Skippable::inner_mut(self : Skippable) -> DynSource {
  self.input
}

///|
pub fn Skippable::into_inner(self : Skippable) -> DynSource {
  self.input
}

///|
pub fn Skippable::next(self : Skippable) -> Sample? {
  if self.do_skip.val {
    None
  } else {
    self.input.next()
  }
}

///|
pub fn Skippable::channels(self : Skippable) -> ChannelCount {
  self.input.channels()
}

///|
pub fn Skippable::sample_rate(self : Skippable) -> SampleRate {
  self.input.sample_rate()
}

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

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

///|
pub impl Source for Skippable with fn sample_rate(self : Skippable) {
  self.sample_rate()
}

///|
pub impl Source for Skippable with fn current_span_len(_self : Skippable) {
  _self.input.current_span_len()
}

///|
pub impl Source for Skippable with fn total_duration(_self : Skippable) {
  _self.input.total_duration()
}

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