package cli

import (
	"context"
	"embed"
	"fmt"
	"sort"
)

const (
	completionCommandName = "generate-completion"
)

var (
	//go:embed autocomplete
	autoCompleteFS embed.FS

	shellCompletions = map[string]renderCompletion{
		"bash": getCompletion("autocomplete/bash_autocomplete"),
		"ps":   getCompletion("autocomplete/powershell_autocomplete.ps1"),
		"zsh":  getCompletion("autocomplete/zsh_autocomplete"),
		"fish": func(c *Command) (string, error) {
			return c.ToFishCompletion()
		},
	}
)

type renderCompletion func(*Command) (string, error)

func getCompletion(s string) renderCompletion {
	return func(c *Command) (string, error) {
		b, err := autoCompleteFS.ReadFile(s)
		return string(b), err
	}
}

func buildCompletionCommand() *Command {
	return &Command{
		Name:   completionCommandName,
		Hidden: true,
		Action: completionCommandAction,
	}
}

func completionCommandAction(ctx context.Context, cmd *Command) error {
	var shells []string
	for k := range shellCompletions {
		shells = append(shells, k)
	}

	sort.Strings(shells)

	if cmd.Args().Len() == 0 {
		return Exit(fmt.Sprintf("no shell provided for completion command. available shells are %+v", shells), 1)
	}
	s := cmd.Args().First()

	if rc, ok := shellCompletions[s]; !ok {
		return Exit(fmt.Sprintf("unknown shell %s, available shells are %+v", s, shells), 1)
	} else if c, err := rc(cmd); err != nil {
		return Exit(err, 1)
	} else {
		if _, err = cmd.Writer.Write([]byte(c)); err != nil {
			return Exit(err, 1)
		}
	}
	return nil
}
