<?php
/* Upload-Token für Mobile-Upload eines Berichts.
 * Token = 64 Hex-Zeichen, gültig 1h, max 100 Uploads.
 */

class BerichtUploadToken
{
    public $db;
    public $id;
    public $token;
    public $fk_bericht;
    public $fk_user_creat;
    public $expires_at;
    public $uploads_count = 0;
    public $max_uploads = 100;
    public $datec;

    const DEFAULT_LIFETIME = 3600; // 1h
    const DEFAULT_MAX_UPLOADS = 100;

    public function __construct(DoliDB $db)
    {
        $this->db = $db;
    }

    /**
     * Erstellt einen neuen Token für einen Bericht.
     * Räumt dabei abgelaufene Tokens gleich mit auf (kein Cronjob nötig).
     * @return string|false  Hex-Token bei Erfolg
     */
    public function create($fk_bericht, $fk_user, $lifetime = null, $max_uploads = null)
    {
        // Opportunistisches Cleanup: entferne abgelaufene Tokens bei jedem Insert
        $this->db->query("DELETE FROM ".$this->db->prefix()."bericht_upload_token"
            ." WHERE expires_at < '".$this->db->idate(dol_now())."'", 1);

        $this->token        = bin2hex(random_bytes(32));
        $this->fk_bericht   = (int) $fk_bericht;
        $this->fk_user_creat = (int) $fk_user;
        $this->datec        = dol_now();
        $this->expires_at   = $this->datec + ($lifetime ?: self::DEFAULT_LIFETIME);
        $this->max_uploads  = $max_uploads ?: self::DEFAULT_MAX_UPLOADS;
        $this->uploads_count = 0;

        $sql = "INSERT INTO ".$this->db->prefix()."bericht_upload_token "
            ."(token, fk_bericht, fk_user_creat, expires_at, uploads_count, max_uploads, datec) VALUES ("
            ."'".$this->db->escape($this->token)."',"
            .$this->fk_bericht.","
            .$this->fk_user_creat.","
            ."'".$this->db->idate($this->expires_at)."',"
            ."0,"
            .$this->max_uploads.","
            ."'".$this->db->idate($this->datec)."'"
            .")";
        if (!$this->db->query($sql)) return false;
        $this->id = $this->db->last_insert_id($this->db->prefix()."bericht_upload_token");
        return $this->token;
    }

    /**
     * Lädt einen Token und prüft Gültigkeit.
     * @return BerichtUploadToken|null
     */
    public static function fetchValid(DoliDB $db, $token)
    {
        if (!preg_match('/^[a-f0-9]{64}$/', $token)) return null;
        $sql = "SELECT rowid, token, fk_bericht, fk_user_creat, expires_at, uploads_count, max_uploads, datec"
            ." FROM ".$db->prefix()."bericht_upload_token"
            ." WHERE token = '".$db->escape($token)."'"
            ." AND expires_at > '".$db->idate(dol_now())."'"
            ." AND uploads_count < max_uploads";
        $res = $db->query($sql);
        if (!$res || $db->num_rows($res) === 0) return null;
        $obj = $db->fetch_object($res);
        $t = new self($db);
        $t->id = (int) $obj->rowid;
        $t->token = $obj->token;
        $t->fk_bericht = (int) $obj->fk_bericht;
        $t->fk_user_creat = (int) $obj->fk_user_creat;
        $t->expires_at = $db->jdate($obj->expires_at);
        $t->uploads_count = (int) $obj->uploads_count;
        $t->max_uploads = (int) $obj->max_uploads;
        $t->datec = $db->jdate($obj->datec);
        return $t;
    }

    public function incrementCount()
    {
        $this->uploads_count++;
        return $this->db->query("UPDATE ".$this->db->prefix()."bericht_upload_token"
            ." SET uploads_count = uploads_count + 1"
            ." WHERE rowid = ".((int) $this->id));
    }

    /**
     * Instanz-Methode für den Dolibarr-Cronjob.
     * Räumt expired Tokens auf.
     *
     * @return int  Anzahl gelöschter Tokens (>=0), -1 bei Fehler
     */
    public function cleanupExpired()
    {
        $sql = "DELETE FROM ".$this->db->prefix()."bericht_upload_token"
            ." WHERE expires_at < '".$this->db->idate(dol_now())."'";
        $res = $this->db->query($sql);
        if (!$res) {
            $this->error = $this->db->lasterror();
            return -1;
        }
        return $this->db->affected_rows($res);
    }

    /**
     * Statische Variante für Direktaufrufe außerhalb des Cronjobs.
     */
    public static function cleanupExpiredStatic(DoliDB $db)
    {
        $db->query("DELETE FROM ".$db->prefix()."bericht_upload_token"
            ." WHERE expires_at < '".$db->idate(dol_now())."'");
    }
}
