package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"strings"
)

const (
	docFile = "doc/documentation.md"
)

// GenerateDocumentation generates grv markdown documentation
func GenerateDocumentation() (err error) {
	helpSections, _, err := GenerateHelpView(NewConfiguration(NewKeyBindingManager(), nil, nil, nil))
	if err != nil {
		return
	}

	file, err := os.Create(docFile)
	if err != nil {
		return
	}
	defer file.Close()

	writer := bufio.NewWriter(file)
	writeHelpDocumentHeader(writer)

	for _, helpSection := range helpSections {
		writeHelpSection(writer, helpSection)
	}

	writer.Flush()

	return
}

func writeHelpDocumentHeader(writer io.Writer) {
	fmt.Fprintln(writer, "<!-- DO NOT EDIT -->")
	fmt.Fprintln(writer, "<!-- This file is auto-generated by grv -->")
	fmt.Fprintln(writer, "")
	fmt.Fprintln(writer, "# GRV Documentation")
	fmt.Fprintln(writer, "")
}

func writeHelpSection(writer io.Writer, helpSection *HelpSection) {
	writeHelpSectionTitle(writer, helpSection.title.text)
	writeHelpSectionDescription(writer, helpSection.description)
	writeHelpSectionTable(writer, helpSection.tableFormatter)
}

func writeHelpSectionTitle(writer io.Writer, title string) {
	if title != "" {
		fmt.Fprintln(writer, "")
		fmt.Fprintln(writer, "##", title)
		fmt.Fprintln(writer, "")
	}
}

func writeHelpSectionDescription(writer io.Writer, description []HelpSectionText) {
	lineCount := len(description)
	if lineCount == 0 {
		return
	}

	for lineIndex := 0; lineIndex < lineCount; lineIndex++ {
		line := description[lineIndex]

		switch line.themeComponentID {
		case CmpHelpViewIndexTitle:
			lineIndex = writeHelpSectionTitleLink(writer, line.text, false, lineIndex, description)
		case CmpHelpViewIndexSubTitle:
			lineIndex = writeHelpSectionTitleLink(writer, line.text, true, lineIndex, description)
		case CmpHelpViewSectionSubTitle:
			fmt.Fprintln(writer, "###", line.text)
		case CmpHelpViewSectionCodeBlock:
			codeLineIndex := lineIndex + 1
			for ; codeLineIndex < lineCount; codeLineIndex++ {
				if description[codeLineIndex].themeComponentID != CmpHelpViewSectionCodeBlock {
					break
				}
			}

			writeHelpSectionCodeBlock(writer, description[lineIndex:codeLineIndex])
			lineIndex = codeLineIndex - 1
		default:
			fmt.Fprintln(writer, line.text)
		}
	}

	fmt.Fprintln(writer, "")
}

func writeHelpSectionTitleLink(writer io.Writer, title string, subTitle bool, lineIndex int, description []HelpSectionText) int {
	title = strings.TrimLeft(title, " -")
	link := strings.ToLower(strings.Replace(title, " ", "-", -1))
	markDownTitle := fmt.Sprintf("[%v](#%v)", title, link)

	if subTitle {
		markDownTitle = "     * " + markDownTitle
	} else {
		markDownTitle = " - " + markDownTitle
	}

	fmt.Fprintln(writer, markDownTitle)

	if nextLineIndex := lineIndex + 1; nextLineIndex < len(description) {
		if description[nextLineIndex].text == "" {
			return nextLineIndex
		}
	}

	return lineIndex
}

func writeHelpSectionCodeBlock(writer io.Writer, codeBlock []HelpSectionText) {
	fmt.Fprintln(writer, "```")

	for _, line := range codeBlock {
		fmt.Fprintln(writer, line.text)
	}

	fmt.Fprintln(writer, "```")
}

func writeHelpSectionTable(writer io.Writer, tableFormatter *TableFormatter) {
	if tableFormatter == nil {
		return
	}

	fmt.Fprintln(writer, "```")

	for renderedRowIndex := uint(0); renderedRowIndex < tableFormatter.RenderedRows(); renderedRowIndex++ {
		fmt.Fprintln(writer, "", tableFormatter.RenderRowText(renderedRowIndex))
	}

	fmt.Fprintln(writer, "```")
	fmt.Fprintln(writer, "")
}
