---library for `kpsewhich`
---@module kpathsea
---@copyright 2025
local kpse = require 'kpse'
local argparse = require 'argparse'
local semver = require 'semver'
local M = {}

---get parser
---@param progname string program name
---@return table parser
function M.get_parser(progname)
   local parser = argparse(progname):add_complete()
   parser:argument('file', 'file name'):args('*')
   parser:option('--progname', 'set program name', progname)
   parser:option('--help-formats -l', 'display information about all supported file formats by -l, -ll'):args(0):count(
       '*')
   parser:option('--expand-braces', 'output variable and brace expansion'):count('*')
   parser:option('--expand-path', 'output complete path expansion'):count('*')
   parser:option('--expand-var', 'output variable expansion'):count('*')
   parser:option('--var-value', 'output variable-expanded value of variable'):count('*')
   local names = {}
   for name, _ in pairs(M.formats) do
       table.insert(names, name)
   end
   for alias, _ in pairs(M.aliases) do
       table.insert(names, alias)
   end
   table.sort(names)
   parser:option('--show-path', 'output search path for file type'):count('*'):choices(names)
   parser:option('--version', 'display version information number and exit.'):args(0)
   parser:option('--debug -d', 'set debug flags'):args(0):count('*')
   return parser
end

---**entry for kpsewhich**
---@param args string[] command line arguments
function M.main(args)
   local parser = M.get_parser(args[0])
   args = parser:parse(args)
   if args.version then
       print(kpse.version())
       return
   elseif args.help_formats > 0 then
       if args.help_formats > 1 then
           kpse.set_program_name(args.progname)
       end
       local names = {}
       for name, _ in pairs(M.formats) do
           table.insert(names, name)
       end
       table.sort(names)
       for _, name in ipairs(names) do
           local format = M.formats[name]
           local aliases = { name }
           for k, v in pairs(M.aliases) do
               if v == name then
                   table.insert(aliases, k)
               end
           end
           print(table.concat(aliases, ', ') ..
               ': ' .. table.concat(format.vars, ', ') .. ': defined by ' .. (format.source or 'texmf.cnf'))
           if args.help_formats > 1 then
               if format.source then
                   print(kpse.default_texmfcnf())
               else
                   print(kpse.show_path(name))
               end
           end
       end
       return
   end
   kpse.set_program_name(args.progname)
   for _, v in ipairs(args.expand_braces or {}) do
       if args.debug == 0 then
           v = v .. ' -> ' .. kpse.expand_braces(v)
       end
       print(v)
   end
   for _, v in ipairs(args.expand_path or {}) do
       if args.debug == 0 then
           v = v .. ' -> ' .. kpse.expand_path(v)
       end
       print(v)
   end
   for _, v in ipairs(args.expand_var or {}) do
       if args.debug == 0 then
           v = v .. ' -> ' .. kpse.expand_var(v)
       end
       print(v)
   end
   for _, v in ipairs(args.var_value or {}) do
       if args.debug == 0 then
           v = v .. ' = ' .. kpse.var_value(v)
       end
       print(v)
   end
   for _, v in ipairs(args.show_path or {}) do
       v = M.aliases[v] or v
       if args.debug == 0 then
           v = v .. ': ' .. kpse.show_path(v)
       end
       print(v)
   end
   local err
   for k, v in ipairs(args.file) do
       if args.debug == 0 then
           v = kpse.lookup(v)
       end
       if v == nil then
           v = args.file[k] .. ' not found'
           err = true
       end
       print(v)
   end
   if err then
       os.exit(1)
   end
end

M.aliases = {
   bitmapfont = 'bitmap font',
   mpsupport = 'MetaPost support',
   source = 'TeX system sources',
   doc = 'TeX system documentation',
   trofffont = 'Troff fonts',
   dvipsconfig = 'dvips config',
   web2c = 'web2c files',
   othertext = 'other text files',
   otherbin = 'other binary files',
   miscfont = 'misc fonts',
   cmap = 'cmap files',
   pdftexconfig = 'pdftex config',
}

M.formats = {
   gf = {
       patterns = { '*.gf' },
       vars = { 'GFFONTS', 'GLYPHFONTS', 'TEXFONTS' }
   },
   pk = {
       patterns = { '*.pk' },
       vars = { 'PKFONTS', 'TEXPKS', 'GLYPHFONTS', 'TEXFONTS' }
   },
   ['bitmap font'] = {
       vars = { 'GLYPHFONTS', 'TEXFONTS' }
   },
   tfm = {
       patterns = { '*.tfm' },
       vars = { 'TFMFONTS', 'TEXFONTS' }
   },
   afm = {
       patterns = { '*.afm' },
       vars = { 'AFMFONTS', 'TEXFONTS' }
   },
   base = {
       patterns = { '*.base' },
       vars = { 'MFBASES', 'TEXMFINI' }
   },
   bib = {
       patterns = { '*.bib' },
       vars = { 'BIBINPUTS', 'TEXBIB' }
   },
   bst = {
       patterns = { '*.bst' },
       vars = { 'BSTINPUTS' }
   },
   cnf = {
       source = 'paths.h',
       patterns = { '*.cnf' },
       vars = { 'TEXMFCNF' }
   },
   ['ls-R'] = {
       patterns = { 'ls-R', 'ls-r' },
       vars = { 'TEXMFDBS' }
   },
   fmt = {
       patterns = { '*.fmt' },
       vars = { 'TEXFORMATS', 'TEXMFINI' }
   },
   map = {
       patterns = { '*.map' },
       vars = { 'TEXFONTMAPS', 'TEXFONTS' }
   },
   mem = {
       patterns = { '*.mem' },
       vars = { 'MPMEMS', 'TEXMFINI' }
   },
   mf = {
       patterns = { '*.mf' },
       vars = { 'MFINPUTS' }
   },
   mfpool = {
       patterns = { '*.pool' },
       vars = { 'MFPOOL', 'TEXMFINI' }
   },
   mft = {
       patterns = { '*.mft' },
       vars = { 'MFTINPUTS' }
   },
   mp = {
       patterns = { '*.mp' },
       vars = { 'MPINPUTS' }
   },
   mppool = {
       patterns = { '*.pool' },
       vars = { 'MPPOOL', 'TEXMFINI' }
   },
   ['MetaPost support'] = {
       vars = { 'MPSUPPORT' }
   },
   ocp = {
       patterns = { '*.ocp' },
       vars = { 'OCPINPUTS' }
   },
   ofm = {
       patterns = { '*.ofm' },
       vars = { 'OFMFONTS', 'TEXFONTS' }
   },
   opl = {
       patterns = { '*.opl', '*.pl' },
       vars = { 'OPLFONTS', 'TEXFONTS' }
   },
   otp = {
       patterns = { '*.otp' },
       vars = { 'OTPINPUTS' }
   },
   ovf = {
       patterns = { '*.ovf', '*.vf' },
       vars = { 'OVFFONTS', 'TEXFONTS' }
   },
   ovp = {
       patterns = { '*.ovp', '*.vpl' },
       vars = { 'OVPFONTS', 'TEXFONTS' }
   },
   ['graphic/figure'] = {
       patterns = { '*.eps', '*.epsi' },
       vars = { 'TEXPICTS', 'TEXINPUTS' }
   },
   tex = {
       patterns = { '*.tex', '*.sty', '*.cls', '*.fd', '*.aux', '.bbl', '.def', '.clo', '.ldf' },
       vars = { 'TEXINPUTS' }
   },
   ['TeX system documentation'] = {
       vars = { 'TEXDOCS' }
   },
   texpool = {
       patterns = { '*.pool' },
       vars = { 'TEXPOOL', 'TEXMFINI' }
   },
   ['TeX system sources'] = {
       patterns = { '*.dtx', '*.ins' },
       vars = { 'TEXSOURCES' }
   },
   ['PostScript header'] = {
       patterns = { '*.pro' },
       vars = { 'TEXPSHEADERS', 'PSHEADERS' }
   },
   ['Troff fonts'] = {
       vars = { 'TRFONTS' }
   },
   ['type1 fonts'] = {
       patterns = { '*.pfa', '*.pfb' },
       vars = { 'T1FONTS', 'T1INPUTS', 'TEXFONTS', 'TEXPSHEADERS', 'PSHEADERS' }
   },
   vf = {
       patterns = { '*.vf' },
       vars = { 'VFFONTS', 'TEXFONTS' }
   },
   ['dvips config'] = {
       vars = { 'TEXCONFIG' }
   },
   ist = {
       patterns = { '*.ist' },
       vars = { 'TEXINDEXSTYLE', 'INDEXSTYLE' }
   },
   ['truetype fonts'] = {
       patterns = { '*.ttf ', '*.ttc ', '*.TTF ', '*.TTC ', '*.dfont' },
       vars = { 'TTFONTS', 'TEXFONTS' }
   },
   ['type42 fonts'] = {
       patterns = { '*.t42 ', '*.T42 ' },
       vars = { 'T42FONTS', 'TEXFONTS' }
   },
   ['web2c files'] = {
       vars = { 'WEB2C' }
   },
   ['other text files'] = {
       vars = { '${PROGNAME}INPUTS' }
   },
   ['other binary files'] = {
       vars = { '${PROGNAME}INPUTS' }
   },
   ['misc fonts'] = {
       vars = { 'MISCFONTS', 'TEXFONTS' }
   },
   web = {
       patterns = { '*.web', '*.ch' },
       vars = { 'WEBINPUTS' }
   },
   cweb = {
       patterns = { '*.w', '*.web', '*.ch' },
       vars = { 'CWEBINPUTS' }
   },
   ['enc files'] = {
       patterns = { '*.enc' },
       vars = { 'ENCFONTS', 'TEXFONTS' }
   },
   ['cmap files'] = {
       vars = { 'CMAPFONTS', 'TEXFONTS' }
   },
   ['subfont definition files'] = {
       patterns = { '*.sfd' },
       vars = { 'SFDFONTS', 'TEXFONTS' }
   },
   ['opentype fonts'] = {
       patterns = { '*.otf', '*.OTF' },
       vars = { 'OPENTYPEFONTS', 'TEXFONTS' }
   },
   ['pdftex config'] = {
       vars = { 'PDFTEXCONFIG' }
   },
   ['lig files'] = {
       patterns = { '*.lig' },
       vars = { 'LIGFONTS', 'TEXFONTS' }
   },
   texmfscripts = {
       vars = { 'TEXMFSCRIPTS' }
   },
   lua = {
       patterns = { '*.lua', '*.luatex', '*.luc', '*.luctex', '*.texlua', '*.texluc', '*.tlu' },
       vars = { 'LUAINPUTS' }
   },
   ['font feature files'] = {
       patterns = { '*.fea' },
       vars = { 'FONTFEATURES' }
   },
   ['cid maps'] = {
       patterns = { '*.cid', '*.cidmap' },
       vars = { 'FONTCIDMAPS' }
   },
   mlbib = {
       patterns = { '*.mlbib', '*.bib' },
       vars = { 'MLBIBINPUTS', 'BIBINPUTS', 'TEXBIB' }
   },
   mlbst = {
       patterns = { '*.mlbst', '*.bst' },
       vars = { 'MLBSTINPUTS', 'BSTINPUTS' }
   },
   clua = {
       patterns = { '*.dll', '*.so' },
       vars = { 'CLUAINPUTS' }
   },
   ris = {
       patterns = { '*.ris' },
       vars = { 'RISINPUTS' }
   },
   bltxml = {
       patterns = { '*.bltxml' },
       vars = { 'BLTXMLINPUTS' }
   },
}
local v = semver(kpse.version():gsub(".* ", ''):gsub("/dev", ""))
if v < semver(6, 4, 0) then
   M.formats.ris = nil
   M.formats.bltxml = nil
end

return M