local ansikit = require 'ansikit'
local commander = require 'commander'
local fs = require 'fs'
local lunacolors = require 'lunacolors'
local Greenhouse = require 'nature.greenhouse'
local Page = require 'nature.greenhouse.page'
local docfuncs = require 'nature.doc'

local function strip(text, ...)
	for _, pat in ipairs {...} do
		text = text:gsub(pat, '\n')
	end

	return text
end

local function transformHTMLandMD(text)
	return strip(text, '|||', '|%-%-%-%-|%-%-%-%-|')
	:gsub('|(.-)|(.-)|', function(entry1, entry2)
		return string.format('%s - %s', entry1, entry2)
	end)
	:gsub('<hr>', '{separator}')
	:gsub('<.->', '')
	--:gsub('^\n\n', '\n')
	:gsub('\n%s+\n', '\n\n')
	--:gsub('  \n', '\n\n')
	:gsub('{{< (%w+) `(.-)` >}}', function(shortcode, text)
		return docfuncs.renderInfoBlock(shortcode, text)
	end)
	:gsub('```(%w+)\n(.-)```', function(lang, text)
		return docfuncs.renderCodeBlock(text)
	end)
	:gsub('```\n(.-)\n```', function(text)
		return docfuncs.renderCodeBlock(text)
	end)
	:gsub('`[^\n].-`', lunacolors.cyan)
	:gsub('#+ (.-\n)', function(heading) return lunacolors.blue(lunacolors.bold('→ ' .. heading)) end)
	:gsub('%*%*(.-)%*%*', lunacolors.bold)
end

commander.register('doc', function(args, sinks)
	local moddocPath = hilbish.dataDir .. '/docs/'
	local stat = pcall(fs.stat, '.git/refs/heads/extended-job-api')
	if stat then
		-- hilbish git
		moddocPath = './docs/'
	end

	local modules = table.map(fs.readdir(moddocPath), function(f)
		return lunacolors.underline(lunacolors.blue(string.gsub(f, '.md', '')))
	end)
	local doc = [[
Welcome to Hilbish's documentation viewer! Here you can find
documentation for builtin functions and other things related
to Hilbish.

Usage: doc <section> [subdoc]
Available sections: ]] .. table.concat(modules, ', ')
	local f
	local function handleYamlInfo(d)
		local vals = {}
		local docs = d

		local valsStr = docs:match '^%-%-%-\n.-\n%-%-%-'
		if valsStr then
			docs = docs:sub(valsStr:len() + 2, #docs)
			local pre = docs:sub(1, 1)
			if pre == '\n' then
				docs = docs:sub(2)
			end

			-- parse vals
			local lines = string.split(valsStr, '\n')
			for _, line in ipairs(lines) do
				local key = line:match '(%w+): '
				local val = line:match '^%w+: (.-)$'

				if key then
					vals[key] = val
				end
			end
		end

		--docs = docs:sub(1, #docs - 1)
		return docs, vals
	end

	if #args > 0 then
		local mod = args[1]

		f = io.open(moddocPath .. mod .. '.md', 'rb')
		local funcdocs = nil
		local subdocName = args[2]
		if not f then
			moddocPath = moddocPath .. mod .. '/'
			if not subdocName then
				subdocName = '_index'
			end
			f = io.open(moddocPath .. subdocName .. '.md', 'rb')
			local oldmoddocPath = moddocPath
			if not f then
				moddocPath = moddocPath .. subdocName:match '%w+' .. '/'
				f = io.open(moddocPath .. subdocName .. '.md', 'rb')
			end
			if not f then
				moddocPath = oldmoddocPath .. subdocName .. '/'
				subdocName = args[3] or '_index'
				f = io.open(moddocPath .. subdocName .. '.md', 'rb')
			end
			if not f then
				sinks.out:writeln('No documentation found for ' .. mod .. '.')
				return 1
			end
		end

	end

	local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= '_index.md' and f ~= 'index.md' end)
	local subdocs = table.map(moddocs, function(fname)
		return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.md', '')))
	end)

	local gh = Greenhouse(sinks.out)
	function gh:resize()
		local size = terminal.size()
		self.region = {
			width = size.width,
			height = size.height - 1
		}
	end
	gh:resize()

	function gh:render()
		local workingPage = self.pages[self.curPage]
		local offset = self.offset
		if self.isSpecial then
			offset = self.specialOffset
			workingPage = self.specialPage
		end
		local size = terminal.size()

		self.sink:write(ansikit.getCSI(size.height - 1 .. ';1', 'H'))
		self.sink:write(ansikit.getCSI(0, 'J'))
		if not self.isSpecial then
			if args[1] == 'api' then
				self.sink:writeln(workingPage.title)
				self.sink:write(lunacolors.format(string.format('{grayBg} ↳ {white}{italic}%s {reset}', workingPage.description or 'No description.')))
			else
				self.sink:write(lunacolors.reset(string.format('Viewing doc page %s', moddocPath)))
			end
		end
	end
	local backtickOccurence = 0
	local function formatDocText(d)
		return transformHTMLandMD(d)
		--[[
		return lunacolors.format(d:gsub('`(.-)`', function(t)
			return docfuncs.renderCodeBlock(t)
		end):gsub('\n#+.-\n', function(t)
			local signature = t:gsub('<.->(.-)</.->', '{underline}%1'):gsub('\\', '<')
			return '{bold}{yellow}' .. signature .. '{reset}'
		end))
		]]--
	end


	local doc, vals = handleYamlInfo(#args == 0 and doc or formatDocText(f:read '*a'))
	if #moddocs ~= 0 and f then
		doc = doc .. '\nSubdocs: ' .. table.concat(subdocs, ', ') .. '\n\n'
	end
	if f then f:close() end

	local page = Page(vals.title, doc)
	page.description = vals.description
	gh:addPage(page)

	-- add subdoc pages
	for _, sdName in ipairs(moddocs) do
		local sdFile = fs.join(sdName, '_index.md')
		if sdName:match '.md$' then
			sdFile = sdName
		end

		local f = io.open(moddocPath .. sdFile, 'rb')
		local doc, vals = handleYamlInfo(formatDocText(f:read '*a'))
		local page = Page(vals.title or sdName, doc)
		page.description = vals.description
		gh:addPage(page)
	end
	ansikit.hideCursor()
	gh:initUi()
end)