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

///|
/// cvar support (CVT variations) for embedded hinting.
///
/// Ported from `read-fonts` cvar parsing + `skrifa` hint instance setup
/// (Apache-2.0 OR MIT).
const TAG_CVAR : UInt = 0x63766172 // "cvar"

///|
fn cvar_fixed16_16_to_f26_6(bits : Int) -> Int {
  // Matches `font_types::Fixed::to_f26dot6()` rounding.
  ((bits.to_int64() + (0x200).to_int64()) >> 10).to_int()
}

///|
fn cvar_read_u16_be(view : BytesView, offset : Int) -> Int? {
  gvar_read_u16_be(view, offset)
}

///|
fn cvar_read_i16_be(view : BytesView, offset : Int) -> Int? {
  gvar_read_i16_be(view, offset)
}

///|
/// Computes accumulated cvar deltas (in 16.16 fixed bits) for the current
/// normalized coordinates.
///
/// Returns None if cvar is missing, invalid, or if variation is inactive.
fn cvar_deltas_fixed16_16(
  font : @moon_skrifa.FontRef,
  axis_count : Int,
  coords : ArrayView[@moon_skrifa.NormalizedCoord],
  cvt_len : Int,
) -> Array[Int]? {
  if axis_count <= 0 || cvt_len <= 0 || coords.is_empty() {
    return None
  }
  let cvar = match font.table(TAG_CVAR) {
    None => return None
    Some(v) => v
  }
  if cvar.length() < 8 {
    return None
  }
  let major = cvar_read_u16_be(cvar, 0).unwrap_or(-1)
  let minor = cvar_read_u16_be(cvar, 2).unwrap_or(-1)
  if major != 1 || minor != 0 {
    return None
  }
  let tuple_count_flags = cvar_read_u16_be(cvar, 4).unwrap_or(0)
  let tuple_count = tuple_count_flags & 0x0FFF
  let shared_points = (tuple_count_flags & 0x8000) != 0
  let data_off = cvar_read_u16_be(cvar, 6).unwrap_or(-1)
  if tuple_count <= 0 || data_off < 8 || data_off > cvar.length() {
    return None
  }
  let sizes : Array[Int] = Array::new()
  let tuple_indexes : Array[Int] = Array::new()
  let scalars : Array[Double] = Array::new()
  let mut header_off = 8
  for _ in 0.. cvar.length() {
      return None
    }
    for ax in 0.. cvar.length() {
        return None
      }
      for ax in 0.. data_off {
    return None
  }
  let out : Array[Double] = Array::make(cvt_len, 0.0)
  let mut cursor = data_off
  let mut shared_points_list : Array[Int]? = None
  if shared_points {
    let (pts, off2) = match gvar_points(cvar, cursor, cvt_len) {
      None => return None
      Some(v) => v
    }
    shared_points_list = pts
    cursor = off2
  }
  for i in 0.. cvar.length() {
      return None
    }
    let scalar = scalars.at(i)
    if scalar == 0.0 {
      cursor = tuple_end
      continue
    }
    // PRIVATE_POINT_NUMBERS = 0x2000.
    let private_points = (ti & 0x2000) != 0
    let mut points_list : Array[Int]? = None
    let mut after_points = cursor
    if private_points || !shared_points {
      let (pts, off2) = match gvar_points(cvar, cursor, cvt_len) {
        None => return None
        Some(v) => v
      }
      points_list = pts
      after_points = off2
    } else {
      points_list = shared_points_list
      after_points = cursor
    }
    let count = match points_list {
      None => cvt_len
      Some(arr) => arr.length()
    }
    let (dxs, after_x) = match gvar_deltas(cvar, after_points, count) {
      None => return None
      Some(v) => v
    }
    if after_x > tuple_end {
      return None
    }
    match points_list {
      None =>
        for ix in 0..
        for j in 0..= 0 && ix < cvt_len {
            out.set(ix, out.at(ix) + dxs.at(j).to_double() * scalar)
          }
        }
    }
    cursor = tuple_end
  }
  let out_bits : Array[Int] = Array::make(cvt_len, 0)
  for i in 0.. String {
  "AAEAAAAMAIAAAwBAT1MvMm4kh4gAAAFIAAAAYGN2YXI8NRkyAAADEAAAARtjdnQgCgsBHwAAAawAAADw" +
  "ZnZhcnhQU38AAAQsAAABDGdseWYdRDvlAAACoAAAACpndmFyAAUAMAAABTgAAAAYaGVhZAyV7XwAAADM" +
  "AAAANmhoZWEGqQF/AAABBAAAACRobXR4AfQAMgAAAagAAAAEbG9jYQAAABUAAAKcAAAABG1heHACPA/Z" +
  "AAABKAAAACBwb3N03jWOyQAAAswAAABEAAEAAABb5ytjRkQ5Xw889QALA+gAAAAA1F3isQAAAADWQuC1" +
  "ABL/EAJpAvgAAAAGAAIAAAAAAAAAAQAABCz+3AAAAoUAEgAcAmkAAQAAAAAAAAAAAAAAAAAAAAEAAQAA" +
  "AAEAMwACAAAAAAACABAALwCaAAABjg91AAAAAAAEAgsBkAAFAAACigJYAAAASwKKAlgAAAFeADIBQgAA" +
  "AgIFAgYFBQICBOAAAv9AAAAfCAAAKQAQAABHT09HAUAAIABvBCz+3AAABCwBJAAAAAAAAAAAAhgCygAA" +
  "ACAAAAH0ADIC+AAKAsoAAALKAAoCGAAKAAAAAAAA//YAAP/2/wb/9gAAAAAAAAAAAAAAAAAAAAAAAAAA" +
  "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
  "AAAAAAAAAAAAAAAAAAAAAAAAAEAAXgBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1" +
  "AAAAQAAAAAAAAAAAAAAAKgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
  "AAAAAAAAAAAAAAAVAAIAM/8GAc0DtgADAAcAABcRIRElIREhMwGa/pkBNP7M+gSw+1AzBEoAAAAAAgAA" +
  "AAAAAP+cADIAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAHdW5pMDAyMAd1bmkwMDY4B3VuaTAwNkUHdW5p" +
  "MDA2RgABAAAACwB2AA+gAAAAwAAAAAAPoADAAMAAAAAAD6AAQADAAAAAAA+gAMAAAAAAAAAPoABAAAAA" +
  "AAAAD6AAAAAAAEAAAA+gAAAAwABAAAAPoABAAMAAQAAAD6AAwAAAAEAAAA+gAEAAAABAAAAPoADAAMAA" +
  "QAAGBUEBARICBgUI+Aj1AP8GBUEBARICBgX+CPkLAAEGBUEBARICBgU46CoG9vwGBUEBARICBgXUvtnk" +
  "2eoGBUEBARICBgUWZCQTJBMGBUEBARICBgUIAAjVz+AGBUEBARICBgX4APgLCQEGBUEBARICBgWwAKb6" +
  "0QQGBUEBARICBgXwAOscJxYGBUEBARICBgXSAOrtI+0GBUEBARICBgUCAAf19/8AAAEAAAAQAAIAAwAU" +
  "AAwAEHdnaHQAHAAAAF4AAADCAAAAAAEAd2R0aABGAAAAZAAAAGQAAAAAAQFvcHN6AAwAAAAMAAAASAAA" +
  "AAABAgEHAAAAXgAAAGQAAAAMAAABAwAAABwAAABGAAAADAAAAQQAAABeAAAARgAAAAwAAAEFAAAAwgAA" +
  "AEYAAAAMAAABBgAAABwAAABkAAAADAAAAQgAAADCAAAAZAAAAAwAAAEJAAAAHAAAAEYAAABIAAABCgAA" +
  "AF4AAABGAAAASAAAAQsAAADCAAAARgAAAEgAAAEMAAAAHAAAAGQAAABIAAABDQAAAF4AAABkAAAASAAA" +
  "AQ4AAADCAAAAZAAAAEgAAAABAAAAAwAAAAAAGAABAAAAAAAYAAAAAA=="
}

///|
fn cvar_test_b64_val(c : Int) -> Int? {
  if c >= 65 && c <= 90 {
    Some(c - 65)
  } else if c >= 97 && c <= 122 {
    Some(c - 97 + 26)
  } else if c >= 48 && c <= 57 {
    Some(c - 48 + 52)
  } else if c == 43 {
    Some(62)
  } else if c == 47 {
    Some(63)
  } else {
    None
  }
}

///|
fn cvar_test_b64_decode(s : String) -> Bytes {
  let out : Array[Byte] = Array::new()
  let vals : Array[Int] = Array::new()
  let n = s.length()
  for i in 0.. 0
    Some(fvar) => cvar_read_u16_be(fvar, 8).unwrap_or(0)
  }
  let cvt_len = match font.table(0x63767420) {
    None => 0
    Some(cvt) => cvt.length() / 2
  }
  let coords : Array[@moon_skrifa.NormalizedCoord] = Array::from_fixed_array([
    8192, -8192,
  ])
  let deltas = cvar_deltas_fixed16_16(
    font,
    axis_count,
    coords.op_as_view(),
    cvt_len,
  ).unwrap()
  inspect(deltas.at(65).to_string(), content="1900544")
  inspect(deltas.at(66).to_string(), content="2621440")
  inspect(deltas.at(67).to_string(), content="2129920")
  inspect(deltas.at(85).to_string(), content="360448")
  inspect(deltas.at(87).to_string(), content="1015808")
  inspect(deltas.at(93).to_string(), content="524288")
}