#!/usr/bin/env ruby
# frozen_string_literal: true

require 'mikunyan'
require 'fileutils'
begin
  require 'usamin'
  require 'usamin/overwrite'
rescue LoadError
  require 'json'
end

opts = { as_asset: false, outputdir: nil, sprite: false, pretty: false }
arg = nil
i = 0
while i < ARGV.count
  if ARGV[i].start_with?('-')
    case ARGV[i]
    when '--as-asset', '-a'
      opts[:as_asset] = true
    when '--outputdir', '-o'
      i += 1
      opts[:outputdir] = ARGV[i]
    when '--sprite', '-s'
      opts[:sprite] = true
    when '--pretty', '-p'
      opts[:pretty] = true
    else
      warn("Unknown option: #{ARGV[i]}")
    end
  else
    arg ||= ARGV[i]
  end
  i += 1
end

unless arg
  warn('Input file is not specified')
  exit(1)
end

unless File.file?(arg)
  warn("File not found: #{arg}")
  exit(1)
end

if opts[:as_asset]
  assets = [Mikunyan::Asset.file(arg)]
else
  bundle = Mikunyan::AssetBundle.file(arg)
  assets = bundle.assets
end

outdir = opts[:outputdir] || File.basename(arg, '.*')
FileUtils.mkpath(outdir)

if opts[:sprite]
  textures = {}
  textures_meta = {}
  assets.each do |asset|
    json = {}

    asset.each_object do |obj|
      next unless obj.type == 'Sprite'
      obj = obj.parse
      next unless obj&.m_RD&.texture
      file_id = obj.m_RD.texture.m_FileID.value
      texture_asset = file_id == 0 ? asset : bundle && bundle[asset.references[file_id - 1].file_path]
      texture_id = obj.m_RD.texture.m_PathID.value
      next unless texture_asset && texture_id

      unless textures.dig(texture_asset, texture_id)
        texture_obj = texture_asset.parse_object(texture_id)
        if texture_obj.is_a?(Mikunyan::CustomTypes::Texture2D)
          textures[texture_asset] ||= {}
          textures[texture_asset][texture_id] = texture_obj.generate_png
          textures_meta[texture_asset] ||= {}
          textures_meta[texture_asset][texture_id] = {
            name: texture_obj.m_Name&.value, width: texture_obj.m_Width&.value, height: texture_obj.m_Height&.value,
            format: texture_obj.m_TextureFormat&.value, asset: texture_asset.name, path_id: texture_id
          }
        end
      end

      next unless textures_meta[texture_asset][texture_id]

      unless json.key?([file_id, texture_id])
        json[[file_id, texture_id]] = textures_meta[texture_asset][texture_id].dup
        json[[file_id, texture_id]][:sprites] = []
      end

      x = obj.m_Rect&.x&.value
      y = obj.m_Rect&.y&.value
      width = obj.m_Rect&.width&.value
      height = obj.m_Rect&.height&.value

      json[[file_id, texture_id]][:sprites] << { name: obj.object_name, x: x, y: y, width: width, height: height, path_id: obj.path_id }

      texture = textures[texture_asset][texture_id]
      next unless texture && x && y && width && height
      texture.crop(x.round, (texture.height - height - y).round, width.round, height.round).save("#{outdir}/#{obj.object_name}.png")
    end
    puts opts[:pretty] ? JSON.pretty_generate(json.values) : JSON.generate(json.values)
  end
else
  assets.each do |asset|
    json = []
    asset.each_object do |obj|
      next unless obj.type == 'Texture2D'
      obj = obj.parse
      next unless obj.is_a?(Mikunyan::CustomTypes::Texture2D)
      json << {
        name: obj.object_name, width: obj.width, height: obj.height,
        format: obj.texture_format, path_id: obj.path_id
      }
      obj.generate_png&.save("#{outdir}/#{obj.object_name}.png")
    end
    puts opts[:pretty] ? JSON.pretty_generate(json) : JSON.generate(json)
  end
end
