package db

import (
	"errors"
	"time"

	"TerraOceanBot/common"
)

const (
	ForceRejectionVote = -1
	NuclearOptionVote  = 10
)

var ErrForceRejectionVoteReuse = errors.New("db: the user has used force rejection vote in the last month")
var ErrVoteIsOver = errors.New("db: the vote cannot be changed once it's over")

func CreateCustomVote(messageID, text string) (int, error) {
	result, err := db.Exec("INSERT INTO vote(messageId, name, type, finished) VALUES(?, ?, ?, ?)", messageID, text, "custom", false)
	if err != nil {
		return 0, err
	}
	lastID, err := result.LastInsertId()
	return int(lastID), nil
}

func CreateInviteVote(messageID, username, reason string) (int, error) {
	result, err := db.Exec("INSERT INTO vote(messageId, name, type, finished) VALUES(?, ?, ?, ?)", messageID, username+":"+reason, "invite", false)
	if err != nil {
		return 0, err
	}
	lastID, err := result.LastInsertId()
	return int(lastID), nil
}

func GetVoteName(id int) (string, error) {
	rows, err := db.Query("SELECT name FROM vote WHERE id=?", id)
	if err != nil {
		return "", err
	}
	defer rows.Close()
	if rows.Next() {
		var name string
		err := rows.Scan(&name)
		if err != nil {
			return "", err
		}
		return name, nil
	}
	return "", ErrNotFound
}

func GetVoteFromMessageID(msgID string) (int, error) {
	rows, err := db.Query("SELECT id FROM vote WHERE messageId=?", msgID)
	if err != nil {
		return 0, err
	}
	defer rows.Close()
	if rows.Next() {
		var id int
		err := rows.Scan(&id)
		if err != nil {
			return 0, err
		}
		return id, nil
	}
	return 0, ErrNotFound
}

func GetMessageIDFromVote(voteID int) (string, error) {
	rows, err := db.Query("SELECT messageId FROM vote WHERE id=?", voteID)
	if err != nil {
		return "", err
	}
	defer rows.Close()
	if rows.Next() {
		var id string
		err := rows.Scan(&id)
		if err != nil {
			return "", err
		}
		return id, nil
	}
	return "", ErrNotFound
}

func GetVoteType(voteID int) (string, error) {
	rows, err := db.Query("SELECT type FROM vote WHERE id=?", voteID)
	if err != nil {
		return "", err
	}
	defer rows.Close()
	if rows.Next() {
		var messageType string
		err := rows.Scan(&messageType)
		if err != nil {
			return "", err
		}
		return messageType, nil
	}
	return "", ErrNotFound
}

func UpdateVote(voteID int, userID string, voteValue int) error {
	if voteValue == ForceRejectionVote {
		//Check if they used it within a month.
		rows, err := db.Query("SELECT voteId FROM choices WHERE date >= ? AND value=?", time.Now().AddDate(0, -1, 0), ForceRejectionVote)
		if err != nil {
			return err
		}
		if rows.Next() {
			return ErrForceRejectionVoteReuse
		}
		rows.Close()
	}

	//Check if the vote is finished and don't allow change of vote that way.
	rows, err := db.Query("SELECT finished FROM vote WHERE id=? AND finished=?", voteID, true)
	defer rows.Close()
	if rows.Next() {
		return ErrVoteIsOver
	}

	_, err = db.Exec("REPLACE INTO choices (voteId, userId, date, value) VALUES (?, ?, ?, ?)", voteID, userID, time.Now(), voteValue)
	return err
}

func FinishVote(voteID int) error {
	_, err := db.Exec("UPDATE vote SET finished=true WHERE id=?", voteID)
	return err
}

func GetAllVoteChoices(voteID int) ([]common.VoteChoice, error) {
	rows, err := db.Query("SELECT userId, value FROM choices WHERE voteId=?", voteID)
	if err != nil {
		return []common.VoteChoice{}, err
	}
	defer rows.Close()
	array := make([]common.VoteChoice, 0)
	for rows.Next() {
		var userID string
		var value int
		rows.Scan(&userID, &value)
		array = append(array, common.VoteChoice{
			UserID: userID,
			Value:  value,
		})
	}
	return array, nil
}