package main

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/bwmarrin/discordgo"
)

func status(s *discordgo.Session) {
	defer log.PanicSafe()
	status := fmt.Sprintf("Uptime: %+v\n", time.Since(startupTime))
	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 += "```"
	}
	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("Private statistics: %+v", statistics)
	go runPurge(s)
	return
}
func storeVerification(v Verification) {
	defer log.PanicSafe()
	fileURL, _ := url.Parse(v.Photo)
	path := fileURL.Path
	segments := strings.Split(path, "/")

	fileName := segments[len(segments)-1]
	file, _ := os.Create(fmt.Sprintf("./verifications/%s-%s-%s", v.UserID, v.Username, fileName))
	client := http.Client{
		CheckRedirect: func(r *http.Request, via []*http.Request) error {
			r.URL.Opaque = r.URL.Path
			return nil
		},
	}
	resp, err := client.Get(v.Photo)
	if err != nil {
		log.LogError("Unable to download verification %s-%s-%s", v.UserID, v.Username, fileName)
	}
	defer resp.Body.Close()
	defer file.Close()
	_, err = io.Copy(file, resp.Body)
	if err != nil {
		log.LogError("Unable to store verification %s-%s-%s", v.UserID, v.Username, fileName)
	}
}
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 findVerification(s *discordgo.Session, m *discordgo.MessageCreate) {
	defer log.PanicSafe()
	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)
	}

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

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

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 {
			log.LogInfo("Restarting.")
			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 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
	}

}