// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package command

import (
	"errors"
	"fmt"
	"io"
	"os"
	"strings"

	"github.com/opentofu/opentofu/internal/repl"

	"github.com/chzyer/readline"
	"github.com/mitchellh/cli"
)

func (c *ConsoleCommand) modeInteractive(session *repl.Session, ui cli.Ui) int {
	// Configure input
	l, err := readline.NewEx(&readline.Config{
		Prompt:            "> ",
		InterruptPrompt:   "^C",
		EOFPrompt:         "exit",
		HistorySearchFold: true,
		Stdin:             os.Stdin,
		Stdout:            os.Stdout,
		Stderr:            os.Stderr,
	})
	if err != nil {
		c.Ui.Error(fmt.Sprintf(
			"Error initializing console: %s",
			err))
		return 1
	}
	defer l.Close()

	var consoleState consoleBracketState

	for {
		// Read a line
		line, err := l.Readline()
		if errors.Is(err, readline.ErrInterrupt) {
			if len(line) == 0 {
				break
			} else {
				continue
			}
		} else if errors.Is(err, io.EOF) {
			break
		}
		line = strings.TrimSpace(line)

		// we update the state with the new line, so if we have open
		// brackets we know not to execute the command just yet
		fullCommand, openState := consoleState.UpdateState(line)

		if openState > 0 {
			// here there are open brackets somewhere, so we don't execute it
			// as we are in a bracket we update the prompt. we use one . per layer pf brackets
			l.SetPrompt(fmt.Sprintf("%s ", strings.Repeat(".", openState)))
		} else {
			out, exit, diags := session.Handle(fullCommand)
			if diags.HasErrors() {
				c.showDiagnostics(diags)
			}
			if exit {
				break
			}

			// clear the state and buffer as we have executed a command
			// we also reset the prompt
			l.SetPrompt("> ")

			ui.Output(out)
		}
	}

	return 0
}
