package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"time"
	"os"

	"github.com/bwmarrin/discordgo"
)

func status(s *discordgo.Session) {
	defer log.PanicSafe()
	monChan, _ := s.Channel(config.MonitorChann)

	roles, _ := s.GuildRoles(config.GuildID)
	var monRole discordgo.Role
	var veriRole discordgo.Role
	for _, role := range roles {
		if role.ID == config.MonitorRole {
			monRole = *role
		}
		if role.ID == config.VerifiedRole {
			veriRole = *role
		}
	}
	status := fmt.Sprintf("Uptime: %+v\n", time.Since(startupTime))
	status += fmt.Sprintf("Monitor role: %+v\n", monRole.Mention())
	status += fmt.Sprintf("Monitor chann: %+v\n", monChan.Mention())
	status += fmt.Sprintf("Verified role: %+v\n", veriRole.Mention())
	status += fmt.Sprintf("Last bump: %+v\n", time.Since(config.BumpTime))
	status += fmt.Sprintf("Last bumper: <@%+v>\n", config.LastBumper)
	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(s, 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(s, uid)
			status += fmt.Sprintf("%+v for another %+v\n", probationUser.Username, time.Until(join.Add(2*time.Hour)))
		}
		status += "```"
	}
	s.ChannelMessageSend(config.AdminChannel, status)
	statistics := "```"
	for k, v := range config.Stats {
		adminUser, err := s.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(fmt.Sprintf("Private statistics: %+v", statistics))
	go runPurge(s)
	return
}

func loadConfig() {
	var c Config
	confFile, _ := ioutil.ReadFile(configFile)
	err := json.Unmarshal([]byte(confFile), &c)
	if err != nil {
		log.LogErrorType(err)
		return
	}
	config = c

	if time.Since(config.BumpTime) < (2 * time.Hour) {
		bump = false
	} else {
		bump = true
	}

	if config.Stats == nil {
		config.Stats = make(map[string]int)
	}
	if config.Unverified == nil {
		config.Unverified = make(map[string]time.Time)
	}
	if config.Verifications == nil {
		config.Verifications = make(map[string]Verification)
	}
	if config.Probations == nil {
		config.Probations = make(map[string]time.Time)
	}

	log.LogInfo("Setup completed using config file.")
}

func saveConfig() {
	defer log.PanicSafe()
	file, err := json.Marshal(config)
	if err != nil {
		log.LogErrorType(err)
	}
	err = ioutil.WriteFile(configFile, file, 0600)
	if err != nil {
		log.LogErrorType(err)
	} 
}

func setAdminChannel(s *discordgo.Session, m *discordgo.MessageCreate) {
	config.AdminChannel = m.ChannelID
	if len(m.MentionRoles) != 1 {
		s.ChannelMessageSend(config.AdminChannel, "Invalid verified role")
		return
	}
	config.VerifiedRole = m.MentionRoles[0]
	s.ChannelMessageDelete(m.ChannelID, m.ID)
	msg, _ := s.ChannelMessageSend(config.AdminChannel, "Run !setup in the monitored channel to finish setup.")
	setupMsg = msg.ID
}
func setMonitorChann(s *discordgo.Session, m *discordgo.MessageCreate) {
	config.MonitorChann = m.ChannelID
	if len(m.MentionRoles) != 1 {
		s.ChannelMessageSend(config.AdminChannel, "Invalid monitor role")
		return
	}
	config.MonitorRole = m.MentionRoles[0]
	s.ChannelMessageDelete(m.ChannelID, m.ID)
	s.ChannelMessageSend(config.AdminChannel, "Setup completed. Run !status for status.")
	s.ChannelMessageDelete(config.AdminChannel, setupMsg)
	go purgeTimer(s)
	saveConfig()
}

func bumpTimer(s *discordgo.Session) {
	if !bump {
		return
	}
	bump = false
	config.BumpTime = time.Now()
	time.Sleep(2 * time.Hour)
	if time.Since(lastActiveTime) < (5*time.Minute) && lastActiveChan != config.AdminChannel {
		s.ChannelMessageSend(lastActiveChan, "!d bump is ready, please use it. (say \"!d bump\" without the quotes)")
	}
	s.ChannelMessageSend(config.AdminChannel, "!d bump is ready.")
	bump = true
}
func purgeTimer(s *discordgo.Session) {
	for {
		runPurge(s)
		saveConfig()
		if time.Since(lastActiveTime) > 4 * time.Hour && time.Since(startupTime) > 12 * time.Hour {
			saveConfig()
			os.Exit(0)
		}
		time.Sleep(20 * time.Minute)
	}
}

func (v Verification) prettyPrint() string {
	ret := ""
	ret += fmt.Sprintf("```%+v has marked %+v's verification as %+v\n", v.Admin, v.Username, v.Status)
	ret += fmt.Sprintf("Submitted: %+v\nClosed: %+v\n", v.Submitted, v.Closed)
	ret += fmt.Sprintf("Turnaround time: %+v```", time.Since(v.Submitted))
	ret += fmt.Sprintf("\n%+v", v.Photo)
	return ret
}

func userFromID(s *discordgo.Session, i string) discordgo.User {
	u, err := s.GuildMember(config.GuildID, i)
	if err != nil {
		log.LogErrorType(err)
		return discordgo.User{}
	}
	return *u.User
}

func adminInteraction(s *discordgo.Session, m string) {
	admin, _ := s.GuildMember(config.GuildID, m)
	counter, ok := config.Stats[admin.User.ID]
	if !ok {
		config.Stats[admin.User.ID] = 0
	} else {
		config.Stats[admin.User.ID] = counter + 1
	}

}