package tasks

import (
	"fmt"
	"log"
	"time"

	"github.com/bwmarrin/discordgo"
	"github.com/dustinpianalto/goff/internal/postgres"
)

type Task struct {
	ID           int64
	Type         string
	Content      string
	GuildID      string
	ChannelID    string
	UserID       string
	CreationTime time.Time
	TriggerTime  time.Time
}

func processTask(task *Task, s *discordgo.Session) {
	query := "SELECT completed, processing from tasks where id = $1"
	res, err := postgres.DB.Query(query, task.ID)
	if err != nil {
		log.Println(err)
		return
	}
	var completed bool
	var processing bool
	res.Next()
	err = res.Scan(&completed, &processing)
	if err != nil {
		log.Println(err)
		return
	}
	if completed || processing {
		return
	}
	closeQuery := "Update tasks set completed = true where id = $1"
	processQuery := "UPDATE tasks SET processing = true WHERE id = $1"
	defer postgres.DB.Exec(closeQuery, task.ID)
	_, err = postgres.DB.Exec(processQuery, task.ID)
	if err != nil {
		log.Println(err)
		return
	}
	log.Println(fmt.Sprintf("Processing task %v", task.ID))
	guild, err := s.Guild(task.GuildID)
	if err != nil {
		log.Print(fmt.Sprintf("Can't find guild with ID %v. Canceling task %v.", task.GuildID, task.ID))
		return
	}
	channel, err := s.Channel(task.ChannelID)
	if err != nil {
		log.Print(fmt.Sprintf("Can't find channel with ID %v. Canceling task %v.", task.ChannelID, task.ID))
		return
	}
	if channel.GuildID != guild.ID {
		log.Print(fmt.Sprintf("The channel %v is not in guild %v. Canceling task %v.", channel.Name, guild.Name, task.ID))
		return
	}
	member, err := s.GuildMember(guild.ID, task.UserID)
	if err != nil {
		log.Print(fmt.Sprintf("Can't find user with ID %v in guild %v. Canceling task %v.", task.UserID, guild.Name, task.ID))
		return
	}
	if task.Type == "Reminder" {
		color := s.State.UserColor(member.User.ID, channel.ID)
		e := discordgo.MessageEmbed{
			Title:       "REMINDER",
			Description: task.Content,
			Timestamp:   task.CreationTime.Format(time.RFC3339),
			Color:       color,
			Footer: &discordgo.MessageEmbedFooter{
				Text: "Created: ",
			},
		}
		msg := discordgo.MessageSend{
			Content: member.Mention(),
			Embed:   &e,
		}
		_, err = s.ChannelMessageSendComplex(channel.ID, &msg)
		if err != nil {
			log.Println(err)
		}
	}
	processQuery = "UPDATE tasks SET processing = false WHERE id = $1"
	_, err = postgres.DB.Exec(processQuery, task.ID)
	if err != nil {
		log.Println(err)
	}

}

func getTasksToRun() []Task {
	query := "SELECT id, type, content, guild_id, channel_id, user_id, creation_time, trigger_time " +
		"from tasks where completed is false and processing is false and trigger_time < $1"
	res, err := postgres.DB.Query(query, time.Now())
	if err != nil {
		log.Println(err)
		return nil
	}
	var tasks []Task
	for res.Next() {
		var t Task
		err = res.Scan(&t.ID, &t.Type, &t.Content, &t.GuildID, &t.ChannelID, &t.UserID, &t.CreationTime, &t.TriggerTime)
		if err != nil {
			log.Println(err)
		}
		for _, task := range tasks {
			if task.ID == t.ID {
				continue
			}
		}
		tasks = append(tasks, t)
	}

	return tasks
}

func ProcessTasks(s *discordgo.Session, interval int) {
	for {
		time.Sleep(time.Duration(interval * 1e9))

		tasks := getTasksToRun()

		if len(tasks) > 0 {
			for _, t := range tasks {
				go processTask(&t, s)
			}
		}
	}
}
