package main

import (
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/irccloud/go-ircevent"
	"github.com/spf13/viper"
)

func (i *IRCCat) handleCommand(event *irc.Event) {
	msg := event.Message()
	channel := ""
	respond_to := event.Arguments[0]

	if i.inChannel(respond_to) {
		channel = respond_to
	} else {
		respond_to = event.Nick
		if !i.authorisedUser(event.Nick) {
			log.Infof("Unauthorised command: %s (%s) %s", event.Nick, respond_to, msg)
			return
		}
	}

	log.Infof("Authorised command: %s (%s) %s", event.Nick, respond_to, msg)

	parts := strings.SplitN(msg, " ", 2)

	args := ""
	if len(parts) > 1 {
		args = parts[1]
	}

	handler := viper.GetString("commands.handler")
	if handler != "" {
		cmd := exec.Command(handler)
		cmd.Env = append(os.Environ(), fmt.Sprintf("IRCCAT_NICK=%s", event.Nick),
			fmt.Sprintf("IRCCAT_USER=%s", event.User),
			fmt.Sprintf("IRCCAT_HOST=%s", event.Host),
			fmt.Sprintf("IRCCAT_CHANNEL=%s", channel),
			fmt.Sprintf("IRCCAT_RESPOND_TO=%s", respond_to),
			fmt.Sprintf("IRCCAT_COMMAND=%s", parts[0][1:]),
			fmt.Sprintf("IRCCAT_ARGS=%s", args),
			fmt.Sprintf("IRCCAT_RAW=%s", event.Raw))

		i.runCommand(cmd, respond_to)
	}
}

// Run a command with the output going to the nick/channel identified by respond_to
func (i *IRCCat) runCommand(cmd *exec.Cmd, respond_to string) {
	var out bytes.Buffer
	cmd.Stdout = &out
	cmd.Stderr = &out
	err := cmd.Run()
	if err != nil {
		log.Errorf("Running command %s failed: %s", cmd.Args, err)
		i.irc.Privmsgf(respond_to, "Command failed: %s", err)
	}

	lines := strings.Split(out.String(), "\n")
	line_count := len(lines)
	if line_count > viper.GetInt("commands.max_response_lines") {
		line_count = viper.GetInt("commands.max_response_lines")
	}

	for _, line := range lines[0:line_count] {
		if line != "" {
			// 360 bytes is the worst-case maximum size for PRIVMSG lines. Truncate the lines at that length.
			if len(line) > 360 {
				line = line[:360]
			}
			i.irc.Privmsg(respond_to, line)
		}
		// Pause between lines to avoid being flooded out
		time.Sleep(250)
	}
}
