<?php
/**
 * API de Deploy - MontaLoja
 * Compara e sincroniza arquivos entre staging e producao usando PHP puro
 * Inclui funcionalidade de rollback, limpeza de backups, recuperação e importação/exportação de arquivos
 */

set_error_handler(function($errno, $errstr, $errfile, $errline) {
    http_response_code(500);
    die(json_encode(array('success' => false, 'error' => "Error: {$errstr}")));
});

set_exception_handler(function($e) {
    http_response_code(500);
    die(json_encode(array('success' => false, 'error' => "Exception: " . $e->getMessage())));
});

ob_start();

define('STAGING_PATH', '/home/socialar/dev.duolead.com.br');
define('PRODUCTION_PATH', '/home/socialar/duolead.com.br');
define('BACKUP_PATH', '/home/socialar/duolead.com.br/backups');
define('ROLLBACK_PATH', '/home/socialar/duolead.com.br/backups/rollback');
define('FILE_VERSIONS_PATH', '/home/socialar/duolead.com.br/backups/versions');
define('DEPLOY_LOG', '/home/socialar/duolead.com.br/deploy/deploy_history.log');
define('CHANGESETS_FILE', BACKUP_PATH . '/changesets.json');

$excludeItems = array(
    'uploads',
    'backups',
    'deploy',
    'releases',
    'shared',
    'storage',
    '.zip',
    '.bak',
    'error_log',
    '.well-known',
    'cgi-bin'
);

// Arquivos específicos a excluir (caminho relativo exato)
$excludeFiles = array(
    'includes/config.php'
);

$isStaging = (strpos($_SERVER['HTTP_HOST'] ?? '', 'dev.') !== false);
$sessionName = $isStaging ? 'montaloja_staging_session' : 'montaloja_session';
session_name($sessionName);
if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

ob_end_clean();
header('Content-Type: application/json; charset=utf-8');
header('Cache-Control: no-cache, must-revalidate');

function jsonResponse($success, $data = null, $error = null) {
    $response = array('success' => $success);
    if ($data !== null) $response['data'] = $data;
    if ($error !== null) $response['error'] = $error;
    die(json_encode($response));
}

$isSuperAdmin = false;
if (isset($_SESSION['is_super_admin'])) {
    if ($_SESSION['is_super_admin'] === true) {
        $isSuperAdmin = true;
    }
}

if (!$isSuperAdmin) {
    http_response_code(403);
    jsonResponse(false, null, 'Acesso negado. Faca login no SuperAdmin.');
}

$json = json_decode(file_get_contents('php://input'), true) ?: array();
$action = $_GET['action'] ?? $json['action'] ?? '';

switch ($action) {
    case 'status':
        getDeployStatus();
        break;
    case 'deploy':
        executeDeploy();
        break;
    case 'rollback':
        executeRollback();
        break;
    case 'history':
        getDeployHistory();
        break;
    case 'clear_backup':
        clearBackup();
        break;
    // Endpoints para recuperação de arquivos
    case 'list_production_files':
        listProductionFiles();
        break;
    case 'get_file_content':
        getFileContent();
        break;
    case 'download_file':
        downloadFile();
        break;
    case 'save_file_version':
        saveFileVersion();
        break;
    case 'list_file_versions':
        listFileVersions();
        break;
    case 'restore_file_version':
        restoreFileVersion();
        break;
    // Novos endpoints para importar/exportar
    case 'upload_file':
        uploadFile();
        break;
    case 'export_file':
        exportFile();
        break;
    case 'list_staging_files':
        listStagingFiles();
        break;
    case 'get_staging_file_content':
        getStagingFileContent();
        break;
    case 'reverse_sync':
        executeReverseSync();
        break;
    // Endpoints de Changesets
    case 'list_changesets':
        listChangesets();
        break;
    case 'create_changeset':
        createChangeset();
        break;
    case 'update_changeset':
        updateChangeset();
        break;
    case 'delete_changeset':
        deleteChangeset();
        break;
    case 'deploy_changeset':
        deployChangeset();
        break;
    case 'rollback_changeset':
        rollbackChangeset();
        break;
    case 'reverse_sync_status':
        getReverseSyncStatus();
        break;
    // Aliases para compatibilidade com frontend
    case 'list_files':
        listFilesGeneric();
        break;
    case 'view_file':
        viewFileGeneric();
        break;
    case 'reverse_status':
        getReverseSyncStatus();
        break;
    case 'copy_file':
        copyFileGeneric();
        break;
    default:
        jsonResponse(false, null, 'Acao invalida');
}

function listFilesRecursive($dir, $base = '') {
    global $excludeItems;
    $files = array();

    if (!is_dir($dir)) return $files;

    $items = @scandir($dir);
    if (!$items) return $files;

    foreach ($items as $item) {
        if ($item === '.' or $item === '..') continue;

        $skip = false;
        foreach ($excludeItems as $exclude) {
            if (strpos($item, $exclude) !== false) {
                $skip = true;
                break;
            }
        }
        if ($skip) continue;

        $path = $dir . '/' . $item;
        $relativePath = $base ? $base . '/' . $item : $item;

        if (is_dir($path)) {
            $files = array_merge($files, listFilesRecursive($path, $relativePath));
        } else {
            // Verificar se arquivo específico deve ser excluído
            if (in_array($relativePath, $GLOBALS['excludeFiles'])) continue;
            $files[$relativePath] = array(
                'path' => $relativePath,
                'size' => filesize($path),
                'mtime' => filemtime($path),
                'hash' => md5_file($path)
            );
        }
    }

    return $files;
}

function getDeployStatus() {
    $stagingFiles = listFilesRecursive(STAGING_PATH);
    $productionFiles = listFilesRecursive(PRODUCTION_PATH);

    $changes = array();

    foreach ($stagingFiles as $path => $info) {
        if (!isset($productionFiles[$path])) {
            $changes[] = array('file' => $path, 'status' => 'new');
        } elseif ($info['hash'] !== $productionFiles[$path]['hash']) {
            $changes[] = array('file' => $path, 'status' => 'modified');
        }
    }

    foreach ($productionFiles as $path => $info) {
        if (!isset($stagingFiles[$path])) {
            $changes[] = array('file' => $path, 'status' => 'deleted');
        }
    }

    $canRollback = is_dir(ROLLBACK_PATH) && file_exists(ROLLBACK_PATH . '/rollback_info.json');

    $backupSize = 0;
    $backupFiles = 0;
    if ($canRollback) {
        $backupInfo = getBackupInfo();
        $backupSize = $backupInfo['size'];
        $backupFiles = $backupInfo['files'];
    }

    jsonResponse(true, array(
        'total' => count($changes),
        'changes' => $changes,
        'backup_exists' => $canRollback,
        'backup_size' => $backupSize,
        'backup_files' => $backupFiles
    ));
}
function getBackupInfo() {
    $size = 0;
    $files = 0;

    if (!is_dir(ROLLBACK_PATH)) {
        return array('size' => 0, 'files' => 0);
    }

    $allFiles = listFilesRecursiveSimple(ROLLBACK_PATH);
    $files = count($allFiles);

    foreach ($allFiles as $file) {
        $fullPath = ROLLBACK_PATH . '/' . $file;
        if (file_exists($fullPath)) {
            $size += filesize($fullPath);
        }
    }

    return array('size' => $size, 'files' => $files);
}

function formatBytes($bytes) {
    if ($bytes >= 1073741824) {
        return number_format($bytes / 1073741824, 2) . ' GB';
    } elseif ($bytes >= 1048576) {
        return number_format($bytes / 1048576, 2) . ' MB';
    } elseif ($bytes >= 1024) {
        return number_format($bytes / 1024, 2) . ' KB';
    } else {
        return $bytes . ' bytes';
    }
}

function executeDeploy() {
    $timestamp = date('Ymd_His');
    $log = array();
    $log[] = "=== Deploy iniciado: " . date('Y-m-d H:i:s') . " ===";

    $stagingFiles = listFilesRecursive(STAGING_PATH);
    $productionFiles = listFilesRecursive(PRODUCTION_PATH);

    $toDeploy = array();
    $toBackup = array();
    $toDelete = array();

    // Arquivos novos ou modificados
    foreach ($stagingFiles as $path => $info) {
        if (!isset($productionFiles[$path])) {
            $toDeploy[] = $path;
        } elseif ($info['hash'] !== $productionFiles[$path]['hash']) {
            $toDeploy[] = $path;
            $toBackup[] = $path;
        }
    }

    // Arquivos removidos (existem em produção mas não em staging)
    foreach ($productionFiles as $path => $info) {
        if (!isset($stagingFiles[$path])) {
            $toDelete[] = $path;
            $toBackup[] = $path; // Backup antes de deletar
        }
    }

    if (count($toDeploy) === 0 && count($toDelete) === 0) {
        jsonResponse(true, array(
            'deploy_id' => "deploy_{$timestamp}",
            'files_synced' => 0,
            'files_deleted' => 0,
            'files_backed_up' => 0,
            'output' => 'Nenhuma alteracao para deploy.'
        ));
    }

    // Preparar diretório de rollback
    $rollbackDir = ROLLBACK_PATH;
    if (is_dir($rollbackDir)) {
        clearDirectory($rollbackDir);
    }
    if (!is_dir($rollbackDir)) {
        @mkdir($rollbackDir, 0755, true);
    }

    // Fazer backup dos arquivos que serão modificados ou deletados
    $backedUp = 0;
    foreach ($toBackup as $file) {
        $srcFile = PRODUCTION_PATH . '/' . $file;
        $destFile = $rollbackDir . '/' . $file;
        $destDir = dirname($destFile);

        if (!is_dir($destDir)) {
            @mkdir($destDir, 0755, true);
        }

        if (file_exists($srcFile)) {
            if (@copy($srcFile, $destFile)) {
                $backedUp++;
                $log[] = "Backup: {$file}";
            }
        }
    }

    // Salvar informações de rollback incluindo arquivos deletados
    $rollbackInfo = array(
        'timestamp' => $timestamp,
        'date' => date('Y-m-d H:i:s'),
        'files' => $toBackup,
        'deleted_files' => $toDelete,
        'user' => isset($_SESSION['super_admin_name']) ? $_SESSION['super_admin_name'] : 'Admin'
    );
    @file_put_contents($rollbackDir . '/rollback_info.json', json_encode($rollbackInfo, JSON_PRETTY_PRINT));

    // Copiar arquivos novos/modificados
    $synced = 0;
    $errors = array();

    foreach ($toDeploy as $file) {
        $srcFile = STAGING_PATH . '/' . $file;
        $destFile = PRODUCTION_PATH . '/' . $file;
        $destDir = dirname($destFile);

        if (!is_dir($destDir)) {
            @mkdir($destDir, 0755, true);
        }

        if (@copy($srcFile, $destFile)) {
            $synced++;
            $log[] = "Copiado: {$file}";
        } else {
            $errors[] = $file;
            $log[] = "ERRO ao copiar: {$file}";
        }
    }

    // REMOVER arquivos que foram deletados no staging
    $deleted = 0;
    foreach ($toDelete as $file) {
        $targetFile = PRODUCTION_PATH . '/' . $file;
        
        if (file_exists($targetFile)) {
            if (@unlink($targetFile)) {
                $deleted++;
                $log[] = "Removido: {$file}";
                
                // Remover diretório pai se ficou vazio
                $parentDir = dirname($targetFile);
                while ($parentDir !== PRODUCTION_PATH && is_dir($parentDir)) {
                    $contents = @scandir($parentDir);
                    $isEmpty = ($contents && count($contents) <= 2); // apenas . e ..
                    if ($isEmpty) {
                        @rmdir($parentDir);
                        $log[] = "Removido diretorio vazio: " . str_replace(PRODUCTION_PATH . '/', '', $parentDir);
                        $parentDir = dirname($parentDir);
                    } else {
                        break;
                    }
                }
            } else {
                $errors[] = "delete:{$file}";
                $log[] = "ERRO ao remover: {$file}";
            }
        }
    }

    $log[] = "=== Deploy concluido ===";
    $log[] = "Arquivos sincronizados: {$synced}";
    $log[] = "Arquivos removidos: {$deleted}";
    $log[] = "Arquivos em backup: {$backedUp}";

    // Salvar histórico
    $historyFile = dirname(DEPLOY_LOG) . '/deploy_history.json';
    $history = array();
    if (file_exists($historyFile)) {
        $content = @file_get_contents($historyFile);
        if ($content) {
            $decoded = json_decode($content, true);
            if (is_array($decoded)) $history = $decoded;
        }
    }

    array_unshift($history, array(
        'id' => "deploy_{$timestamp}",
        'timestamp' => date('Y-m-d H:i:s'),
        'user' => isset($_SESSION['super_admin_name']) ? $_SESSION['super_admin_name'] : 'Admin',
        'files_synced' => $synced,
        'files_deleted' => $deleted,
        'files_backed_up' => $backedUp,
        'status' => count($errors) > 0 ? 'partial' : 'success',
        'type' => 'deploy'
    ));

    @file_put_contents($historyFile, json_encode(array_slice($history, 0, 50), JSON_PRETTY_PRINT));
    @file_put_contents(DEPLOY_LOG, implode("\n", $log) . "\n\n", FILE_APPEND);

    jsonResponse(true, array(
        'deploy_id' => "deploy_{$timestamp}",
        'files_synced' => $synced,
        'files_deleted' => $deleted,
        'files_backed_up' => $backedUp,
        'errors' => $errors,
        'output' => implode("\n", $log)
    ));
}

function executeRollback() {
    $rollbackDir = ROLLBACK_PATH;
    $infoFile = $rollbackDir . '/rollback_info.json';

    if (!is_dir($rollbackDir) or !file_exists($infoFile)) {
        jsonResponse(false, null, 'Nenhum backup disponivel para rollback');
    }

    $info = json_decode(file_get_contents($infoFile), true);
    if (!$info or !isset($info['files'])) {
        jsonResponse(false, null, 'Arquivo de info do rollback invalido');
    }

    $timestamp = date('Ymd_His');
    $log = array();
    $log[] = "=== Rollback iniciado: " . date('Y-m-d H:i:s') . " ===";
    $log[] = "Restaurando backup de: " . $info['date'];

    $restoredFiles = 0;
    $errors = array();

    foreach ($info['files'] as $file) {
        $srcFile = $rollbackDir . '/' . $file;
        $destFile = PRODUCTION_PATH . '/' . $file;

        if (file_exists($srcFile)) {
            $destDir = dirname($destFile);
            if (!is_dir($destDir)) {
                @mkdir($destDir, 0755, true);
            }

            if (@copy($srcFile, $destFile)) {
                $restoredFiles++;
                $log[] = "Restaurado: {$file}";
            } else {
                $errors[] = $file;
                $log[] = "ERRO ao restaurar: {$file}";
            }
        }
    }

    $log[] = "=== Rollback concluido ===";
    $log[] = "Arquivos restaurados: {$restoredFiles}";

    $historyFile = dirname(DEPLOY_LOG) . '/deploy_history.json';
    $history = array();
    if (file_exists($historyFile)) {
        $content = @file_get_contents($historyFile);
        if ($content) {
            $decoded = json_decode($content, true);
            if (is_array($decoded)) $history = $decoded;
        }
    }

    array_unshift($history, array(
        'id' => "rollback_{$timestamp}",
        'timestamp' => date('Y-m-d H:i:s'),
        'user' => isset($_SESSION['super_admin_name']) ? $_SESSION['super_admin_name'] : 'Admin',
        'files_synced' => $restoredFiles,
        'status' => count($errors) > 0 ? 'partial' : 'success',
        'type' => 'rollback'
    ));

    @file_put_contents($historyFile, json_encode(array_slice($history, 0, 50), JSON_PRETTY_PRINT));
    @file_put_contents(DEPLOY_LOG, implode("\n", $log) . "\n\n", FILE_APPEND);

    clearDirectory($rollbackDir);

    jsonResponse(true, array(
        'rollback_id' => "rollback_{$timestamp}",
        'files_restored' => $restoredFiles,
        'errors' => $errors,
        'output' => implode("\n", $log)
    ));
}

function clearBackup() {
    $rollbackDir = ROLLBACK_PATH;

    if (!is_dir($rollbackDir)) {
        jsonResponse(true, array(
            'message' => 'Nenhum backup para limpar',
            'files_removed' => 0,
            'space_freed' => '0 bytes'
        ));
    }

    $backupInfo = getBackupInfo();
    $filesCount = $backupInfo['files'];
    $sizeFreed = $backupInfo['size'];

    clearDirectory($rollbackDir);

    $historyFile = dirname(DEPLOY_LOG) . '/deploy_history.json';
    $history = array();
    if (file_exists($historyFile)) {
        $content = @file_get_contents($historyFile);
        if ($content) {
            $decoded = json_decode($content, true);
            if (is_array($decoded)) $history = $decoded;
        }
    }

    $timestamp = date('Ymd_His');
    array_unshift($history, array(
        'id' => "cleanup_{$timestamp}",
        'timestamp' => date('Y-m-d H:i:s'),
        'user' => isset($_SESSION['super_admin_name']) ? $_SESSION['super_admin_name'] : 'Admin',
        'files_synced' => $filesCount,
        'status' => 'success',
        'type' => 'cleanup'
    ));

    @file_put_contents($historyFile, json_encode(array_slice($history, 0, 50), JSON_PRETTY_PRINT));

    jsonResponse(true, array(
        'message' => 'Backup limpo com sucesso',
        'files_removed' => $filesCount,
        'space_freed' => formatBytes($sizeFreed)
    ));
}

function listFilesRecursiveSimple($dir, $base = '') {
    $files = array();

    if (!is_dir($dir)) return $files;

    $items = @scandir($dir);
    if (!$items) return $files;

    foreach ($items as $item) {
        if ($item === '.' or $item === '..') continue;

        $path = $dir . '/' . $item;
        $relativePath = $base ? $base . '/' . $item : $item;

        if (is_dir($path)) {
            $files = array_merge($files, listFilesRecursiveSimple($path, $relativePath));
        } else {
            $files[] = $relativePath;
        }
    }

    return $files;
}

function clearDirectory($dir) {
    if (!is_dir($dir)) return;

    $items = @scandir($dir);
    if (!$items) return;

    foreach ($items as $item) {
        if ($item === '.' or $item === '..') continue;

        $path = $dir . '/' . $item;

        if (is_dir($path)) {
            clearDirectory($path);
            @rmdir($path);
        } else {
            @unlink($path);
        }
    }
}

function getDeployHistory() {
    $historyFile = dirname(DEPLOY_LOG) . '/deploy_history.json';
    $deploys = array();
    if (file_exists($historyFile)) {
        $content = @file_get_contents($historyFile);
        if ($content) {
            $decoded = json_decode($content, true);
            if (is_array($decoded)) $deploys = $decoded;
        }
    }

    $canRollback = is_dir(ROLLBACK_PATH) and file_exists(ROLLBACK_PATH . '/rollback_info.json');

    $backupInfo = getBackupInfo();

    jsonResponse(true, array(
        'deploys' => $deploys,
        'can_rollback' => $canRollback,
        'backup_size' => formatBytes($backupInfo['size']),
        'backup_files' => $backupInfo['files']
    ));
}

// ====================================================
// FUNÇÕES PARA RECUPERAÇÃO DE ARQUIVOS
// ====================================================

function listProductionFiles() {
    $search = isset($_GET['search']) ? trim($_GET['search']) : '';
    $folder = isset($_GET['folder']) ? trim($_GET['folder']) : '';

    $basePath = PRODUCTION_PATH;
    if ($folder) {
        $basePath = PRODUCTION_PATH . '/' . ltrim($folder, '/');
    }

    $folders = array();
    $files = array();

    if (is_dir($basePath)) {
        $items = @scandir($basePath);
        if ($items) {
            global $excludeItems;
            foreach ($items as $item) {
                if ($item === '.' or $item === '..') continue;

                $skip = false;
                foreach ($excludeItems as $exclude) {
                    if (strpos($item, $exclude) !== false) {
                        $skip = true;
                        break;
                    }
                }
                if ($skip) continue;

                $fullPath = $basePath . '/' . $item;
                $relativePath = $folder ? $folder . '/' . $item : $item;

                if (is_dir($fullPath)) {
                    $folders[] = array(
                        'name' => $item,
                        'path' => $relativePath,
                        'type' => 'folder'
                    );
                } else {
                    if ($search && stripos($item, $search) === false) {
                        continue;
                    }

                    $ext = strtolower(pathinfo($item, PATHINFO_EXTENSION));
                    $files[] = array(
                        'name' => $item,
                        'path' => $relativePath,
                        'type' => 'file',
                        'extension' => $ext,
                        'size' => filesize($fullPath),
                        'size_formatted' => formatBytes(filesize($fullPath)),
                        'modified' => date('Y-m-d H:i:s', filemtime($fullPath)),
                        'is_code' => in_array($ext, array('php', 'js', 'css', 'html', 'json', 'xml', 'sql', 'txt', 'md', 'htaccess'))
                    );
                }
            }
        }
    }

    usort($folders, function($a, $b) { return strcasecmp($a['name'], $b['name']); });
    usort($files, function($a, $b) { return strcasecmp($a['name'], $b['name']); });

    $breadcrumb = array();
    if ($folder) {
        $parts = explode('/', $folder);
        $currentPath = '';
        foreach ($parts as $part) {
            $currentPath .= ($currentPath ? '/' : '') . $part;
            $breadcrumb[] = array('name' => $part, 'path' => $currentPath);
        }
    }

    jsonResponse(true, array(
        'current_folder' => $folder,
        'breadcrumb' => $breadcrumb,
        'folders' => $folders,
        'files' => $files,
        'total_folders' => count($folders),
        'total_files' => count($files)
    ));
}

function getFileContent() {
    $filePath = isset($_GET['file']) ? trim($_GET['file']) : '';

    if (!$filePath) {
        jsonResponse(false, null, 'Caminho do arquivo nao especificado');
    }

    $filePath = str_replace('..', '', $filePath);
    $fullPath = PRODUCTION_PATH . '/' . ltrim($filePath, '/');

    if (!file_exists($fullPath)) {
        jsonResponse(false, null, 'Arquivo nao encontrado');
    }

    if (is_dir($fullPath)) {
        jsonResponse(false, null, 'O caminho especificado e um diretorio');
    }

    $ext = strtolower(pathinfo($fullPath, PATHINFO_EXTENSION));
    $allowedExtensions = array('php', 'js', 'css', 'html', 'htm', 'json', 'xml', 'sql', 'txt', 'md', 'htaccess', 'ini', 'yaml', 'yml', 'env');

    if (!in_array($ext, $allowedExtensions) && $ext !== '') {
        jsonResponse(false, null, 'Tipo de arquivo nao permitido para visualizacao');
    }

    $content = @file_get_contents($fullPath);
    if ($content === false) {
        jsonResponse(false, null, 'Erro ao ler o arquivo');
    }

    $versions = getFileVersionsList($filePath);

    jsonResponse(true, array(
        'file' => $filePath,
        'name' => basename($fullPath),
        'extension' => $ext,
        'size' => filesize($fullPath),
        'size_formatted' => formatBytes(filesize($fullPath)),
        'modified' => date('Y-m-d H:i:s', filemtime($fullPath)),
        'content' => $content,
        'versions' => $versions
    ));
}

function downloadFile() {
    $filePath = isset($_GET['file']) ? trim($_GET['file']) : '';

    if (!$filePath) {
        jsonResponse(false, null, 'Caminho do arquivo nao especificado');
    }

    $filePath = str_replace('..', '', $filePath);
    $fullPath = PRODUCTION_PATH . '/' . ltrim($filePath, '/');

    if (!file_exists($fullPath) || is_dir($fullPath)) {
        jsonResponse(false, null, 'Arquivo nao encontrado');
    }

    ob_end_clean();

    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="' . basename($fullPath) . '"');
    header('Content-Length: ' . filesize($fullPath));
    header('Cache-Control: no-cache, must-revalidate');

    readfile($fullPath);
    exit;
}

function saveFileVersion() {
    $filePath = isset($_GET['file']) ? trim($_GET['file']) : '';
    $note = isset($_GET['note']) ? trim($_GET['note']) : '';

    if (!$filePath) {
        jsonResponse(false, null, 'Caminho do arquivo nao especificado');
    }

    $filePath = str_replace('..', '', $filePath);
    $fullPath = PRODUCTION_PATH . '/' . ltrim($filePath, '/');

    if (!file_exists($fullPath) || is_dir($fullPath)) {
        jsonResponse(false, null, 'Arquivo nao encontrado');
    }

    if (!is_dir(FILE_VERSIONS_PATH)) {
        @mkdir(FILE_VERSIONS_PATH, 0755, true);
    }

    $fileDir = dirname($filePath);
    $fileName = basename($filePath);
    $versionDir = FILE_VERSIONS_PATH . '/' . ($fileDir ? $fileDir . '/' : '') . $fileName . '_versions';

    if (!is_dir($versionDir)) {
        @mkdir($versionDir, 0755, true);
    }

    $timestamp = date('Ymd_His');
    $versionFileName = pathinfo($fileName, PATHINFO_FILENAME) . '_' . $timestamp . '.' . pathinfo($fileName, PATHINFO_EXTENSION);
    $versionPath = $versionDir . '/' . $versionFileName;

    if (!@copy($fullPath, $versionPath)) {
        jsonResponse(false, null, 'Erro ao salvar versao do arquivo');
    }

    $metaFile = $versionDir . '/versions_meta.json';
    $meta = array();
    if (file_exists($metaFile)) {
        $meta = json_decode(file_get_contents($metaFile), true) ?: array();
    }

    array_unshift($meta, array(
        'version_file' => $versionFileName,
        'original_file' => $filePath,
        'timestamp' => $timestamp,
        'date' => date('Y-m-d H:i:s'),
        'size' => filesize($fullPath),
        'user' => isset($_SESSION['super_admin_name']) ? $_SESSION['super_admin_name'] : 'Admin',
        'note' => $note
    ));

    $meta = array_slice($meta, 0, 20);
    @file_put_contents($metaFile, json_encode($meta, JSON_PRETTY_PRINT));

    jsonResponse(true, array(
        'message' => 'Versao salva com sucesso',
        'version_file' => $versionFileName,
        'date' => date('Y-m-d H:i:s')
    ));
}

function listFileVersions() {
    $filePath = isset($_GET['file']) ? trim($_GET['file']) : '';

    if (!$filePath) {
        jsonResponse(false, null, 'Caminho do arquivo nao especificado');
    }

    $versions = getFileVersionsList($filePath);

    jsonResponse(true, array(
        'file' => $filePath,
        'versions' => $versions
    ));
}

function getFileVersionsList($filePath) {
    $fileDir = dirname($filePath);
    $fileName = basename($filePath);
    $versionDir = FILE_VERSIONS_PATH . '/' . ($fileDir && $fileDir !== '.' ? $fileDir . '/' : '') . $fileName . '_versions';
    $metaFile = $versionDir . '/versions_meta.json';

    if (!file_exists($metaFile)) {
        return array();
    }

    $meta = json_decode(file_get_contents($metaFile), true) ?: array();

    foreach ($meta as $key => $version) {
        $versionPath = $versionDir . '/' . $version['version_file'];
        $meta[$key]['exists'] = file_exists($versionPath);
        $meta[$key]['size_formatted'] = formatBytes($version['size']);
    }

    return $meta;
}

function restoreFileVersion() {
    $filePath = isset($_GET['file']) ? trim($_GET['file']) : '';
    $versionFile = isset($_GET['version']) ? trim($_GET['version']) : '';

    if (!$filePath || !$versionFile) {
        jsonResponse(false, null, 'Parametros invalidos');
    }

    $filePath = str_replace('..', '', $filePath);
    $versionFile = str_replace('..', '', $versionFile);

    $fileDir = dirname($filePath);
    $fileName = basename($filePath);
    $versionDir = FILE_VERSIONS_PATH . '/' . ($fileDir && $fileDir !== '.' ? $fileDir . '/' : '') . $fileName . '_versions';
    $versionPath = $versionDir . '/' . $versionFile;

    if (!file_exists($versionPath)) {
        jsonResponse(false, null, 'Versao nao encontrada');
    }

    $targetPath = PRODUCTION_PATH . '/' . ltrim($filePath, '/');

    $timestamp = date('Ymd_His');
    $backupName = pathinfo($fileName, PATHINFO_FILENAME) . '_pre_restore_' . $timestamp . '.' . pathinfo($fileName, PATHINFO_EXTENSION);
    @copy($targetPath, $versionDir . '/' . $backupName);

    if (!@copy($versionPath, $targetPath)) {
        jsonResponse(false, null, 'Erro ao restaurar arquivo');
    }

    jsonResponse(true, array(
        'message' => 'Arquivo restaurado com sucesso',
        'restored_from' => $versionFile,
        'backup_created' => $backupName
    ));
}

// ====================================================
// NOVAS FUNÇÕES PARA IMPORTAR/EXPORTAR ARQUIVOS
// ====================================================

/**
 * Lista arquivos do STAGING (dev.duolead.com.br) para importação/exportação
 */
function listStagingFiles() {
    $search = isset($_GET['search']) ? trim($_GET['search']) : '';
    $folder = isset($_GET['folder']) ? trim($_GET['folder']) : '';

    $basePath = STAGING_PATH;
    if ($folder) {
        $basePath = STAGING_PATH . '/' . ltrim($folder, '/');
    }

    $folders = array();
    $files = array();

    if (is_dir($basePath)) {
        $items = @scandir($basePath);
        if ($items) {
            global $excludeItems;
            foreach ($items as $item) {
                if ($item === '.' or $item === '..') continue;

                $skip = false;
                foreach ($excludeItems as $exclude) {
                    if (strpos($item, $exclude) !== false) {
                        $skip = true;
                        break;
                    }
                }
                if ($skip) continue;

                $fullPath = $basePath . '/' . $item;
                $relativePath = $folder ? $folder . '/' . $item : $item;

                if (is_dir($fullPath)) {
                    $folders[] = array(
                        'name' => $item,
                        'path' => $relativePath,
                        'type' => 'folder'
                    );
                } else {
                    if ($search && stripos($item, $search) === false) {
                        continue;
                    }

                    $ext = strtolower(pathinfo($item, PATHINFO_EXTENSION));
                    
                    // Verificar se existe em produção e se é diferente
                    $prodPath = PRODUCTION_PATH . '/' . $relativePath;
                    $existsInProd = file_exists($prodPath);
                    $isDifferent = false;
                    if ($existsInProd) {
                        $isDifferent = md5_file($fullPath) !== md5_file($prodPath);
                    }
                    
                    $files[] = array(
                        'name' => $item,
                        'path' => $relativePath,
                        'type' => 'file',
                        'extension' => $ext,
                        'size' => filesize($fullPath),
                        'size_formatted' => formatBytes(filesize($fullPath)),
                        'modified' => date('Y-m-d H:i:s', filemtime($fullPath)),
                        'is_code' => in_array($ext, array('php', 'js', 'css', 'html', 'json', 'xml', 'sql', 'txt', 'md', 'htaccess')),
                        'exists_in_production' => $existsInProd,
                        'is_different' => $isDifferent
                    );
                }
            }
        }
    }

    usort($folders, function($a, $b) { return strcasecmp($a['name'], $b['name']); });
    usort($files, function($a, $b) { return strcasecmp($a['name'], $b['name']); });

    $breadcrumb = array();
    if ($folder) {
        $parts = explode('/', $folder);
        $currentPath = '';
        foreach ($parts as $part) {
            $currentPath .= ($currentPath ? '/' : '') . $part;
            $breadcrumb[] = array('name' => $part, 'path' => $currentPath);
        }
    }

    jsonResponse(true, array(
        'current_folder' => $folder,
        'breadcrumb' => $breadcrumb,
        'folders' => $folders,
        'files' => $files,
        'total_folders' => count($folders),
        'total_files' => count($files)
    ));
}

/**
 * Obtém conteúdo de arquivo do STAGING
 */
function getStagingFileContent() {
    $filePath = isset($_GET['file']) ? trim($_GET['file']) : '';

    if (!$filePath) {
        jsonResponse(false, null, 'Caminho do arquivo nao especificado');
    }

    $filePath = str_replace('..', '', $filePath);
    $fullPath = STAGING_PATH . '/' . ltrim($filePath, '/');

    if (!file_exists($fullPath)) {
        jsonResponse(false, null, 'Arquivo nao encontrado');
    }

    if (is_dir($fullPath)) {
        jsonResponse(false, null, 'O caminho especificado e um diretorio');
    }

    $ext = strtolower(pathinfo($fullPath, PATHINFO_EXTENSION));
    $allowedExtensions = array('php', 'js', 'css', 'html', 'htm', 'json', 'xml', 'sql', 'txt', 'md', 'htaccess', 'ini', 'yaml', 'yml', 'env');

    if (!in_array($ext, $allowedExtensions) && $ext !== '') {
        jsonResponse(false, null, 'Tipo de arquivo nao permitido para visualizacao');
    }

    $content = @file_get_contents($fullPath);
    if ($content === false) {
        jsonResponse(false, null, 'Erro ao ler o arquivo');
    }

    // Verificar se existe em produção
    $prodPath = PRODUCTION_PATH . '/' . ltrim($filePath, '/');
    $existsInProd = file_exists($prodPath);
    $prodContent = null;
    if ($existsInProd) {
        $prodContent = @file_get_contents($prodPath);
    }

    jsonResponse(true, array(
        'file' => $filePath,
        'name' => basename($fullPath),
        'extension' => $ext,
        'size' => filesize($fullPath),
        'size_formatted' => formatBytes(filesize($fullPath)),
        'modified' => date('Y-m-d H:i:s', filemtime($fullPath)),
        'content' => $content,
        'exists_in_production' => $existsInProd,
        'production_content' => $prodContent
    ));
}

/**
 * Upload de arquivo para o servidor (importar)
 * Recebe arquivo via POST e salva no caminho especificado
 */
function uploadFile() {
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        jsonResponse(false, null, 'Metodo nao permitido');
    }

    $targetPath = isset($_POST['target_path']) ? trim($_POST['target_path']) : '';
    $environment = isset($_POST['environment']) ? trim($_POST['environment']) : 'staging';

    if (empty($targetPath)) {
        jsonResponse(false, null, 'Caminho de destino nao especificado');
    }

    if (!isset($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
        $errorMessages = array(
            UPLOAD_ERR_INI_SIZE => 'Arquivo muito grande (limite do PHP)',
            UPLOAD_ERR_FORM_SIZE => 'Arquivo muito grande (limite do formulario)',
            UPLOAD_ERR_PARTIAL => 'Upload incompleto',
            UPLOAD_ERR_NO_FILE => 'Nenhum arquivo enviado',
            UPLOAD_ERR_NO_TMP_DIR => 'Pasta temporaria nao encontrada',
            UPLOAD_ERR_CANT_WRITE => 'Falha ao escrever arquivo',
            UPLOAD_ERR_EXTENSION => 'Upload bloqueado por extensao'
        );
        $error = isset($_FILES['file']['error']) ? $errorMessages[$_FILES['file']['error']] : 'Erro desconhecido';
        jsonResponse(false, null, 'Erro no upload: ' . $error);
    }

    // Sanitizar caminho
    $targetPath = str_replace('..', '', $targetPath);
    $targetPath = ltrim($targetPath, '/');

    // Determinar diretório base
    $basePath = ($environment === 'production') ? PRODUCTION_PATH : STAGING_PATH;
    $fullTargetPath = $basePath . '/' . $targetPath;

    // Criar diretório se não existir
    $targetDir = dirname($fullTargetPath);
    if (!is_dir($targetDir)) {
        if (!@mkdir($targetDir, 0755, true)) {
            jsonResponse(false, null, 'Erro ao criar diretorio de destino');
        }
    }

    // Fazer backup se arquivo já existir
    $backupCreated = false;
    if (file_exists($fullTargetPath)) {
        $timestamp = date('Ymd_His');
        $fileName = basename($fullTargetPath);
        $fileDir = dirname($targetPath);
        $versionDir = FILE_VERSIONS_PATH . '/' . ($fileDir ? $fileDir . '/' : '') . $fileName . '_versions';
        
        if (!is_dir($versionDir)) {
            @mkdir($versionDir, 0755, true);
        }
        
        $backupName = pathinfo($fileName, PATHINFO_FILENAME) . '_pre_import_' . $timestamp . '.' . pathinfo($fileName, PATHINFO_EXTENSION);
        if (@copy($fullTargetPath, $versionDir . '/' . $backupName)) {
            $backupCreated = true;
            
            // Atualizar meta
            $metaFile = $versionDir . '/versions_meta.json';
            $meta = array();
            if (file_exists($metaFile)) {
                $meta = json_decode(file_get_contents($metaFile), true) ?: array();
            }
            array_unshift($meta, array(
                'version_file' => $backupName,
                'original_file' => $targetPath,
                'timestamp' => $timestamp,
                'date' => date('Y-m-d H:i:s'),
                'size' => filesize($fullTargetPath),
                'user' => isset($_SESSION['super_admin_name']) ? $_SESSION['super_admin_name'] : 'Admin',
                'note' => 'Backup antes de importacao'
            ));
            $meta = array_slice($meta, 0, 20);
            @file_put_contents($metaFile, json_encode($meta, JSON_PRETTY_PRINT));
        }
    }

    // Mover arquivo uploadado
    if (!move_uploaded_file($_FILES['file']['tmp_name'], $fullTargetPath)) {
        jsonResponse(false, null, 'Erro ao salvar arquivo');
    }

    // Registrar no histórico
    $historyFile = dirname(DEPLOY_LOG) . '/deploy_history.json';
    $history = array();
    if (file_exists($historyFile)) {
        $content = @file_get_contents($historyFile);
        if ($content) {
            $decoded = json_decode($content, true);
            if (is_array($decoded)) $history = $decoded;
        }
    }

    $timestamp = date('Ymd_His');
    array_unshift($history, array(
        'id' => "import_{$timestamp}",
        'timestamp' => date('Y-m-d H:i:s'),
        'user' => isset($_SESSION['super_admin_name']) ? $_SESSION['super_admin_name'] : 'Admin',
        'files_synced' => 1,
        'status' => 'success',
        'type' => 'import',
        'details' => "Importado: {$targetPath} para {$environment}"
    ));

    @file_put_contents($historyFile, json_encode(array_slice($history, 0, 50), JSON_PRETTY_PRINT));

    jsonResponse(true, array(
        'message' => 'Arquivo importado com sucesso',
        'file' => $targetPath,
        'environment' => $environment,
        'size' => filesize($fullTargetPath),
        'size_formatted' => formatBytes(filesize($fullTargetPath)),
        'backup_created' => $backupCreated
    ));
}

/**
 * Exporta arquivo de staging para produção ou vice-versa
 */
function exportFile() {
    $filePath = isset($_GET['file']) ? trim($_GET['file']) : '';
    $direction = isset($_GET['direction']) ? trim($_GET['direction']) : 'staging_to_production';

    if (!$filePath) {
        jsonResponse(false, null, 'Caminho do arquivo nao especificado');
    }

    $filePath = str_replace('..', '', $filePath);
    $filePath = ltrim($filePath, '/');

    if ($direction === 'staging_to_production') {
        $sourcePath = STAGING_PATH . '/' . $filePath;
        $destPath = PRODUCTION_PATH . '/' . $filePath;
        $sourceEnv = 'staging';
        $destEnv = 'production';
    } else {
        $sourcePath = PRODUCTION_PATH . '/' . $filePath;
        $destPath = STAGING_PATH . '/' . $filePath;
        $sourceEnv = 'production';
        $destEnv = 'staging';
    }

    if (!file_exists($sourcePath)) {
        jsonResponse(false, null, 'Arquivo de origem nao encontrado');
    }

    if (is_dir($sourcePath)) {
        jsonResponse(false, null, 'Nao e possivel exportar diretorios');
    }

    // Fazer backup se arquivo já existir no destino
    $backupCreated = false;
    if (file_exists($destPath)) {
        $timestamp = date('Ymd_His');
        $fileName = basename($destPath);
        $fileDir = dirname($filePath);
        $versionDir = FILE_VERSIONS_PATH . '/' . ($fileDir ? $fileDir . '/' : '') . $fileName . '_versions';
        
        if (!is_dir($versionDir)) {
            @mkdir($versionDir, 0755, true);
        }
        
        $backupName = pathinfo($fileName, PATHINFO_FILENAME) . '_pre_export_' . $timestamp . '.' . pathinfo($fileName, PATHINFO_EXTENSION);
        if (@copy($destPath, $versionDir . '/' . $backupName)) {
            $backupCreated = true;
            
            // Atualizar meta
            $metaFile = $versionDir . '/versions_meta.json';
            $meta = array();
            if (file_exists($metaFile)) {
                $meta = json_decode(file_get_contents($metaFile), true) ?: array();
            }
            array_unshift($meta, array(
                'version_file' => $backupName,
                'original_file' => $filePath,
                'timestamp' => $timestamp,
                'date' => date('Y-m-d H:i:s'),
                'size' => filesize($destPath),
                'user' => isset($_SESSION['super_admin_name']) ? $_SESSION['super_admin_name'] : 'Admin',
                'note' => "Backup antes de exportar de {$sourceEnv}"
            ));
            $meta = array_slice($meta, 0, 20);
            @file_put_contents($metaFile, json_encode($meta, JSON_PRETTY_PRINT));
        }
    }

    // Criar diretório de destino se não existir
    $destDir = dirname($destPath);
    if (!is_dir($destDir)) {
        if (!@mkdir($destDir, 0755, true)) {
            jsonResponse(false, null, 'Erro ao criar diretorio de destino');
        }
    }

    // Copiar arquivo
    if (!@copy($sourcePath, $destPath)) {
        jsonResponse(false, null, 'Erro ao exportar arquivo');
    }

    // Registrar no histórico
    $historyFile = dirname(DEPLOY_LOG) . '/deploy_history.json';
    $history = array();
    if (file_exists($historyFile)) {
        $content = @file_get_contents($historyFile);
        if ($content) {
            $decoded = json_decode($content, true);
            if (is_array($decoded)) $history = $decoded;
        }
    }

    $timestamp = date('Ymd_His');
    array_unshift($history, array(
        'id' => "export_{$timestamp}",
        'timestamp' => date('Y-m-d H:i:s'),
        'user' => isset($_SESSION['super_admin_name']) ? $_SESSION['super_admin_name'] : 'Admin',
        'files_synced' => 1,
        'status' => 'success',
        'type' => 'export',
        'details' => "Exportado: {$filePath} de {$sourceEnv} para {$destEnv}"
    ));

    @file_put_contents($historyFile, json_encode(array_slice($history, 0, 50), JSON_PRETTY_PRINT));

    jsonResponse(true, array(
        'message' => 'Arquivo exportado com sucesso',
        'file' => $filePath,
        'from' => $sourceEnv,
        'to' => $destEnv,
        'backup_created' => $backupCreated
    ));
}

/**
 * Obtém status de diferenças entre produção e staging (para sync reverso)
 */
function getReverseSyncStatus() {
    $productionFiles = listFilesRecursive(PRODUCTION_PATH);
    $stagingFiles = listFilesRecursive(STAGING_PATH);

    $modified = array();
    $added = array();
    $deleted = array();

    // Arquivos novos ou modificados em produção
    foreach ($productionFiles as $path => $info) {
        if (!isset($stagingFiles[$path])) {
            $added[] = $path . ' (novo em prod)';
        } elseif ($info['hash'] !== $stagingFiles[$path]['hash']) {
            $modified[] = $path . ' (modificado em prod)';
        }
    }

    // Arquivos que existem apenas no staging (seriam removidos)
    foreach ($stagingFiles as $path => $info) {
        if (!isset($productionFiles[$path])) {
            $deleted[] = $path . ' (apenas em staging)';
        }
    }

    $allChanges = array_merge($modified, $added, $deleted);

    jsonResponse(true, array(
        'total' => count($allChanges),
        'files' => $allChanges,
        'modified' => count($modified),
        'added' => count($added),
        'deleted' => count($deleted),
        'direction' => 'production_to_staging'
    ));
}

/**
 * Executa sync reverso: Produção → Staging
 * Copia arquivos de produção para staging para sincronizar os ambientes
 */
function executeReverseSync() {
    $timestamp = date('Ymd_His');
    $log = array();
    $log[] = "=== Reverse Sync iniciado: " . date('Y-m-d H:i:s') . " ===";

    // Verificar se foi passada uma lista específica de arquivos
    $input = json_decode(file_get_contents('php://input'), true);
    $selectedFiles = isset($input['files']) && is_array($input['files']) ? $input['files'] : null;
    $productionFiles = listFilesRecursive(PRODUCTION_PATH);
    $stagingFiles = listFilesRecursive(STAGING_PATH);

    $toSync = array();
    $toBackup = array();
    $toDelete = array();

    // Arquivos novos ou modificados em produção
    foreach ($productionFiles as $path => $info) {
        if ($selectedFiles !== null && !in_array($path, $selectedFiles)) continue;
        if (!isset($stagingFiles[$path])) {
            $toSync[] = $path;
        } elseif ($info['hash'] !== $stagingFiles[$path]['hash']) {
            $toSync[] = $path;
            $toBackup[] = $path;
        }
    }

    // Arquivos removidos em produção (existem em staging mas não em prod)
    foreach ($stagingFiles as $path => $info) {
        if ($selectedFiles !== null && !in_array($path, $selectedFiles)) continue;
        if (!isset($productionFiles[$path])) {
            $toDelete[] = $path;
            $toBackup[] = $path;
        }
    }

    if (count($toSync) === 0 && count($toDelete) === 0) {
        jsonResponse(true, array(
            'sync_id' => "reverse_sync_{$timestamp}",
            'files_synced' => 0,
            'files_deleted' => 0,
            'output' => 'Ambientes já estão sincronizados.'
        ));
    }

    // Preparar diretório de backup para staging
    $backupDir = BACKUP_PATH . '/staging_backup_' . $timestamp;
    if (!is_dir($backupDir)) {
        @mkdir($backupDir, 0755, true);
    }

    // Fazer backup dos arquivos do staging que serão sobrescritos
    $backedUp = 0;
    foreach ($toBackup as $file) {
        $srcFile = STAGING_PATH . '/' . $file;
        $destFile = $backupDir . '/' . $file;
        $destDir = dirname($destFile);

        if (!is_dir($destDir)) {
            @mkdir($destDir, 0755, true);
        }

        if (file_exists($srcFile)) {
            if (@copy($srcFile, $destFile)) {
                $backedUp++;
                $log[] = "Backup staging: {$file}";
            }
        }
    }

    // Copiar arquivos de produção para staging
    $synced = 0;
    $errors = array();

    foreach ($toSync as $file) {
        $srcFile = PRODUCTION_PATH . '/' . $file;
        $destFile = STAGING_PATH . '/' . $file;
        $destDir = dirname($destFile);

        if (!is_dir($destDir)) {
            @mkdir($destDir, 0755, true);
        }

        if (@copy($srcFile, $destFile)) {
            $synced++;
            $log[] = "Copiado para staging: {$file}";
        } else {
            $errors[] = $file;
            $log[] = "ERRO ao copiar: {$file}";
        }
    }

    // Remover arquivos do staging que não existem mais em produção
    $deleted = 0;
    foreach ($toDelete as $file) {
        $targetFile = STAGING_PATH . '/' . $file;

        if (file_exists($targetFile)) {
            if (@unlink($targetFile)) {
                $deleted++;
                $log[] = "Removido do staging: {$file}";

                // Remover diretório vazio
                $targetDir = dirname($targetFile);
                while ($targetDir !== STAGING_PATH && @rmdir($targetDir)) {
                    $targetDir = dirname($targetDir);
                }
            }
        }
    }

    // Registrar no histórico
    $historyFile = dirname(DEPLOY_LOG) . '/deploy_history.json';
    $history = array();
    if (file_exists($historyFile)) {
        $content = @file_get_contents($historyFile);
        if ($content) {
            $decoded = json_decode($content, true);
            if (is_array($decoded)) $history = $decoded;
        }
    }

    array_unshift($history, array(
        'id' => "reverse_sync_{$timestamp}",
        'timestamp' => date('Y-m-d H:i:s'),
        'user' => isset($_SESSION['super_admin_name']) ? $_SESSION['super_admin_name'] : 'Admin',
        'files_synced' => $synced,
        'files_deleted' => $deleted,
        'files_backed_up' => $backedUp,
        'status' => count($errors) > 0 ? 'partial' : 'success',
        'type' => 'reverse_sync',
        'details' => "Sincronizado: {$synced} arquivos de produção para staging"
    ));

    @file_put_contents($historyFile, json_encode(array_slice($history, 0, 50), JSON_PRETTY_PRINT));

    $log[] = "=== Reverse Sync finalizado: " . date('Y-m-d H:i:s') . " ===";
    $log[] = "Arquivos sincronizados: {$synced}";
    $log[] = "Arquivos removidos: {$deleted}";
    $log[] = "Backups criados: {$backedUp}";

    if (count($errors) > 0) {
        $log[] = "Erros: " . count($errors);
    }

    jsonResponse(true, array(
        'sync_id' => "reverse_sync_{$timestamp}",
        'files_synced' => $synced,
        'files_deleted' => $deleted,
        'files_backed_up' => $backedUp,
        'errors' => $errors,
        'output' => implode("\n", $log)
    ));
}

// ============================================================
// SISTEMA DE CHANGESETS (Grupos de Modificações)
// ============================================================


/**
 * Lista todos os changesets salvos
 */
function listChangesets() {
    $changesets = loadChangesets();
    jsonResponse(true, array(
        'changesets' => $changesets,
        'total' => count($changesets)
    ));
}

/**
 * Carrega changesets do arquivo JSON
 */
function loadChangesets() {
    if (!file_exists(CHANGESETS_FILE)) {
        return array();
    }
    $content = @file_get_contents(CHANGESETS_FILE);
    if (!$content) return array();
    $data = json_decode($content, true);
    return is_array($data) ? $data : array();
}

/**
 * Salva changesets no arquivo JSON
 */
function saveChangesets($changesets) {
    $dir = dirname(CHANGESETS_FILE);
    if (!is_dir($dir)) {
        @mkdir($dir, 0755, true);
    }
    return @file_put_contents(CHANGESETS_FILE, json_encode($changesets, JSON_PRETTY_PRINT));
}

/**
 * Cria um novo changeset (grupo de arquivos)
 */
function createChangeset() {
    $input = json_decode(file_get_contents('php://input'), true);
    
    $name = isset($input['name']) ? trim($input['name']) : '';
    $description = isset($input['description']) ? trim($input['description']) : '';
    $files = isset($input['files']) ? $input['files'] : array();
    
    if (empty($name)) {
        jsonResponse(false, null, 'Nome do changeset é obrigatório');
    }
    
    if (empty($files) || !is_array($files)) {
        jsonResponse(false, null, 'Selecione pelo menos um arquivo');
    }
    
    $changesets = loadChangesets();
    
    $id = 'cs_' . date('Ymd_His') . '_' . substr(md5(uniqid()), 0, 6);
    
    $changeset = array(
        'id' => $id,
        'name' => $name,
        'description' => $description,
        'files' => $files,
        'created_at' => date('Y-m-d H:i:s'),
        'created_by' => isset($_SESSION['super_admin_name']) ? $_SESSION['super_admin_name'] : 'Admin',
        'status' => 'pending',
        'deployed_at' => null
    );
    
    array_unshift($changesets, $changeset);
    saveChangesets($changesets);
    
    jsonResponse(true, array(
        'message' => 'Changeset criado com sucesso',
        'changeset' => $changeset
    ));
}

/**
 * Atualiza um changeset existente
 */
function updateChangeset() {
    $input = json_decode(file_get_contents('php://input'), true);
    
    $id = isset($input['id']) ? trim($input['id']) : '';
    $name = isset($input['name']) ? trim($input['name']) : '';
    $description = isset($input['description']) ? trim($input['description']) : '';
    $files = isset($input['files']) ? $input['files'] : null;
    
    if (empty($id)) {
        jsonResponse(false, null, 'ID do changeset é obrigatório');
    }
    
    $changesets = loadChangesets();
    $found = false;
    
    foreach ($changesets as &$cs) {
        if ($cs['id'] === $id) {
            if (!empty($name)) $cs['name'] = $name;
            if (!empty($description)) $cs['description'] = $description;
            if ($files !== null && is_array($files)) $cs['files'] = $files;
            $cs['updated_at'] = date('Y-m-d H:i:s');
            $found = true;
            break;
        }
    }
    
    if (!$found) {
        jsonResponse(false, null, 'Changeset não encontrado');
    }
    
    saveChangesets($changesets);
    jsonResponse(true, array('message' => 'Changeset atualizado'));
}

/**
 * Remove um changeset
 */
function deleteChangeset() {
    $id = isset($_GET['id']) ? trim($_GET['id']) : '';
    
    if (empty($id)) {
        jsonResponse(false, null, 'ID do changeset é obrigatório');
    }
    
    $changesets = loadChangesets();
    $newChangesets = array();
    $found = false;
    
    foreach ($changesets as $cs) {
        if ($cs['id'] === $id) {
            $found = true;
        } else {
            $newChangesets[] = $cs;
        }
    }
    
    if (!$found) {
        jsonResponse(false, null, 'Changeset não encontrado');
    }
    
    saveChangesets($newChangesets);
    jsonResponse(true, array('message' => 'Changeset removido'));
}

/**
 * Faz deploy de um changeset específico
 */
function deployChangeset() {
    $id = isset($_GET['id']) ? trim($_GET['id']) : '';
    
    if (empty($id)) {
        jsonResponse(false, null, 'ID do changeset é obrigatório');
    }
    
    $changesets = loadChangesets();
    $targetChangeset = null;
    
    foreach ($changesets as &$cs) {
        if ($cs['id'] === $id) {
            $targetChangeset = &$cs;
            break;
        }
    }
    
    if (!$targetChangeset) {
        jsonResponse(false, null, 'Changeset não encontrado');
    }
    
    $timestamp = date('Ymd_His');
    $log = array();
    $log[] = "=== Deploy Changeset [{$targetChangeset['name']}] iniciado: " . date('Y-m-d H:i:s') . " ===";
    
    $files = $targetChangeset['files'];
    $toBackup = array();
    
    // Verificar quais arquivos existem em produção para backup
    foreach ($files as $file) {
        $prodFile = PRODUCTION_PATH . '/' . $file;
        if (file_exists($prodFile)) {
            $toBackup[] = $file;
        }
    }
    
    // Preparar diretório de rollback específico do changeset
    $rollbackDir = ROLLBACK_PATH . '/changeset_' . $id . '_' . $timestamp;
    if (!is_dir($rollbackDir)) {
        @mkdir($rollbackDir, 0755, true);
    }
    
    // Fazer backup
    $backedUp = 0;
    foreach ($toBackup as $file) {
        $srcFile = PRODUCTION_PATH . '/' . $file;
        $destFile = $rollbackDir . '/' . $file;
        $destDir = dirname($destFile);
        
        if (!is_dir($destDir)) {
            @mkdir($destDir, 0755, true);
        }
        
        if (@copy($srcFile, $destFile)) {
            $backedUp++;
            $log[] = "Backup: {$file}";
        }
    }
    
    // Salvar info do rollback
    $rollbackInfo = array(
        'changeset_id' => $id,
        'changeset_name' => $targetChangeset['name'],
        'timestamp' => $timestamp,
        'date' => date('Y-m-d H:i:s'),
        'files' => $toBackup,
        'user' => isset($_SESSION['super_admin_name']) ? $_SESSION['super_admin_name'] : 'Admin'
    );
    @file_put_contents($rollbackDir . '/rollback_info.json', json_encode($rollbackInfo, JSON_PRETTY_PRINT));
    
    // Copiar arquivos de staging para produção
    $synced = 0;
    $errors = array();
    
    foreach ($files as $file) {
        $srcFile = STAGING_PATH . '/' . $file;
        $destFile = PRODUCTION_PATH . '/' . $file;
        
        if (!file_exists($srcFile)) {
            $errors[] = $file . ' (não existe em staging)';
            $log[] = "ERRO: {$file} não existe em staging";
            continue;
        }
        
        $destDir = dirname($destFile);
        if (!is_dir($destDir)) {
            @mkdir($destDir, 0755, true);
        }
        
        if (@copy($srcFile, $destFile)) {
            $synced++;
            $log[] = "Copiado: {$file}";
        } else {
            $errors[] = $file;
            $log[] = "ERRO ao copiar: {$file}";
        }
    }
    
    // Atualizar status do changeset
    $targetChangeset['status'] = count($errors) > 0 ? 'partial' : 'deployed';
    $targetChangeset['deployed_at'] = date('Y-m-d H:i:s');
    $targetChangeset['deployed_by'] = isset($_SESSION['super_admin_name']) ? $_SESSION['super_admin_name'] : 'Admin';
    $targetChangeset['rollback_dir'] = $rollbackDir;
    
    saveChangesets($changesets);
    
    // Registrar no histórico
    $historyFile = dirname(DEPLOY_LOG) . '/deploy_history.json';
    $history = array();
    if (file_exists($historyFile)) {
        $content = @file_get_contents($historyFile);
        if ($content) {
            $decoded = json_decode($content, true);
            if (is_array($decoded)) $history = $decoded;
        }
    }
    
    array_unshift($history, array(
        'id' => "changeset_{$id}_{$timestamp}",
        'timestamp' => date('Y-m-d H:i:s'),
        'user' => isset($_SESSION['super_admin_name']) ? $_SESSION['super_admin_name'] : 'Admin',
        'files_synced' => $synced,
        'files_backed_up' => $backedUp,
        'status' => count($errors) > 0 ? 'partial' : 'success',
        'type' => 'changeset_deploy',
        'changeset_id' => $id,
        'changeset_name' => $targetChangeset['name'],
        'details' => "Changeset [{$targetChangeset['name']}]: {$synced} arquivos sincronizados"
    ));
    
    @file_put_contents($historyFile, json_encode(array_slice($history, 0, 100), JSON_PRETTY_PRINT));
    
    $log[] = "=== Deploy Changeset finalizado: " . date('Y-m-d H:i:s') . " ===";
    $log[] = "Arquivos sincronizados: {$synced}";
    $log[] = "Backups criados: {$backedUp}";
    
    jsonResponse(true, array(
        'changeset_id' => $id,
        'files_synced' => $synced,
        'files_backed_up' => $backedUp,
        'errors' => $errors,
        'output' => implode("\n", $log)
    ));
}

/**
 * Faz rollback de um changeset específico
 */
function rollbackChangeset() {
    $id = isset($_GET['id']) ? trim($_GET['id']) : '';
    
    if (empty($id)) {
        jsonResponse(false, null, 'ID do changeset é obrigatório');
    }
    
    $changesets = loadChangesets();
    $targetChangeset = null;
    
    foreach ($changesets as &$cs) {
        if ($cs['id'] === $id) {
            $targetChangeset = &$cs;
            break;
        }
    }
    
    if (!$targetChangeset) {
        jsonResponse(false, null, 'Changeset não encontrado');
    }
    
    if (empty($targetChangeset['rollback_dir']) || !is_dir($targetChangeset['rollback_dir'])) {
        jsonResponse(false, null, 'Não há backup disponível para rollback');
    }
    
    $rollbackDir = $targetChangeset['rollback_dir'];
    $rollbackInfoFile = $rollbackDir . '/rollback_info.json';
    
    if (!file_exists($rollbackInfoFile)) {
        jsonResponse(false, null, 'Informações de rollback não encontradas');
    }
    
    $rollbackInfo = json_decode(file_get_contents($rollbackInfoFile), true);
    $files = $rollbackInfo['files'];
    
    $log = array();
    $log[] = "=== Rollback Changeset [{$targetChangeset['name']}] iniciado: " . date('Y-m-d H:i:s') . " ===";
    
    $restored = 0;
    $errors = array();
    
    foreach ($files as $file) {
        $srcFile = $rollbackDir . '/' . $file;
        $destFile = PRODUCTION_PATH . '/' . $file;
        
        if (file_exists($srcFile)) {
            if (@copy($srcFile, $destFile)) {
                $restored++;
                $log[] = "Restaurado: {$file}";
            } else {
                $errors[] = $file;
                $log[] = "ERRO ao restaurar: {$file}";
            }
        }
    }
    
    // Atualizar status
    $targetChangeset['status'] = 'rolled_back';
    $targetChangeset['rolled_back_at'] = date('Y-m-d H:i:s');
    saveChangesets($changesets);
    
    $log[] = "=== Rollback finalizado: " . date('Y-m-d H:i:s') . " ===";
    
    jsonResponse(true, array(
        'files_restored' => $restored,
        'errors' => $errors,
        'output' => implode("\n", $log)
    ));
}

// ============================================
// FUNÇÕES GENÉRICAS PARA COMPATIBILIDADE COM FRONTEND
// ============================================

function listFilesGeneric() {
    $path = isset($_GET['path']) ? trim($_GET['path']) : '';
    $json = json_decode(file_get_contents('php://input'), true) ?: array();
    if (empty($path) && isset($json['path'])) $path = $json['path'];
    
    $environment = isset($_GET['environment']) ? $_GET['environment'] : 
                   (isset($json['environment']) ? $json['environment'] : 'production');
    
    $basePath = ($environment === 'staging') ? STAGING_PATH : PRODUCTION_PATH;
    $fullPath = $basePath . ($path ? '/' . ltrim($path, '/') : '');
    
    $result = array();
    
    if (is_dir($fullPath)) {
        $items = @scandir($fullPath);
        if ($items) {
            global $excludeItems;
            foreach ($items as $item) {
                if ($item === '.' || $item === '..') continue;
                
                $skip = false;
                foreach ($excludeItems as $exclude) {
                    if (strpos($item, $exclude) !== false) {
                        $skip = true;
                        break;
                    }
                }
                if ($skip) continue;
                
                $itemPath = $fullPath . '/' . $item;
                $result[] = array(
                    'name' => $item,
                    'is_dir' => is_dir($itemPath),
                    'size' => is_file($itemPath) ? filesize($itemPath) : 0
                );
            }
        }
    }
    
    // Ordenar: pastas primeiro, depois arquivos
    usort($result, function($a, $b) {
        if ($a['is_dir'] && !$b['is_dir']) return -1;
        if (!$a['is_dir'] && $b['is_dir']) return 1;
        return strcasecmp($a['name'], $b['name']);
    });
    
    jsonResponse(true, $result);
}

function viewFileGeneric() {
    $path = isset($_GET['path']) ? trim($_GET['path']) : '';
    $json = json_decode(file_get_contents('php://input'), true) ?: array();
    if (empty($path) && isset($json['path'])) $path = $json['path'];
    
    $environment = isset($_GET['environment']) ? $_GET['environment'] : 
                   (isset($json['environment']) ? $json['environment'] : 'production');
    
    $basePath = ($environment === 'staging') ? STAGING_PATH : PRODUCTION_PATH;
    $fullPath = $basePath . '/' . ltrim($path, '/');
    
    if (!file_exists($fullPath) || is_dir($fullPath)) {
        jsonResponse(false, null, 'Arquivo não encontrado');
        return;
    }
    
    $content = @file_get_contents($fullPath);
    if ($content === false) {
        jsonResponse(false, null, 'Erro ao ler arquivo');
        return;
    }
    
    // Limitar tamanho do conteúdo para arquivos muito grandes
    $maxSize = 500000; // 500KB
    if (strlen($content) > $maxSize) {
        $content = substr($content, 0, $maxSize) . "\n\n... [ARQUIVO TRUNCADO - MUITO GRANDE] ...";
    }
    
    jsonResponse(true, array(
        'path' => $path,
        'content' => $content,
        'size' => formatBytes(filesize($fullPath)),
        'modified' => date('Y-m-d H:i:s', filemtime($fullPath))
    ));
}

function copyFileGeneric() {
    $path = isset($_GET['path']) ? trim($_GET['path']) : '';
    $json = json_decode(file_get_contents('php://input'), true) ?: array();
    if (empty($path) && isset($json['path'])) $path = $json['path'];
    
    $direction = isset($_GET['direction']) ? $_GET['direction'] : 
                 (isset($json['direction']) ? $json['direction'] : 'staging_to_production');
    
    if (empty($path)) {
        jsonResponse(false, null, 'Caminho do arquivo é obrigatório');
        return;
    }
    
    if ($direction === 'staging_to_production') {
        $srcPath = STAGING_PATH . '/' . ltrim($path, '/');
        $dstPath = PRODUCTION_PATH . '/' . ltrim($path, '/');
    } else {
        $srcPath = PRODUCTION_PATH . '/' . ltrim($path, '/');
        $dstPath = STAGING_PATH . '/' . ltrim($path, '/');
    }
    
    if (!file_exists($srcPath)) {
        jsonResponse(false, null, 'Arquivo de origem não encontrado');
        return;
    }
    
    // Criar diretório de destino se não existir
    $dstDir = dirname($dstPath);
    if (!is_dir($dstDir)) {
        if (!@mkdir($dstDir, 0755, true)) {
            jsonResponse(false, null, 'Erro ao criar diretório de destino');
            return;
        }
    }
    
    // Copiar arquivo
    if (@copy($srcPath, $dstPath)) {
        jsonResponse(true, array(
            'message' => 'Arquivo copiado com sucesso',
            'from' => $srcPath,
            'to' => $dstPath
        ));
    } else {
        jsonResponse(false, null, 'Erro ao copiar arquivo');
    }
}
