<?php

class CommandLocker {
    private $pdo;
    private $lockTimeout = 300; // 5 minutos de tiempo de espera para el bloqueo

    public function __construct(PDO $pdo) {
        $this->pdo = $pdo;
        $this->pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    }

    private function log($message, $data = []) {
        // This will be handled by the main bot's logger
        // For now, do nothing.
    }

    public function acquireLock($command, $chatId, $type = 'command', $data = []) {
        $this->log("Intentando adquirir bloqueo", ['command' => $command, 'chatId' => $chatId, 'type' => $type]);
        $this->cleanupExpiredLocks();
        
        try {
            $this->pdo->beginTransaction();
            
            $query = "SELECT id, status, created_at FROM command_locks WHERE command = ? AND chat_id = ? ORDER BY created_at DESC LIMIT 1 FOR UPDATE";
            $stmt = $this->pdo->prepare($query);
            $stmt->execute([$command, $chatId]);
            $existingLock = $stmt->fetch(PDO::FETCH_ASSOC);
            
            if ($existingLock && $existingLock['status'] === 'processing' && strtotime($existingLock['created_at']) > strtotime('-5 minutes')) {
                $this->log("Bloqueo ya en proceso, rechazando nueva solicitud");
                $this->pdo->rollBack();
                return false;
            }

            $expiresAt = (new DateTime('+5 minutes'))->format('Y-m-d H:i:s');
            $dataJson = !empty($data) ? json_encode($data) : null;
            
            if ($existingLock) {
                $upd = $this->pdo->prepare("UPDATE command_locks SET type = ?, status='processing', data = ?, expires_at = ?, updated_at = NOW() WHERE id = ?");
                $upd->execute([$type, $dataJson, $expiresAt, $existingLock['id']]);
                $this->pdo->commit();
                return (int)$existingLock['id'];
            } else {
                $query = "INSERT INTO command_locks (chat_id, command, type, data, status, expires_at, created_at, updated_at) VALUES (?, ?, ?, ?, 'processing', ?, NOW(), NOW())";
                $stmt = $this->pdo->prepare($query);
                $stmt->execute([$chatId, $command, $type, $dataJson, $expiresAt]);
                $lockId = $this->pdo->lastInsertId();
                $this->pdo->commit();
                return (int)$lockId;
            }
        } catch (Exception $e) {
            $this->log("Error al adquirir bloqueo", ['error' => $e->getMessage()]);
            if ($this->pdo->inTransaction()) {
                $this->pdo->rollBack();
            }
            return false;
        }
    }

    public function updateLockStatus($lockId, $status, $messageId = null) {
        $this->log("Actualizando estado de bloqueo", ['lockId' => $lockId, 'status' => $status]);
        try {
            $query = "UPDATE command_locks SET status = ?, message_id = COALESCE(?, message_id), updated_at = NOW() WHERE id = ?";
            $stmt = $this->pdo->prepare($query);
            return $stmt->execute([$status, $messageId, $lockId]);
        } catch (Exception $e) {
            $this->log("Error al actualizar estado de bloqueo", ['error' => $e->getMessage()]);
            return false;
        }
    }
    
    public function releaseLock($lockId, $messageId = null) {
        return $this->updateLockStatus($lockId, 'completed', $messageId);
    }
    
    public function failLock($lockId, $errorMessage = '') {
        $this->log("Marcando bloqueo como fallido", ['lockId' => $lockId, 'errorMessage' => $errorMessage]);
        try {
            $query = "UPDATE command_locks SET status = 'failed', data = JSON_SET(COALESCE(data, '{}'), '$.error', ?) WHERE id = ?";
            $stmt = $this->pdo->prepare($query);
            return $stmt->execute([$errorMessage, $lockId]);
        } catch (Exception $e) {
            $this->log("Error al marcar bloqueo como fallido", ['error' => $e->getMessage()]);
            return false;
        }
    }

    private function cleanupExpiredLocks() {
        try {
            $this->pdo->exec("DELETE FROM command_locks WHERE expires_at <= NOW()");
        } catch (Exception $e) {
            $this->log("Error al limpiar bloqueos expirados", ['error' => $e->getMessage()]);
        }
    }
}
