package main

import (
	"fmt"
	"os"
	"path/filepath"
	"regexp"
	"strings"

	"github.com/spf13/cobra/doc"

	"github.com/hetznercloud/cli/internal/cli"
	"github.com/hetznercloud/cli/internal/state"
	"github.com/hetznercloud/cli/internal/state/config"
)

//go:generate go run $GOFILE

func run() error {
	// Define the directory where the docs will be generated
	dir := "../../docs/reference/manual"

	// Clean the directory to make sure outdated files don't persist
	err := os.RemoveAll(dir)
	if err != nil {
		return fmt.Errorf("could not remove docs directory: %w", err)
	}

	// Create directory again
	if err := os.MkdirAll(dir, 0755); err != nil { //nolint:gosec
		return fmt.Errorf("error creating docs directory: %w", err)
	}

	cfg := config.New()
	s, err := state.New(cfg)
	if err != nil {
		return fmt.Errorf("could not create state: %w", err)
	}

	cmd := cli.NewRootCommand(s)

	// Generate the docs
	if err := doc.GenMarkdownTree(cmd, dir); err != nil {
		return fmt.Errorf("error generating docs: %w", err)
	}

	files, err := os.ReadDir(dir)
	if err != nil {
		return fmt.Errorf("error listing doc files: %w", err)
	}

	// Remove the 'Auto generated by...' lines at the bottom of files
	// This is done because this line contains the current date, which would create a diff when the file is re-generated
	generatedOnRegex := regexp.MustCompile(`\n###### Auto generated by spf13/cobra on .*\n`)
	for _, f := range files {
		if f.IsDir() {
			continue
		}
		path := filepath.Join(dir, f.Name())
		bytes, err := os.ReadFile(path)
		if err != nil {
			return fmt.Errorf("could not read file at %q: %w", path, err)
		}
		bytes = generatedOnRegex.ReplaceAll(bytes, nil)
		// We do this to wrap tables in a code block. Otherwise, they won't be displayed properly in markdown viewers.
		bytes = []byte(strings.ReplaceAll(string(bytes), "┌", "```\n┌"))
		bytes = []byte(strings.ReplaceAll(string(bytes), "┘", "┘\n```"))
		err = os.WriteFile(path, bytes, f.Type())
		if err != nil {
			return fmt.Errorf("could not write file at %q: %w", path, err)
		}
	}

	return nil
}

func main() {
	if err := run(); err != nil {
		fmt.Printf("Error: %v\n", err)
		os.Exit(1)
	}
}
