-- Panel Transmitiras: usuarios, permisos y sesiones (mismo modelo que
-- ~/dev/a24c/backend/api/v1/modules/dashboard — tablas en inglés, esquema a24c).
-- Ejecutar en PostgreSQL (misma base donde está el catálogo ControlDesk, p. ej. CONTROLDESK).

CREATE SCHEMA IF NOT EXISTS a24c;

CREATE TABLE IF NOT EXISTS a24c.dashboard_users (
    id              SERIAL PRIMARY KEY,
    username        VARCHAR(50) UNIQUE NOT NULL,
    email           VARCHAR(100) UNIQUE NOT NULL,
    password_hash   VARCHAR(255) NOT NULL,
    full_name       VARCHAR(100),
    is_active       BOOLEAN NOT NULL DEFAULT true,
    is_admin        BOOLEAN NOT NULL DEFAULT false,
    created_at      TIMESTAMPTZ NOT NULL DEFAULT now(),
    last_access_at  TIMESTAMPTZ,
    CONSTRAINT chk_dashboard_users_username_length CHECK (char_length(username) >= 3)
);

CREATE TABLE IF NOT EXISTS a24c.dashboard_user_database_permissions (
    id                     SERIAL PRIMARY KEY,
    dashboard_user_id      INTEGER NOT NULL REFERENCES a24c.dashboard_users (id) ON DELETE CASCADE,
    database_name          VARCHAR(255) NOT NULL,
    can_view               BOOLEAN NOT NULL DEFAULT true,
    can_download_backup    BOOLEAN NOT NULL DEFAULT false,
    can_restore            BOOLEAN NOT NULL DEFAULT false,
    assigned_at            TIMESTAMPTZ NOT NULL DEFAULT now(),
    UNIQUE (dashboard_user_id, database_name)
);

CREATE TABLE IF NOT EXISTS a24c.dashboard_sessions (
    id                  SERIAL PRIMARY KEY,
    dashboard_user_id   INTEGER NOT NULL REFERENCES a24c.dashboard_users (id) ON DELETE CASCADE,
    token               VARCHAR(255) UNIQUE NOT NULL,
    ip_address          VARCHAR(50),
    user_agent          TEXT,
    created_at          TIMESTAMPTZ NOT NULL DEFAULT now(),
    expires_at          TIMESTAMPTZ NOT NULL,
    is_active           BOOLEAN NOT NULL DEFAULT true
);

CREATE INDEX IF NOT EXISTS idx_a24c_dashboard_user_db_perm_user
    ON a24c.dashboard_user_database_permissions (dashboard_user_id);
CREATE INDEX IF NOT EXISTS idx_a24c_dashboard_user_db_perm_dbname
    ON a24c.dashboard_user_database_permissions (database_name);
CREATE INDEX IF NOT EXISTS idx_a24c_dashboard_users_active ON a24c.dashboard_users (is_active);
CREATE INDEX IF NOT EXISTS idx_a24c_dashboard_sessions_token ON a24c.dashboard_sessions (token);
CREATE INDEX IF NOT EXISTS idx_a24c_dashboard_sessions_user ON a24c.dashboard_sessions (dashboard_user_id);

COMMENT ON TABLE a24c.dashboard_users IS 'Operadores del panel Transmitiras (JWT/bcrypt). Paridad api/v1/modules/dashboard/users.';
COMMENT ON TABLE a24c.dashboard_user_database_permissions IS 'Permisos por base de datos. Paridad dashboard/user_database_permissions.';
COMMENT ON TABLE a24c.dashboard_sessions IS 'Sesiones persistidas (opcional; el panel usa JWT en cookie). Paridad dashboard/sessions.';

-- Usuario admin por defecto (cambiar password_hash tras primer arranque; ver scripts/generate-password-hash.js)
INSERT INTO a24c.dashboard_users (username, email, password_hash, full_name, is_admin, is_active)
VALUES (
    'admin',
    'admin@aduanasoft.com',
    '$2b$10$rKvvkYpNwF5J5K5J5J5J5uX5X5X5X5X5X5X5X5X5X5X5X5X5X5X5X',
    'Administrador del Sistema',
    true,
    true
)
ON CONFLICT (username) DO NOTHING;

-- ============================================================================
-- Integración CloudRestoreAS: servidores de restauración y bitácora de jobs.
-- Equivalente versionado en database/migrations/001_restore_targets.{up,down}.sql
-- ============================================================================

-- Servidores SQL Server destino de restauración (Alfa, Omega, Gamma). Son máquinas
-- EXTERNAS independientes: el .bak se transfiere por SFTP/SSH al servidor y el SQL Server
-- restaura desde su disco local. Cada base (a24c.database_nodes.restore_target_id) se asigna
-- a uno de ellos. Las contraseñas (SQL y SSH) se guardan cifradas con AES-256-GCM, nunca en plano.
CREATE TABLE IF NOT EXISTS a24c.restore_targets (
    id                      SERIAL PRIMARY KEY,
    name                    VARCHAR(120) NOT NULL UNIQUE,  -- Alfa | Omega | Gamma
    server_ip               VARCHAR(255),            -- SQL Server: IP/hostname; acepta "ip,puerto"
    sql_username            VARCHAR(128),
    sql_password_encrypted  TEXT,                    -- sobre gcm:iv:tag:ciphertext
    data_folder             VARCHAR(500),            -- ruta .mdf/.ldf EN el server remoto (C:\SQLData)
    ssh_host                VARCHAR(255),            -- host SSH del servidor (suele ser el mismo equipo)
    ssh_port                INTEGER DEFAULT 22,
    ssh_username            VARCHAR(128),
    ssh_password_encrypted  TEXT,                    -- credencial SSH cifrada (AES-256-GCM)
    remote_inbox_path       VARCHAR(500),            -- ruta en el server donde se sube el .bak y se restaura (C:\RestoreInbox)
    notes                   TEXT,
    -- Características de hardware (opcionales, capturadas a mano). Se usan para distribuir bases
    -- por capacidad; el disco es la capacidad que manda. NULL = sin capturar.
    os                      VARCHAR(50),             -- Sistema operativo (Linux/Windows/…)
    ram_gb                  INTEGER,                 -- RAM en GB
    disk_gb                 INTEGER,                 -- Disco en GB
    location                VARCHAR(255),            -- Ubicación (ej: Kansas City, United States)
    size_category           VARCHAR(20),             -- Etiqueta: Chico | Mediano | Grande
    created_at              TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at              TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- Tres servidores fijos de partida (editables). Datos de conexión vacíos hasta configurarse.
INSERT INTO a24c.restore_targets (name) VALUES ('Alfa'), ('Omega'), ('Gamma')
ON CONFLICT (name) DO NOTHING;

-- Asignación servidor de restauración ↔ base de datos (la tabla database_nodes la aprovisiona
-- el backend a24c; aquí solo se agrega la columna de asignación).
ALTER TABLE a24c.database_nodes
    ADD COLUMN IF NOT EXISTS restore_target_id INTEGER
    REFERENCES a24c.restore_targets (id) ON DELETE SET NULL;

-- Backfill único: la credencial SQL del nodo (database_nodes.sql_password, columna de a24c) se
-- copia del restaurador asignado como sobre cifrado gcm: (el panel lo descifra al conectar).
-- Idempotente: solo rellena nodos ya asignados sin contraseña; no pisa valores existentes.
-- Guardado por si a24c aún no aprovisionó la columna sql_password (evita romper el init).
-- Rollback: UPDATE a24c.database_nodes SET sql_password = NULL;
DO $$
BEGIN
    IF EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'a24c'
          AND table_name = 'database_nodes'
          AND column_name = 'sql_password'
    ) THEN
        UPDATE a24c.database_nodes n
        SET sql_password = rt.sql_password_encrypted
        FROM a24c.restore_targets rt
        WHERE n.restore_target_id = rt.id
          AND rt.sql_password_encrypted IS NOT NULL
          AND (n.sql_password IS NULL OR n.sql_password = '');
    END IF;
END $$;

-- Bitácora de restauraciones reportadas por CloudRestoreAS.
CREATE TABLE IF NOT EXISTS a24c.restore_job_logs (
    id                  SERIAL PRIMARY KEY,
    filename            VARCHAR(500) NOT NULL,
    restore_target_id   INTEGER REFERENCES a24c.restore_targets (id) ON DELETE SET NULL,
    db_name             VARCHAR(255),
    status              VARCHAR(20) NOT NULL CHECK (status IN ('completed', 'failed', 'forwarded')),
    duration_ms         INTEGER,
    error_message       TEXT,
    restored_at         TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_a24c_restore_job_logs_target
    ON a24c.restore_job_logs (restore_target_id);
CREATE INDEX IF NOT EXISTS idx_a24c_restore_job_logs_restored_at
    ON a24c.restore_job_logs (restored_at);
CREATE INDEX IF NOT EXISTS idx_a24c_restore_job_logs_status
    ON a24c.restore_job_logs (status);
-- Bitácora por servidor en el panel: últimas N restauraciones de un target.
CREATE INDEX IF NOT EXISTS idx_a24c_restore_job_logs_target_date
    ON a24c.restore_job_logs (restore_target_id, restored_at DESC);

COMMENT ON TABLE a24c.restore_targets IS 'Servidores SQL Server destino de restauración (CloudRestoreAS). Contraseña cifrada AES-256-GCM.';
COMMENT ON TABLE a24c.restore_job_logs IS 'Bitácora de restauraciones reportadas por CloudRestoreAS.';

-- Equivalente versionado en database/migrations/002_cloudrestore_status.{up,down}.sql
-- Carpeta de entrada reportada por CloudRestoreAS (solo lectura en el panel).
CREATE TABLE IF NOT EXISTS a24c.cloudrestore_status (
    id              SERIAL PRIMARY KEY,
    instance_key    VARCHAR(120) NOT NULL UNIQUE DEFAULT 'default',
    input_folder    VARCHAR(500) NOT NULL,
    host_name       VARCHAR(255),
    app_version     VARCHAR(50),
    reported_at     TIMESTAMPTZ NOT NULL DEFAULT now()
);

COMMENT ON TABLE a24c.cloudrestore_status IS
    'Carpeta de entrada vigente reportada por CloudRestoreAS. Solo lectura en el panel.';
