<?php
namespace EasyChat\Model;

class ModerationToken extends Base {

    public function ensureTable() {
        $this->db->query("CREATE TABLE IF NOT EXISTS `{$this->prefix}moderation_tokens` (
            `id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
            `public_id` VARCHAR(64) NOT NULL,
            `token_hash` CHAR(64) NOT NULL,
            `purpose` VARCHAR(64) NOT NULL,
            `version_code` INT(11) NOT NULL DEFAULT 0,
            `expires_at` DATETIME NOT NULL,
            `used_at` DATETIME DEFAULT NULL,
            `created_at` DATETIME NOT NULL,
            `used_by_fcm_hash` CHAR(64) DEFAULT NULL,
            `last_error` VARCHAR(255) DEFAULT NULL,
            UNIQUE KEY `uniq_public_id` (`public_id`),
            UNIQUE KEY `uniq_token_hash` (`token_hash`),
            KEY `idx_purpose_expires` (`purpose`, `expires_at`),
            KEY `idx_used_at` (`used_at`)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");
    }

    public function createToken($public_id, $plain_token, $purpose, $version_code, $expires_at) {
        $this->ensureTable();
        $this->db->query("INSERT INTO `{$this->prefix}moderation_tokens` SET
            `public_id` = '" . $this->db->escape($public_id) . "',
            `token_hash` = '" . $this->db->escape($this->hashToken($plain_token)) . "',
            `purpose` = '" . $this->db->escape($purpose) . "',
            `version_code` = " . (int)$version_code . ",
            `expires_at` = '" . $this->db->escape($expires_at) . "',
            `created_at` = NOW()");
    }

    public function validateFreshToken($plain_token, $purpose, $version_code) {
        $this->ensureTable();
        $token_hash = $this->hashToken($plain_token);
        $query = $this->db->query("SELECT *, (`expires_at` <= NOW()) AS `is_expired`
            FROM `{$this->prefix}moderation_tokens`
            WHERE `token_hash` = '" . $this->db->escape($token_hash) . "'
            LIMIT 1");

        if (!$query || !$query->num_rows) {
            return $this->validationError($token_hash, 'not_found');
        }

        $row = $query->row;
        if ($row['purpose'] !== $purpose) {
            return $this->validationError($token_hash, 'purpose_mismatch');
        }
        if ((int)$row['version_code'] !== (int)$version_code) {
            return $this->validationError($token_hash, 'version_mismatch');
        }
        if (!empty($row['used_at'])) {
            return $this->validationError($token_hash, 'already_used');
        }
        if ((int)$row['is_expired'] === 1) {
            return $this->validationError($token_hash, 'expired');
        }

        return array('success' => true, 'row' => $row);
    }

    public function markUsed($plain_token, $fcm_token) {
        $fcm_hash = $fcm_token !== '' ? hash('sha256', $fcm_token) : null;
        $set_fcm = $fcm_hash
            ? ", `used_by_fcm_hash` = '" . $this->db->escape($fcm_hash) . "'"
            : "";

        $this->db->query("UPDATE `{$this->prefix}moderation_tokens`
            SET `used_at` = NOW(), `last_error` = NULL{$set_fcm}
            WHERE `token_hash` = '" . $this->db->escape($this->hashToken($plain_token)) . "'
              AND `used_at` IS NULL
            LIMIT 1");
    }

    private function validationError($token_hash, $reason) {
        if ($token_hash !== '') {
            $this->db->query("UPDATE `{$this->prefix}moderation_tokens`
                SET `last_error` = '" . $this->db->escape($reason) . "'
                WHERE `token_hash` = '" . $this->db->escape($token_hash) . "'
                LIMIT 1");
        }

        return array('success' => false, 'error' => $reason);
    }

    private function hashToken($plain_token) {
        return hash('sha256', (string)$plain_token);
    }
}
