package controller

import (
    "arimelody-web/model"
    "strings"

    "github.com/jmoiron/sqlx"
)

func GetAllAccounts(db *sqlx.DB) ([]model.Account, error) {
    var accounts = []model.Account{}

    err := db.Select(&accounts, "SELECT * FROM account ORDER BY created_at ASC")
    if err != nil {
        return nil, err
    }

    return accounts, nil
}

func GetAccountByID(db *sqlx.DB, id string) (*model.Account, error) {
    var account = model.Account{}

    err := db.Get(&account, "SELECT * FROM account WHERE id=$1", id)
    if err != nil {
        if strings.Contains(err.Error(), "no rows") {
            return nil, nil
        }
        return nil, err
    }

    return &account, nil
}

func GetAccountByUsername(db *sqlx.DB, username string) (*model.Account, error) {
    var account = model.Account{}

    err := db.Get(&account, "SELECT * FROM account WHERE username=$1", username)
    if err != nil {
        if strings.Contains(err.Error(), "no rows") {
            return nil, nil
        }
        return nil, err
    }

    return &account, nil
}

func GetAccountByEmail(db *sqlx.DB, email string) (*model.Account, error) {
    var account = model.Account{}

    err := db.Get(&account, "SELECT * FROM account WHERE email=$1", email)
    if err != nil {
        if strings.Contains(err.Error(), "no rows") {
            return nil, nil
        }
        return nil, err
    }

    return &account, nil
}

func GetAccountBySession(db *sqlx.DB, sessionToken string) (*model.Account, error) {
    if sessionToken == "" { return nil, nil }

    account := model.Account{}

    err := db.Get(&account, "SELECT account.* FROM account JOIN token ON id=account WHERE token=$1", sessionToken)
    if err != nil {
        if strings.Contains(err.Error(), "no rows") {
            return nil, nil
        }
        return nil, err
    }

    return &account, nil
}

func CreateAccount(db *sqlx.DB, account *model.Account) error {
    err := db.Get(
        &account.ID,
        "INSERT INTO account (username, password, email, avatar_url) " +
        "VALUES ($1, $2, $3, $4) " +
        "RETURNING id",
        account.Username,
        account.Password,
        account.Email,
        account.AvatarURL,
    )

    return err
}

func UpdateAccount(db *sqlx.DB, account *model.Account) error {
    _, err := db.Exec(
        "UPDATE account " +
        "SET username=$2,password=$3,email=$4,avatar_url=$5 " +
        "WHERE id=$1",
        account.ID,
        account.Username,
        account.Password,
        account.Email,
        account.AvatarURL,
    )

    return err
}

func DeleteAccount(db *sqlx.DB, accountID string) error {
    _, err := db.Exec("DELETE FROM account WHERE id=$1", accountID)
    return err
}

func IncrementAccountFails(db *sqlx.DB, accountID string) (bool, error) {
    failAttempts := 0
    err := db.Get(&failAttempts, "UPDATE account SET fail_attempts = fail_attempts + 1 WHERE id=$1 RETURNING fail_attempts", accountID)
    if err != nil { return false, err }
    locked := false
    if failAttempts >= model.MAX_LOGIN_FAIL_ATTEMPTS {
        err = LockAccount(db, accountID)
        if err != nil { return false, err }
        locked = true
    }
    return locked, err
}

func LockAccount(db *sqlx.DB, accountID string) error {
    _, err := db.Exec("UPDATE account SET locked = true WHERE id=$1", accountID)
    return err
}

func UnlockAccount(db *sqlx.DB, accountID string) error {
    _, err := db.Exec("UPDATE account SET locked = false, fail_attempts = 0 WHERE id=$1", accountID)
    return err
}
