///|
pub struct EngineProfile {
  name : String
  target : RuntimeTarget
  max_texture : Int
  max_frames : Int
  padding : Int
  scale : Int
  power_of_two : Bool
} derive(Debug, Eq, ToJson, FromJson)

///|
pub fn EngineProfile::options(self : EngineProfile) -> AtlasOptions {
  { max_width: self.max_texture, padding: self.padding }
}

///|
pub fn EngineProfile::adapter(self : EngineProfile) -> RuntimeAdapter {
  RuntimeAdapter::for_target(self.target)
}

///|
pub fn EngineProfile::usable_for(
  self : EngineProfile,
  sheet : SpriteSheet,
) -> Bool {
  sheet.frames.length() <= self.max_frames
}

///|
pub fn EngineProfile::to_json_string(
  self : EngineProfile,
  indent? : Int = 2,
) -> String {
  ToJson::to_json(self).stringify(indent~)
}

///|
pub fn engine_profiles() -> Array[EngineProfile] {
  [
    {
      name: "godot-2d",
      target: Godot,
      max_texture: 4096,
      max_frames: 512,
      padding: 2,
      scale: 1,
      power_of_two: false,
    },
    {
      name: "phaser-web",
      target: Phaser,
      max_texture: 2048,
      max_frames: 256,
      padding: 2,
      scale: 1,
      power_of_two: true,
    },
    {
      name: "moonbit-runtime",
      target: MoonBit,
      max_texture: 4096,
      max_frames: 1024,
      padding: 1,
      scale: 1,
      power_of_two: false,
    },
    {
      name: "generic-portable",
      target: Generic,
      max_texture: 2048,
      max_frames: 128,
      padding: 2,
      scale: 1,
      power_of_two: false,
    },
    {
      name: "mobile-godot",
      target: Godot,
      max_texture: 1024,
      max_frames: 128,
      padding: 2,
      scale: 1,
      power_of_two: true,
    },
    {
      name: "mobile-phaser",
      target: Phaser,
      max_texture: 1024,
      max_frames: 96,
      padding: 1,
      scale: 1,
      power_of_two: true,
    },
  ]
}

///|
pub fn engine_profile_named(name : String) -> EngineProfile? {
  match engine_profiles().search_by(fn(profile) { profile.name == name }) {
    Some(index) => Some(engine_profiles()[index])
    None => None
  }
}

///|
pub fn engine_profiles_for(target : RuntimeTarget) -> Array[EngineProfile] {
  engine_profiles().filter(fn(profile) { profile.target == target })
}

///|
pub fn engine_profiles_supporting(sheet : SpriteSheet) -> Array[EngineProfile] {
  engine_profiles().filter(fn(profile) { profile.usable_for(sheet) })
}

///|
pub fn best_engine_profile(
  sheet : SpriteSheet,
  target : RuntimeTarget,
) -> EngineProfile? {
  let profiles = engine_profiles_for(target).filter(fn(profile) {
    profile.usable_for(sheet)
  })
  match profiles.get(0) {
    None => None
    Some(first) => {
      let mut best = first
      for profile in profiles[1:] {
        if profile.max_texture < best.max_texture {
          best = profile
        }
      }
      Some(best)
    }
  }
}

///|
pub fn engine_profile_count() -> Int {
  engine_profiles().length()
}

///|
pub fn engine_profile_names() -> Array[String] {
  engine_profiles().map(fn(profile) { profile.name })
}

///|
pub fn engine_profile_json(indent? : Int = 2) -> String {
  ToJson::to_json(engine_profiles()).stringify(indent~)
}