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

///|
fn read_u16_le(bytes : Bytes, offset : Int) -> Int {
  bytes[offset].to_int() | (bytes[offset + 1].to_int() << 8)
}

///|
fn read_u32_le(bytes : Bytes, offset : Int) -> Int {
  bytes[offset].to_int() |
  (bytes[offset + 1].to_int() << 8) |
  (bytes[offset + 2].to_int() << 16) |
  (bytes[offset + 3].to_int() << 24)
}

///|
fn read_i16_le(bytes : Bytes, offset : Int) -> Int {
  let u = read_u16_le(bytes, offset)
  if u >= 0x8000 {
    u - 0x10000
  } else {
    u
  }
}

///|
fn read_i24_le(bytes : Bytes, offset : Int) -> Int {
  let u = bytes[offset].to_int() |
    (bytes[offset + 1].to_int() << 8) |
    (bytes[offset + 2].to_int() << 16)
  if u >= 0x800000 {
    u - 0x1000000
  } else {
    u
  }
}

///|
fn read_i32_le(bytes : Bytes, offset : Int) -> Int {
  read_u32_le(bytes, offset)
}

///|
fn pow2(exp : Int) -> Double {
  if exp >= 0 {
    let mut v = 1.0
    for _ in 0.. Double {
  let sign = if bits < 0 { -1.0 } else { 1.0 }
  let exponent = (bits >> 23) & 0xff
  let fraction = bits & 0x7fffff
  if exponent == 255 {
    if fraction == 0 {
      if sign > 0.0 {
        1.0 / 0.0
      } else {
        -1.0 / 0.0
      }
    } else {
      0.0 / 0.0
    }
  } else if exponent == 0 {
    if fraction == 0 {
      if sign > 0.0 {
        0.0
      } else {
        -0.0
      }
    } else {
      sign * pow2(-126) * (Double::from_int(fraction) / 8_388_608.0)
    }
  } else {
    sign *
    pow2(exponent - 127) *
    (1.0 + Double::from_int(fraction) / 8_388_608.0)
  }
}

///|
fn bytes_eq4(
  bytes : Bytes,
  offset : Int,
  b0 : Int,
  b1 : Int,
  b2 : Int,
  b3 : Int,
) -> Bool {
  offset + 4 <= bytes.length() &&
  bytes[offset].to_int() == b0 &&
  bytes[offset + 1].to_int() == b1 &&
  bytes[offset + 2].to_int() == b2 &&
  bytes[offset + 3].to_int() == b3
}

///|
pub fn decode_wav_bytes(bytes : Bytes) -> DecodedSamples raise DecoderError {
  guard bytes.length() >= 12 else {
    raise InvalidFormat("wav header too short")
  }

  guard bytes_eq4(bytes, 0, 0x52, 0x49, 0x46, 0x46) else {
    raise InvalidFormat("missing RIFF")
  }
  guard bytes_eq4(bytes, 8, 0x57, 0x41, 0x56, 0x45) else {
    raise InvalidFormat("missing WAVE")
  }

  let mut audio_format = -1
  let mut channels = -1
  let mut sample_rate = -1
  let mut block_align = -1
  let mut bits_per_sample = -1
  let mut valid_bits_per_sample = -1
  let mut data_offset = -1
  let mut data_len = 0

  let mut offset = 12
  while offset + 8 <= bytes.length() {
    let chunk_len = read_u32_le(bytes, offset + 4)
    let chunk_data = offset + 8
    guard chunk_len >= 0 && chunk_data + chunk_len <= bytes.length() else {
      raise InvalidFormat("chunk length out of bounds")
    }

    if bytes_eq4(bytes, offset, 0x66, 0x6d, 0x74, 0x20) {
      guard chunk_len >= 16 else { raise InvalidFormat("fmt chunk too short") }
      audio_format = read_u16_le(bytes, chunk_data)
      channels = read_u16_le(bytes, chunk_data + 2)
      sample_rate = read_u32_le(bytes, chunk_data + 4)
      block_align = read_u16_le(bytes, chunk_data + 12)
      bits_per_sample = read_u16_le(bytes, chunk_data + 14)
      if chunk_len >= 18 {
        let cb_size = read_u16_le(bytes, chunk_data + 16)
        if audio_format == 0xfffe && cb_size >= 22 && chunk_len >= 40 {
          valid_bits_per_sample = read_u16_le(bytes, chunk_data + 18)
          audio_format = read_u16_le(bytes, chunk_data + 24)
        }
      }
    } else if bytes_eq4(bytes, offset, 0x64, 0x61, 0x74, 0x61) {
      data_offset = chunk_data
      data_len = chunk_len
    }

    offset = chunk_data + chunk_len
    if offset % 2 == 1 {
      offset += 1
    }
  }

  guard audio_format != -1 &&
    channels != -1 &&
    sample_rate != -1 &&
    data_offset != -1 else {
    raise InvalidFormat("missing fmt or data chunk")
  }

  guard channels > 0 && sample_rate > 0 else {
    raise InvalidFormat("invalid channel count or sample rate")
  }

  let effective_bits = if valid_bits_per_sample > 0 {
    valid_bits_per_sample
  } else {
    bits_per_sample
  }
  let bytes_per_sample = if effective_bits <= 8 {
    1
  } else if effective_bits <= 16 {
    2
  } else if effective_bits <= 24 {
    3
  } else if effective_bits <= 32 {
    4
  } else {
    raise Unsupported("unsupported bits per sample")
  }
  let expected_block_align = channels * bytes_per_sample
  guard block_align == expected_block_align else {
    raise InvalidFormat("invalid block align")
  }
  guard data_len % bytes_per_sample == 0 else {
    raise InvalidFormat("data chunk alignment is invalid")
  }

  let sample_count = data_len / bytes_per_sample
  let samples : Array[Double] = []
  if audio_format == 1 {
    match effective_bits {
      8 =>
        for i in 0..
        for i in 0..
        for i in 0..
        for i in 0.. raise Unsupported("unsupported PCM bit depth")
    }
  } else if audio_format == 3 {
    guard effective_bits == 32 else {
      raise Unsupported("only 32-bit IEEE float is supported")
    }
    for i in 0..