// 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 Done {
  input : DynSource
  signal : Ref[Int]
  signal_sent : Ref[Bool]
}

///|
pub fn[S : Source] Done::new(source : S, signal : Ref[Int]) -> Done {
  { input: to_dyn(source), signal, signal_sent: @ref.new(false) }
}

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

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

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

///|
pub fn Done::next(self : Done) -> Sample? {
  let next = self.input.next()
  if !self.signal_sent.val && next is None {
    self.signal.val -= 1
    self.signal_sent.val = true
  }
  next
}

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

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

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

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

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

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

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

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

///|
pub struct EmptyCallback {
  callback : () -> Unit
}

///|
pub fn EmptyCallback::new(callback : () -> Unit) -> EmptyCallback {
  { callback, }
}

///|
pub fn EmptyCallback::next(self : EmptyCallback) -> Sample? {
  (self.callback)()
  None
}

///|
pub fn EmptyCallback::channels(_self : EmptyCallback) -> ChannelCount {
  1
}

///|
pub fn EmptyCallback::sample_rate(_self : EmptyCallback) -> SampleRate {
  48_000
}

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

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

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

///|
pub impl Source for EmptyCallback with fn current_span_len(
  _self : EmptyCallback,
) {
  source_default_current_span_len()
}

///|
pub impl Source for EmptyCallback with fn total_duration(_self : EmptyCallback) {
  Some(@moon_cpal.Duration::from_secs((0 : UInt64)))
}

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

///|
pub struct UniformSourceIterator {
  input : DynSource
  target_channels : ChannelCount
  target_sample_rate : SampleRate
  total_duration : @moon_cpal.Duration?
}

///|
pub fn[S : Source] UniformSourceIterator::new(
  source : S,
  target_channels : ChannelCount,
  target_sample_rate : SampleRate,
) -> UniformSourceIterator {
  guard target_channels > 0 else { panic() }
  guard target_sample_rate > 0 else { panic() }
  let total_duration = source.total_duration()
  {
    input: uniform_source(to_dyn(source), target_channels, target_sample_rate),
    target_channels,
    target_sample_rate,
    total_duration,
  }
}

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

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

///|
pub fn UniformSourceIterator::channels(
  self : UniformSourceIterator,
) -> ChannelCount {
  self.target_channels
}

///|
pub fn UniformSourceIterator::sample_rate(
  self : UniformSourceIterator,
) -> SampleRate {
  self.target_sample_rate
}

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

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

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

///|
pub impl Source for UniformSourceIterator with fn current_span_len(
  _self : UniformSourceIterator,
) {
  source_default_current_span_len()
}

///|
pub impl Source for UniformSourceIterator with fn total_duration(
  self : UniformSourceIterator,
) {
  self.total_duration
}

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

///|
pub struct FromIter {
  sources : Ref[Array[DynSource]]
  current : Ref[DynSource]
  has_current : Ref[Bool]
}

///|
fn from_dyn_iter(sources : Array[DynSource]) -> FromIter {
  if sources.is_empty() {
    {
      sources: @ref.new([]),
      current: @ref.new(make_empty_dyn_source(1, hz_44100)),
      has_current: @ref.new(false),
    }
  } else {
    let xs = sources
    let first = xs.remove(0)
    {
      sources: @ref.new(xs),
      current: @ref.new(first),
      has_current: @ref.new(true),
    }
  }
}

///|
pub fn[S : Source] from_iter(sources : Array[S]) -> FromIter {
  let dyn_sources : Array[DynSource] = []
  for source in sources {
    dyn_sources.push(to_dyn(source))
  }
  from_dyn_iter(dyn_sources)
}

///|
fn FromIter::pull_next_source(self : FromIter) -> Bool {
  if self.sources.val.is_empty() {
    self.has_current.val = false
    false
  } else {
    self.current.val = self.sources.val.remove(0)
    self.has_current.val = true
    true
  }
}

///|
pub fn FromIter::next(self : FromIter) -> Sample? {
  while true {
    if !self.has_current.val && !self.pull_next_source() {
      return None
    }

    match self.current.val.next() {
      None => self.has_current.val = false
      Some(v) => return Some(v)
    }
  }

  None
}

///|
pub fn FromIter::channels(self : FromIter) -> ChannelCount {
  if self.has_current.val {
    self.current.val.channels()
  } else if self.sources.val.is_empty() {
    2
  } else {
    self.sources.val[0].channels()
  }
}

///|
pub fn FromIter::sample_rate(self : FromIter) -> SampleRate {
  if self.has_current.val {
    self.current.val.sample_rate()
  } else if self.sources.val.is_empty() {
    hz_44100
  } else {
    self.sources.val[0].sample_rate()
  }
}

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

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

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

///|
pub impl Source for FromIter with fn current_span_len(_self : FromIter) {
  if _self.has_current.val {
    match _self.current.val.current_span_len() {
      Some(v) => if v != 0 { return Some(v) }
      None => ()
    }
  }
  Some(10_240)
}

///|
pub impl Source for FromIter with fn total_duration(_self : FromIter) {
  source_default_total_duration()
}

///|
pub impl Source for FromIter with fn try_seek(
  self : FromIter,
  pos : @moon_cpal.Duration,
) -> Unit raise SeekError {
  if self.has_current.val {
    self.current.val.try_seek(pos)
  } else {
    ()
  }
}