var io = use('cellfs')

function hashify(fn) {
  var hash = {}
  return function(arg) {
    var key = arg
    if (hash[key] == null) hash[key] = fn(arg)
    return hash[key]
  }
}

// Merge of the old resources.js and packer.js functionalities
var Resources = {}

// Recognized resource extensions
Resources.scripts = ["js"]
Resources.images = ["qoi", "png", "gif", "jpg", "jpeg", "ase", "aseprite"]
Resources.sounds = ["wav", "flac", "mp3", "qoa"]
Resources.fonts = ["ttf"]
Resources.lib = [".so", ".dll", ".dylib"]

// Helper function: get extension from path in lowercase (e.g., "image.png" -> "png")
function getExtension(path) {
  var last = null
  replace(path, ".", function(m,pos) {
    last = pos
    return m
  })
  if (last == null) return null
  return lower(text(path, last + 1))
}

// Return true if ext is in at least one of the recognized lists
function isRecognizedExtension(ext) {
  if (!ext) return false
  if (search(Resources.scripts, ext) != null) return true
  if (search(Resources.images, ext) != null) return true
  if (search(Resources.sounds, ext) != null) return true
  if (search(Resources.fonts, ext) != null) return true
  if (search(Resources.lib, '.' + ext) != null) return true // for .so or .dll
  return false
}

function find_in_path(filename, exts = []) {
  if (!is_text(filename)) return null

  if (search(filename, '.') != null) {
    var candidate = filename // possibly need "/" ?
    if (io.exists(candidate) && !io.is_directory(candidate)) return candidate
    return null
  }

  // Only check extensions if exts is provided and not empty
  if (length(exts) > 0) {
    var cand = null
    arrfor(exts, function(ext) {
      var candidate = filename + '.' + ext
      if (io.exists(candidate) && !io.is_directory(candidate)){
        cand = candidate
        return true
      }
    }, null, true)
    if (cand != null) return cand
  } else {
    // Fallback to extensionless file only if no extensions are specified
    var candidate = filename
    if (io.exists(candidate) && !io.is_directory(candidate)) return candidate
  }
  return null
}

// Return a canonical path (the real directory plus the path)
Resources.canonical = function(file) {
  return io.realdir(file) + file
}

// The resource finders
Resources.find_image = hashify(function(file) {
  return find_in_path(file, Resources.images)
})

Resources.find_sound = hashify(function(file) {
  return find_in_path(file, Resources.sounds)
})

Resources.find_script = hashify(function(file) {
  return find_in_path(file, Resources.scripts)
})

Resources.find_font = hashify(function(file) {
  return find_in_path(file, Resources.fonts)
})

// .prosperonignore reading helper
function read_ignore(dir) {
  var path = dir + '/.prosperonignore'
  var patterns = []
  if (io.exists(path)) {
    var lines = array(io.slurp(path), '\n')
    arrfor(lines, function(line) {
      line = trim(line)
      if (!line || starts_with(line, '#')) return
      push(patterns, line)
    })
  }
  return patterns
}

// Return a list of recognized files in the directory (and subdirectories),
// skipping those matched by .prosperonignore. Directory paths are skipped.
Resources.getAllFiles = function(dir = "") {
  var patterns = read_ignore(dir)
  var all = io.globfs(patterns, dir)
  var results = []
  arrfor(all, function(f) {
    var fullPath = dir + '/' + f
    try {
      var st = io.stat(fullPath)
      // skip directories (filesize=0) or unrecognized extension
      if (!st.filesize) return
      var ext = getExtension(f)
      if (!isRecognizedExtension(ext)) return
      push(results, fullPath)
    } catch(e) {}
  })
  return results
}

// Categorize files by resource type
Resources.gatherStats = function(filePaths) {
  var stats = {
    scripts:0, images:0, sounds:0, fonts:0, lib:0, other:0, total:length(filePaths)
  }
  arrfor(filePaths, function(path) {
    var ext = getExtension(path)
    if (find(Resources.scripts, ext) != null) {
      stats.scripts++
      return
    }
    if (find(Resources.images, ext) != null) {
      stats.images++
      return
    }
    if (find(Resources.sounds, ext) != null) {
      stats.sounds++
      return
    }
    if (find(Resources.fonts, ext) != null) {
      stats.fonts++
      return
    }
    stats.other++
  })
  return stats
}

return Resources
