<?php
namespace app\models;

use app\app;

class transactions
{
    const TYPES = ['CREDIT', 'REWARD', 'REDEEM', 'REVOKE', 'DEPOSIT'];

    public static function init()
    {
        $typesList = "'" . implode("', '", self::TYPES) . "'";
        app::$db->exec("CREATE TABLE IF NOT EXISTS transactions (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            user_id INTEGER NOT NULL REFERENCES users(id),
            type TEXT CHECK(type IN ($typesList)) NOT NULL,
            cents INTEGER DEFAULT 0,
            sats INTEGER DEFAULT 0,
            date TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )");
    }

    public static function getById($id)
    {
        $query = "SELECT * FROM transactions WHERE id = :id";
        $stmt  = app::$db->prepare($query);
        $stmt->bindParam(':id', $id, \PDO::PARAM_INT);
        $stmt->execute();
        return $stmt->fetch();
    }

    public static function add($user_id, $transaction_type, $cents, $sats)
    {
        if (! in_array($transaction_type, self::TYPES)) {
            throw new \Exception("Invalid transaction type.");
        }
        if ($cents < 0 || $sats < 0) {
            throw new \Exception("Amounts must be non-negative integers.");
        }
        $currentBalance = self::getUserBalance($user_id);
        if (in_array($transaction_type, ['REDEEM', 'REVOKE']) && ($currentBalance['total_cents'] < $cents || $currentBalance['total_sats'] < $sats)) {
            throw new \Exception("Insufficient funds.");
        }
        $query = "INSERT INTO transactions (user_id, type, cents, sats) VALUES (:user_id, :transaction_type, :cents, :sats)";
        $stmt  = app::$db->prepare($query);
        $stmt->bindParam(':user_id', $user_id);
        $stmt->bindParam(':transaction_type', $transaction_type);
        $stmt->bindParam(':cents', $cents);
        $stmt->bindParam(':sats', $sats);
        $stmt->execute();
        return app::$db->lastInsertId();
    }

    public static function getUserBalance($user_id)
    {
        $query = "SELECT COALESCE(SUM(cents), 0) AS cents, COALESCE(SUM(sats), 0) AS sats FROM transactions WHERE user_id = :user_id";
        $stmt  = app::$db->prepare($query);
        $stmt->bindParam(':user_id', $user_id);
        $stmt->execute();
        return $stmt->fetch();
    }

    public static function getRecent($n, $currency)
    {
        $query = "SELECT * FROM transactions WHERE $currency > 0 ORDER BY date DESC LIMIT :n";
        $stmt  = app::$db->prepare($query);
        $stmt->bindParam(':n', $n, \PDO::PARAM_INT);
        $stmt->execute();
        return $stmt->fetchAll();
    }

    public static function getWhales($n, $currency)
    {
        if (! in_array($currency, ['cents', 'sats'])) {
            throw new \Exception("Invalid currency type.");
        }
        $query = "SELECT user_id, COALESCE(SUM($currency), 0) AS total FROM transactions GROUP BY user_id ORDER BY total DESC LIMIT :n";
        $stmt  = app::$db->prepare($query);
        $stmt->bindParam(':n', $n, \PDO::PARAM_INT);
        $stmt->execute();
        return $stmt->fetchAll();
    }

    public static function getLiabilities($currency)
    {
        if (! in_array($currency, ['cents', 'sats'])) {
            throw new \Exception("Invalid currency type.");
        }
        $query = "SELECT COALESCE(SUM($currency), 0) AS total FROM transactions";
        $stmt  = app::$db->prepare($query);
        $stmt->execute();
        return $stmt->fetchColumn();
    }
}
