package main

import (
	"fmt"
	"math/rand"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

func setupCommands() {
	reboot := Command{
		Name:          "Reboot",
		RequiresAdmin: true,
		Help:          "Reboot me, requires token from logs.",
		Keywords:      []string{"reboot", "re", "restart"},
		Exec:          Reboot,
	}
	commands = append(commands, reboot)

	bumpset := Command{
		Name:          "BumpSet",
		RequiresAdmin: true,
		Help:          "Set the bump timer (requires time in minutes until next bump).",
		Keywords:      []string{"bs", "bumpset", "bumps"},
		Exec:          BumpSet,
	}
	commands = append(commands, bumpset)

	retrieveVerification := Command{
		Name:          "Retrieve Verification",
		RequiresAdmin: true,
		Help:          "Retrieve verification either by discord ID or by nickname",
		Keywords:      []string{"veri", "verification", "retrieve"},
		Exec:          RetrieveVerification,
	}
	commands = append(commands, retrieveVerification)

	addQuote := Command{
		Name:          "Add Quote",
		RequiresAdmin: true,
		Keywords:      []string{"quote", "addq", "q"},
		Exec:          AddQuote,
	}
	commands = append(commands, addQuote)

	snap := Command{
		Name:          "Snap",
		RequiresAdmin: false,
		Keywords:      []string{"snap", "purge", "sn"},
		Exec:          Snap,
	}
	commands = append(commands, snap)

	status := Command{
		Name:          "Status",
		RequiresAdmin: true,
		Keywords:      []string{"st", "status", "stats"},
		Exec:          Status,
	}
	commands = append(commands, status)

	listCommands := Command{
		Name:          "List Commands",
		RequiresAdmin: false,
		Keywords:      []string{"help", "commands", "cmd", "cmds"},
		Exec:          Commands,
	}
	commands = append(commands, listCommands)
}

func Commands(b BotCommand) bool {
	defer log.PanicSafe()
	print := "Available commands:\n"
	for _, cmd := range commands {
		if cmd.RequiresAdmin {
			if isAdmin(b.Message.Member) {
				print += fmt.Sprintf("```%+v\n%+v\n%+v```\n", cmd.Name, cmd.Keywords, cmd.Help)
			}
		} else {
			print += fmt.Sprintf("```%+v\n%+v\n%+v```\n", cmd.Name, cmd.Keywords, cmd.Help)
		}
	}
	return true
}

func Reboot(b BotCommand) bool {
	defer log.PanicSafe()
	if strings.Contains(b.Message.Content, rebootToken) {
		exit(b.Session)
		return true
	}
	return false
}

func BumpSet(b BotCommand) bool {
	defer log.PanicSafe()
	bump = false
	parts := strings.Split(b.Message.Content, " ")
	timer, err := strconv.Atoi(parts[1])
	if err != nil {
		b.Session.ChannelMessageSend(b.Message.ChannelID, fmt.Sprintf("Unable to decode timer: %+v", parts[1]))
		return false
	}
	config.BumpTime = time.Now().Add(time.Duration(timer) * time.Minute).Add(-2 * time.Hour)
	b.Session.ChannelMessageSend(b.Message.ChannelID, fmt.Sprintf("New bump time: %+v, expecting bump at %+v", config.BumpTime, config.BumpTime.Add(2*time.Hour)))
	return true
}

func RetrieveVerification(b BotCommand) bool {
	defer log.PanicSafe()
	s := b.Session
	m := b.Message
	parts := strings.Split(m.Content, " ")
	discordId := parts[1]
	_, err := strconv.Atoi(discordId)
	if err != nil {
		discordId = idFromUsername(discordId)
	}
	user, err := s.GuildMember(config.GuildID, discordId)
	if err != nil {
		log.LogErrorType(err)
		return false
	}

	matches, err := filepath.Glob(fmt.Sprintf("./verifications/*%+v*", discordId))
	if err != nil {
		log.LogErrorType(err)
		return false
	}
	if len(matches) != 1 {
		s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("Error finding verification for ID %+v", discordId))
		return false
	}

	verificationImage, err := os.Open(matches[0])
	if err != nil {
		log.LogErrorType(err)
		return false
	}
	msg := fmt.Sprintf("```%+v\nJoined: %+v\n```", user.User.Username, user.JoinedAt)
	s.ChannelFileSendWithMessage(m.ChannelID, msg, fmt.Sprintf("%+v Verification", discordId), verificationImage)
	return true
}

func AddQuote(b BotCommand) bool {
	defer log.PanicSafe()
	quotes = append(quotes, strings.ReplaceAll(b.Message.Content, b.Command, ""))
	return true
}

func Snap(b BotCommand) bool {
	defer log.PanicSafe()
	go runPurge(b.Session)
	b.Session.ChannelMessageSend(config.AdminChannel, quotes[rand.Intn(len(quotes))])
	return true
}

func Status(b BotCommand) bool {
	defer log.PanicSafe()
	status := fmt.Sprintf("Uptime: %+v\n", time.Since(startupTime))
	status += fmt.Sprintf("Last active time: %+v\n", time.Since(lastActiveTime))
	status += fmt.Sprintf("Last bump: %+v\n", time.Since(config.BumpTime))
	status += fmt.Sprintf("Last bumper: %+v\n", userFromID(config.LastBumper).Username)
	status += fmt.Sprintf("Bump needed: %+v\n", bump)
	if len(config.Unverified) > 0 {
		status += "Unverified users:\n```"
		for k, v := range config.Unverified {
			uvUser := userFromID(k)
			status += fmt.Sprintf("\n%+v will be removed in %+v", uvUser.Username, time.Until(v.Add(1*time.Hour)))
		}
		status += "```"
	} else {
		status += "There are no unverified users.\n"
	}
	if len(config.Verifications) > 0 {
		status += "Pending verifications:\n"
		status += "```"
		for _, v := range config.Verifications {
			status += fmt.Sprintf("%+v has submitted a verification.", v.Username)
		}
		status += "```"
	} else {
		status += "There are no pending verifications."
	}
	if len(config.Probations) > 0 {
		status += "\nThe following users are on probation: \n```"
		for uid, join := range config.Probations {
			probationUser := userFromID(uid)
			status += fmt.Sprintf("%+v for another %+v\n", probationUser.Username, time.Until(join.Add(2*time.Hour)))
		}
		status += "```"
	} else {
		status += "There are no users on probation."
	}
	b.Session.ChannelMessageSend(config.AdminChannel, status)
	statistics := "```"
	for k, v := range config.Stats {
		adminUser, err := b.Session.GuildMember(config.GuildID, k)
		if err == nil {
			statistics += fmt.Sprintf("\n%+v: %+v", adminUser.User.Username, v+1)
		} else {
			log.LogErrorType(err)
		}
	}
	statistics += "\n```"
	log.LogInfo("Private statistics: %+v", statistics)
	go runPurge(b.Session)
	return true
}