<?php
/* Upload-Token für Mobile-Foto-Upload zu einem Dolibarr-Objekt (Auftrag/Rechnung/Angebot).
 * Token = 64 Hex-Zeichen, gültig 1h, max 100 Uploads.
 * Fotos landen direkt im Dolibarr-Standard-Ordner des Objekts (z.B. commande/{ref}/).
 */

class BerichtUploadToken
{
    public $db;
    public $id;
    public $token;
    public $fk_element;
    public $element_type;
    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 ein Dolibarr-Objekt.
     * Räumt dabei abgelaufene Tokens gleich mit auf (kein Cronjob nötig).
     * @param int    $fk_element    ID des Dolibarr-Objekts (z.B. Auftrags-ID)
     * @param string $element_type  Typ: 'order', 'invoice', 'propal'
     * @param int    $fk_user       User-ID
     * @param int    $lifetime      Gültigkeit in Sekunden (Standard: 3600)
     * @param int    $max_uploads   Max. Uploads (Standard: 100)
     * @return string|false  Hex-Token bei Erfolg
     */
    public function create($fk_element, $element_type, $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_element    = (int) $fk_element;
        $this->element_type  = $element_type;
        $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_element, element_type, fk_user_creat, expires_at, uploads_count, max_uploads, datec) VALUES ("
            ."'".$this->db->escape($this->token)."',"
            .$this->fk_element.","
            ."'".$this->db->escape($this->element_type)."',"
            .$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_element, element_type, 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_element     = (int) $obj->fk_element;
        $t->element_type   = $obj->element_type;
        $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;
    }

    /**
     * Ermittelt den Upload-Ordner für dieses Token basierend auf element_type.
     * @return string|false  Absoluter Pfad zum Upload-Ordner, false bei Fehler
     */
    public function getUploadDir()
    {
        global $conf;
        $parent = $this->fetchParentObject();
        if (!$parent) return false;

        $ref = dol_sanitizeFileName($parent->ref);
        switch ($this->element_type) {
            case 'order':
                return $conf->commande->multidir_output[$parent->entity].'/'.$ref;
            case 'invoice':
                return $conf->facture->multidir_output[$parent->entity].'/'.$ref;
            case 'propal':
                return $conf->propal->multidir_output[$parent->entity].'/'.$ref;
            default:
                return false;
        }
    }

    /**
     * Lädt das Dolibarr-Parent-Objekt (Auftrag/Rechnung/Angebot).
     * @return CommonObject|false
     */
    public function fetchParentObject()
    {
        switch ($this->element_type) {
            case 'order':
                require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
                $obj = new Commande($this->db);
                break;
            case 'invoice':
                require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
                $obj = new Facture($this->db);
                break;
            case 'propal':
                require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
                $obj = new Propal($this->db);
                break;
            default:
                return false;
        }
        if ($obj->fetch($this->fk_element) <= 0) return false;
        return $obj;
    }

    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())."'");
    }
}
