-- ============================================================
-- NIS2 Agile - Migration 010: Audit Trail Certificato SHA-256
-- Hash chain per immutabilità certificabile (ispirato da lg231 AuditTrailService)
-- Estende la tabella audit_logs con prev_hash, entry_hash, severity, performed_by
-- ============================================================
-- Eseguire su Hetzner:
--   mysql -u nis2_agile_user -p nis2_agile_db < docs/sql/010_audit_hash_chain.sql

USE nis2_agile_db;

-- ── Aggiunta colonne (idempotente via information_schema) ──────────────────

-- prev_hash: hash del record precedente per la stessa organization_id
SET @has_prev = (
    SELECT COUNT(*) FROM information_schema.COLUMNS
    WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'audit_logs' AND COLUMN_NAME = 'prev_hash'
);
SET @sql_prev = IF(@has_prev = 0,
    'ALTER TABLE audit_logs ADD COLUMN prev_hash VARCHAR(64) NULL AFTER details',
    'SELECT ''prev_hash already exists'' AS note'
);
PREPARE s FROM @sql_prev; EXECUTE s; DEALLOCATE PREPARE s;

-- entry_hash: SHA-256 di questo record (include prev_hash per la catena)
SET @has_entry = (
    SELECT COUNT(*) FROM information_schema.COLUMNS
    WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'audit_logs' AND COLUMN_NAME = 'entry_hash'
);
SET @sql_entry = IF(@has_entry = 0,
    'ALTER TABLE audit_logs ADD COLUMN entry_hash VARCHAR(64) NOT NULL DEFAULT \'\' AFTER prev_hash',
    'SELECT ''entry_hash already exists'' AS note'
);
PREPARE s FROM @sql_entry; EXECUTE s; DEALLOCATE PREPARE s;

-- severity: criticità dell'evento per filtro dashboard
SET @has_sev = (
    SELECT COUNT(*) FROM information_schema.COLUMNS
    WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'audit_logs' AND COLUMN_NAME = 'severity'
);
SET @sql_sev = IF(@has_sev = 0,
    "ALTER TABLE audit_logs ADD COLUMN severity ENUM('info','warning','critical') NOT NULL DEFAULT 'info' AFTER entry_hash",
    'SELECT ''severity already exists'' AS note'
);
PREPARE s FROM @sql_sev; EXECUTE s; DEALLOCATE PREPARE s;

-- performed_by: email/identificatore utente (denormalizzato per export certificato)
SET @has_by = (
    SELECT COUNT(*) FROM information_schema.COLUMNS
    WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'audit_logs' AND COLUMN_NAME = 'performed_by'
);
SET @sql_by = IF(@has_by = 0,
    'ALTER TABLE audit_logs ADD COLUMN performed_by VARCHAR(255) NULL AFTER severity',
    'SELECT ''performed_by already exists'' AS note'
);
PREPARE s FROM @sql_by; EXECUTE s; DEALLOCATE PREPARE s;

-- ── Indici ────────────────────────────────────────────────────────────────
-- Indice su entry_hash per verifica integrità e ricerca
SET @has_idx_hash = (
    SELECT COUNT(*) FROM information_schema.STATISTICS
    WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'audit_logs' AND INDEX_NAME = 'idx_entry_hash'
);
SET @sql_idx = IF(@has_idx_hash = 0,
    'ALTER TABLE audit_logs ADD INDEX idx_entry_hash (entry_hash)',
    'SELECT ''idx_entry_hash already exists'' AS note'
);
PREPARE s FROM @sql_idx; EXECUTE s; DEALLOCATE PREPARE s;

-- Indice su severity per filtro dashboard
SET @has_idx_sev = (
    SELECT COUNT(*) FROM information_schema.STATISTICS
    WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'audit_logs' AND INDEX_NAME = 'idx_severity'
);
SET @sql_isev = IF(@has_idx_sev = 0,
    'ALTER TABLE audit_logs ADD INDEX idx_severity (severity, organization_id)',
    'SELECT ''idx_severity already exists'' AS note'
);
PREPARE s FROM @sql_isev; EXECUTE s; DEALLOCATE PREPARE s;

-- ── Tabella export certificati audit ─────────────────────────────────────
CREATE TABLE IF NOT EXISTS audit_exports (
    id              INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    organization_id INT NOT NULL,
    exported_by     INT NULL,                          -- user_id (NULL = sistema)
    performed_by    VARCHAR(255) NULL,                 -- email utente
    format          ENUM('json','xml','csv') NOT NULL DEFAULT 'json',
    records_count   INT UNSIGNED NOT NULL DEFAULT 0,
    date_from       DATE NULL,
    date_to         DATE NULL,
    export_hash     VARCHAR(64) NOT NULL,              -- SHA-256 del contenuto export
    chain_valid     TINYINT(1) NOT NULL DEFAULT 1,     -- integrità al momento export
    purpose         VARCHAR(100) NOT NULL DEFAULT 'export_certificato',
    created_at      TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_org (organization_id),
    INDEX idx_created (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- ── Tabella violazioni integrità catena ───────────────────────────────────
CREATE TABLE IF NOT EXISTS audit_violations (
    id              INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    organization_id INT NOT NULL,
    detected_by     VARCHAR(255) NOT NULL DEFAULT 'system',
    broken_at_id    INT NULL,                          -- audit_logs.id dove la catena si rompe
    chain_length    INT UNSIGNED NOT NULL DEFAULT 0,   -- record totali verificati
    notes           TEXT NULL,
    resolved        TINYINT(1) NOT NULL DEFAULT 0,
    created_at      TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

    INDEX idx_org (organization_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

SELECT 'Migration 010 completata: audit_logs con hash chain SHA-256 certificato' AS result;
