#!/usr/bin/env php
<?php
/**
 * auto_rotate_key.php - Автоматическая ротация ключа текущего хоста
 */

// Убираем конфликт с ROOT_PATH
if (!defined('ROOT_PATH')) {
    define('ROOT_PATH', '/var/www/html/admin');
}

// Подключаем конфиг без определения ROOT_PATH
$configPath = '/var/www/html/admin/config.php';
if (file_exists($configPath)) {
    require_once $configPath;
}

define('LOG_FILE', '/var/www/minib/logs/auto_rotation.log');

function logMessage($message) {
    $timestamp = date('Y-m-d H:i:s');
    @file_put_contents(LOG_FILE, "[$timestamp] $message\n", FILE_APPEND);
    echo "[$timestamp] $message\n";
}

function getRotationInterval($db) {
    // Получаем интервал из таблицы settings
    $stmt = $db->prepare('SELECT setValue FROM settings WHERE setId = 4');
    $result = $stmt->execute();
    $row = $result->fetchArray(SQLITE3_ASSOC);
    
    if ($row && isset($row['setValue'])) {
        $interval = (int)$row['setValue'];
        logMessage("Rotation interval from settings: {$interval} days");
        return $interval;
    }
    
    // Значение по умолчанию, если в settings нет записи
    logMessage("Settings record not found, using default: 30 days");
    return 30;
}

function getCurrentHost($db) {
    $stmt = $db->prepare('SELECT * FROM hosts WHERE idHost = 1');
    $result = $stmt->execute();
    $host = $result->fetchArray(SQLITE3_ASSOC);
    
    if (!$host) {
        throw new Exception("Local host (idHost=1) not found in database");
    }
    
    return $host;
}

function generateApiKey() {
    return bin2hex(random_bytes(32));
}

function shouldRotate($db, $host) {
    $rotationInterval = getRotationInterval($db);
    
    // Если интервал = 0, ротация отключена
    if ($rotationInterval === 0) {
        logMessage("Rotation is disabled (interval = 0 days), skipping");
        return false;
    }
    
    if (empty($host['hostDateApiUpdtae'])) {
        logMessage("No previous rotation date found, will rotate");
        return true;
    }
    
    $lastRotation = strtotime($host['hostDateApiUpdtae']);
    $daysPassed = (time() - $lastRotation) / 86400;
    
    logMessage("Last rotation: {$host['hostDateApiUpdtae']} (" . round($daysPassed, 2) . " days ago)");
    logMessage("Rotation interval: {$rotationInterval} days");
    
    return $daysPassed >= $rotationInterval;
}

function main($argv) {
    $force = in_array('--force', $argv);
    
    logMessage("=== Auto Key Rotation Started ===");
    
    try {
        $db = getDB();
        
        // Проверяем интервал ротации
        $rotationInterval = getRotationInterval($db);
        
        // Если интервал = 0 и не force, выходим
        if ($rotationInterval === 0 && !$force) {
            logMessage("Rotation is disabled (interval = 0 days). Use --force to override.");
            logMessage("=== Auto Key Rotation Finished ===");
            return;
        }
        
        if ($rotationInterval === 0 && $force) {
            logMessage("WARNING: Rotation is disabled but --force flag used, forcing rotation anyway");
        }
        
        $host = getCurrentHost($db);
        
        logMessage("Current host: {$host['hostName']} (SN: {$host['hostSn']})");
        logMessage("Host type: {$host['hostType']}");
        
        if (!$force && !shouldRotate($db, $host)) {
            logMessage("Key is still fresh, skipping rotation");
            logMessage("=== Auto Key Rotation Finished ===");
            return;
        }
        
        // Генерируем новый ключ
        $newKey = generateApiKey();
        $oldKey = $host['hostApiKey'];
        
        logMessage("Generating new API key...");
        logMessage("Old key: " . substr($oldKey, 0, 16) . "...");
        logMessage("New key: " . substr($newKey, 0, 16) . "...");
        
        // Обновляем ключ в базе
        $stmt = $db->prepare('
            UPDATE hosts 
            SET hostOldApiKey = :oldKey, 
                hostApiKey = :newKey, 
                hostDateApiUpdtae = datetime("now")
            WHERE hostSn = :sn
        ');
        $stmt->bindValue(':oldKey', $oldKey, SQLITE3_TEXT);
        $stmt->bindValue(':newKey', $newKey, SQLITE3_TEXT);
        $stmt->bindValue(':sn', $host['hostSn'], SQLITE3_TEXT);
        $stmt->execute();
        
        logMessage("✓ Key updated in database");
        
        // Если это мастер, создаем задачи для слейвов
        if ($host['hostType'] === 'master') {
            // Находим всех слейвов
            $stmt = $db->prepare('SELECT * FROM hosts WHERE hostType = "slave"');
            $result = $stmt->execute();
            
            $slaves = [];
            while ($slave = $result->fetchArray(SQLITE3_ASSOC)) {
                $slaves[] = $slave;
            }
            
            if (!empty($slaves)) {
                logMessage("Creating tasks for " . count($slaves) . " slave(s)...");
                
                foreach ($slaves as $slave) {
                    $stmt = $db->prepare('
                        INSERT INTO key_rotation_tasks 
                        (initiatorSn, targetSn, newApiKey, oldApiKey, status, attempts, maxAttempts, 
                         rotationType, initiationDate)
                        VALUES (:initiator, :target, :newKey, :oldKey, "pending", 0, 5, 
                                "master_to_slave", datetime("now"))
                    ');
                    $stmt->bindValue(':initiator', $host['hostSn'], SQLITE3_TEXT);
                    $stmt->bindValue(':target', $slave['hostSn'], SQLITE3_TEXT);
                    $stmt->bindValue(':newKey', $newKey, SQLITE3_TEXT);
                    $stmt->bindValue(':oldKey', $oldKey, SQLITE3_TEXT);
                    $stmt->execute();
                    
                    $taskId = $db->lastInsertRowID();
                    logMessage("  Task {$taskId} created for slave: {$slave['hostSn']}");
                }
            } else {
                logMessage("No slaves found to notify");
            }
        } else {
            // Если это слейв, создаем задачи для мастеров
            $stmt = $db->prepare('SELECT * FROM hosts WHERE hostType = "master"');
            $result = $stmt->execute();
            
            $masters = [];
            while ($master = $result->fetchArray(SQLITE3_ASSOC)) {
                $masters[] = $master;
            }
            
            if (!empty($masters)) {
                $mastersJson = json_encode(array_column($masters, 'hostSn'));
                
                $stmt = $db->prepare('
                    INSERT INTO key_rotation_tasks 
                    (initiatorSn, targetSn, newApiKey, oldApiKey, status, attempts, maxAttempts, 
                     rotationType, targetMastersJson, initiationDate)
                    VALUES (:initiator, :target, :newKey, :oldKey, "pending", 0, 5, 
                            "slave_to_masters", :mastersJson, datetime("now"))
                ');
                $stmt->bindValue(':initiator', $host['hostSn'], SQLITE3_TEXT);
                $stmt->bindValue(':target', $host['hostSn'], SQLITE3_TEXT);
                $stmt->bindValue(':newKey', $newKey, SQLITE3_TEXT);
                $stmt->bindValue(':oldKey', $oldKey, SQLITE3_TEXT);
                $stmt->bindValue(':mastersJson', $mastersJson, SQLITE3_TEXT);
                $stmt->execute();
                
                $taskId = $db->lastInsertRowID();
                logMessage("Task {$taskId} created for " . count($masters) . " master(s)");
            } else {
                logMessage("No masters found to notify");
            }
        }
        
        // Сохраняем бэкап
        $backupFile = '/var/www/minib/logs/last_rotated_key_' . date('Y-m-d') . '.txt';
        file_put_contents($backupFile, 
            "Date: " . date('Y-m-d H:i:s') . "\n" .
            "Host: {$host['hostSn']}\n" .
            "Old Key: {$oldKey}\n" .
            "New Key: {$newKey}\n"
        );
        logMessage("Backup saved: {$backupFile}");
        
        logMessage("✓ SUCCESS! Key rotation completed");
        
    } catch (Exception $e) {
        logMessage("✗ ERROR: " . $e->getMessage());
        logMessage("=== Auto Key Rotation Failed ===");
        exit(1);
    }
    
    logMessage("=== Auto Key Rotation Finished ===");
}

main($argv);