-- Add multipart upload tracking and decouple backup creation from upload
-- This allows resuming interrupted uploads of large backup files
-- and enables asynchronous upload processing

USE `whp`;

CREATE TABLE IF NOT EXISTS `multipart_uploads` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `backup_id` int(11) NOT NULL,
    `upload_id` varchar(255) NOT NULL,
    `bucket` varchar(255) NOT NULL,
    `key` varchar(500) NOT NULL,
    `file_path` varchar(500) NOT NULL,
    `file_size` bigint NOT NULL,
    `chunk_size` int NOT NULL,
    `total_parts` int NOT NULL,
    `completed_parts` text DEFAULT NULL COMMENT 'JSON array of completed part ETags',
    `status` enum('in_progress','completed','aborted','failed') DEFAULT 'in_progress',
    `started_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    `completed_at` timestamp NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    KEY `idx_backup_id` (`backup_id`),
    KEY `idx_upload_id` (`upload_id`),
    KEY `idx_status` (`status`),
    KEY `idx_started_at` (`started_at`),
    CONSTRAINT `fk_multipart_backup` FOREIGN KEY (`backup_id`) REFERENCES `backup_history` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Add index for finding stale uploads (conditional creation)
SET @sql = (SELECT IF(
    (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
     WHERE TABLE_SCHEMA = DATABASE()
     AND TABLE_NAME = 'multipart_uploads'
     AND INDEX_NAME = 'idx_stale_uploads') > 0,
    'SELECT "Index idx_stale_uploads already exists" AS message',
    'CREATE INDEX `idx_stale_uploads` ON `multipart_uploads` (`status`, `updated_at`)'
));
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

-- Add columns to backup_history for decoupled backup/upload process
-- Split into separate ALTER TABLE statements for MariaDB compatibility
ALTER TABLE `backup_history`
ADD COLUMN `upload_method` enum('single','multipart') DEFAULT 'single' AFTER `backup_size`,
ADD COLUMN `multipart_upload_id` varchar(255) DEFAULT NULL AFTER `upload_method`,
ADD COLUMN `local_path` varchar(500) DEFAULT NULL AFTER `backup_path`,
ADD COLUMN `local_size` bigint DEFAULT NULL AFTER `local_path`,
ADD COLUMN `creation_status` enum('pending','creating','created','failed') DEFAULT 'pending' AFTER `status`,
ADD COLUMN `upload_status` enum('pending','uploading','uploaded','failed','skipped') DEFAULT NULL AFTER `creation_status`,
ADD COLUMN `upload_started_at` timestamp NULL DEFAULT NULL AFTER `upload_status`,
ADD COLUMN `upload_completed_at` timestamp NULL DEFAULT NULL AFTER `upload_started_at`,
ADD COLUMN `upload_attempts` int DEFAULT 0 AFTER `upload_completed_at`,
ADD COLUMN `local_deleted_at` timestamp NULL DEFAULT NULL AFTER `upload_attempts`;

-- Add indexes for the new columns (conditional creation)
SET @sql_multipart = (SELECT IF(
    (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
     WHERE TABLE_SCHEMA = DATABASE()
     AND TABLE_NAME = 'backup_history'
     AND INDEX_NAME = 'idx_multipart_upload_id') > 0,
    'SELECT "Index idx_multipart_upload_id already exists" AS message',
    'ALTER TABLE `backup_history` ADD INDEX `idx_multipart_upload_id` (`multipart_upload_id`)'
));
PREPARE stmt FROM @sql_multipart;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

SET @sql_creation = (SELECT IF(
    (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
     WHERE TABLE_SCHEMA = DATABASE()
     AND TABLE_NAME = 'backup_history'
     AND INDEX_NAME = 'idx_creation_status') > 0,
    'SELECT "Index idx_creation_status already exists" AS message',
    'ALTER TABLE `backup_history` ADD INDEX `idx_creation_status` (`creation_status`)'
));
PREPARE stmt FROM @sql_creation;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

SET @sql_upload = (SELECT IF(
    (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
     WHERE TABLE_SCHEMA = DATABASE()
     AND TABLE_NAME = 'backup_history'
     AND INDEX_NAME = 'idx_upload_status') > 0,
    'SELECT "Index idx_upload_status already exists" AS message',
    'ALTER TABLE `backup_history` ADD INDEX `idx_upload_status` (`upload_status`)'
));
PREPARE stmt FROM @sql_upload;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

SET @sql_deleted = (SELECT IF(
    (SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
     WHERE TABLE_SCHEMA = DATABASE()
     AND TABLE_NAME = 'backup_history'
     AND INDEX_NAME = 'idx_local_deleted') > 0,
    'SELECT "Index idx_local_deleted already exists" AS message',
    'ALTER TABLE `backup_history` ADD INDEX `idx_local_deleted` (`local_deleted_at`)'
));
PREPARE stmt FROM @sql_deleted;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;

-- Add comments to columns (separate statements for compatibility)
ALTER TABLE `backup_history` MODIFY COLUMN `local_path` varchar(500) DEFAULT NULL COMMENT 'Path to local backup file';
ALTER TABLE `backup_history` MODIFY COLUMN `local_size` bigint DEFAULT NULL COMMENT 'Size of local backup file';
ALTER TABLE `backup_history` MODIFY COLUMN `creation_status` enum('pending','creating','created','failed') DEFAULT 'pending' COMMENT 'Status of local backup creation';
ALTER TABLE `backup_history` MODIFY COLUMN `upload_status` enum('pending','uploading','uploaded','failed','skipped') DEFAULT NULL COMMENT 'Status of remote upload';
ALTER TABLE `backup_history` MODIFY COLUMN `upload_attempts` int DEFAULT 0 COMMENT 'Number of upload attempts';
ALTER TABLE `backup_history` MODIFY COLUMN `local_deleted_at` timestamp NULL DEFAULT NULL COMMENT 'When local file was deleted';

-- Create table for upload queue management
CREATE TABLE IF NOT EXISTS `backup_upload_queue` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `backup_id` int(11) NOT NULL,
    `priority` int DEFAULT 5 COMMENT 'Upload priority (1=highest, 10=lowest)',
    `status` enum('queued','processing','completed','failed','cancelled') DEFAULT 'queued',
    `worker_id` varchar(100) DEFAULT NULL COMMENT 'ID of worker processing this upload',
    `started_at` timestamp NULL DEFAULT NULL,
    `completed_at` timestamp NULL DEFAULT NULL,
    `error_message` text DEFAULT NULL,
    `retry_count` int DEFAULT 0,
    `next_retry_at` timestamp NULL DEFAULT NULL,
    `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE KEY `uk_backup_id` (`backup_id`),
    KEY `idx_status_priority` (`status`, `priority`),
    KEY `idx_worker_id` (`worker_id`),
    KEY `idx_next_retry` (`next_retry_at`),
    CONSTRAINT `fk_upload_queue_backup` FOREIGN KEY (`backup_id`) REFERENCES `backup_history` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Create table for local storage management
CREATE TABLE IF NOT EXISTS `backup_local_storage` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `storage_path` varchar(500) NOT NULL COMMENT 'Base path for local backup storage',
    `max_size_gb` int DEFAULT 100 COMMENT 'Maximum storage size in GB',
    `current_size_bytes` bigint DEFAULT 0 COMMENT 'Current used space in bytes',
    `cleanup_policy` enum('immediate','after_upload','age_based','size_based') DEFAULT 'after_upload',
    `retention_hours` int DEFAULT 24 COMMENT 'Hours to keep local backups (for age_based)',
    `low_watermark_gb` int DEFAULT 80 COMMENT 'Start cleanup when this size reached (for size_based)',
    `is_active` tinyint(1) DEFAULT 1,
    `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `idx_active` (`is_active`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- Insert default local storage configuration
INSERT INTO `backup_local_storage` (`storage_path`, `max_size_gb`, `cleanup_policy`, `retention_hours`)
VALUES ('/docker/backups/local', 100, 'after_upload', 24);

-- Update existing backup_history records to reflect new structure
-- Mark all completed backups as having both creation and upload completed
UPDATE `backup_history`
SET
    `creation_status` = CASE
        WHEN `status` = 'completed' THEN 'created'
        WHEN `status` = 'failed' THEN 'failed'
        WHEN `status` IN ('pending', 'claimed') THEN 'pending'
        WHEN `status` = 'running' THEN 'creating'
        ELSE 'pending'
    END,
    `upload_status` = CASE
        WHEN `status` = 'completed' THEN 'uploaded'
        WHEN `status` = 'failed' THEN 'failed'
        ELSE 'pending'
    END
WHERE `creation_status` IS NULL;