-- ============================================================
-- 🖥️ CLQMS Edge Workstation - SQLite Database Schema
-- Project Pandaria: Offline-First LIS Architecture
-- ============================================================
-- This is the LOCAL database for each Smart Workstation.
-- Stack: Node.js (Electron) + SQLite
-- Role: "The Cortex" - Immediate Processing
-- ============================================================

-- 🔧 Enable foreign keys (SQLite needs this explicitly)
PRAGMA foreign_keys = ON;

-- ============================================================
-- 1. 📋 CACHED ORDERS (Hot Cache - Last 7 Days)
-- ============================================================
-- Orders downloaded from the Core Server for local processing.
-- Workstation can work 100% offline with this data.

CREATE TABLE IF NOT EXISTS orders (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    server_order_id TEXT UNIQUE NOT NULL,     -- Original ID from Core Server
    patient_id TEXT NOT NULL,
    patient_name TEXT NOT NULL,
    patient_dob DATE,
    patient_gender TEXT CHECK(patient_gender IN ('M', 'F', 'O')),
    order_date DATETIME NOT NULL,
    priority TEXT DEFAULT 'routine' CHECK(priority IN ('stat', 'routine', 'urgent')),
    status TEXT DEFAULT 'pending' CHECK(status IN ('pending', 'in_progress', 'completed', 'cancelled')),
    barcode TEXT,
    notes TEXT,
    synced_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_orders_barcode ON orders(barcode);
CREATE INDEX idx_orders_status ON orders(status);
CREATE INDEX idx_orders_patient ON orders(patient_id);

-- ============================================================
-- 2. 🔬 ORDER TESTS (What tests are requested?)
-- ============================================================
-- Each order can have multiple tests (CBC, Urinalysis, etc.)

CREATE TABLE IF NOT EXISTS order_tests (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    order_id INTEGER NOT NULL,
    test_code TEXT NOT NULL,                  -- Standardized code (e.g., 'WBC_TOTAL')
    test_name TEXT NOT NULL,                  -- Display name (e.g., 'White Blood Cell Count')
    status TEXT DEFAULT 'pending' CHECK(status IN ('pending', 'processing', 'completed', 'failed')),
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE
);

CREATE INDEX idx_order_tests_order ON order_tests(order_id);
CREATE INDEX idx_order_tests_code ON order_tests(test_code);

-- ============================================================
-- 3. 📊 RESULTS (Machine Output - Normalized)
-- ============================================================
-- Results from lab machines, already translated to standard format.

CREATE TABLE IF NOT EXISTS results (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    order_test_id INTEGER,
    machine_id INTEGER,
    test_code TEXT NOT NULL,                  -- Standardized test code
    value REAL NOT NULL,                      -- Numeric result
    unit TEXT NOT NULL,                       -- Standardized unit
    reference_low REAL,
    reference_high REAL,
    flag TEXT CHECK(flag IN ('L', 'N', 'H', 'LL', 'HH', 'A')), -- Low, Normal, High, Critical Low/High, Abnormal
    raw_value TEXT,                           -- Original value from machine
    raw_unit TEXT,                            -- Original unit from machine
    raw_test_code TEXT,                       -- Original code from machine (before translation)
    validated BOOLEAN DEFAULT 0,
    validated_by TEXT,
    validated_at DATETIME,
    machine_timestamp DATETIME,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (order_test_id) REFERENCES order_tests(id) ON DELETE SET NULL,
    FOREIGN KEY (machine_id) REFERENCES machines(id) ON DELETE SET NULL
);

CREATE INDEX idx_results_order_test ON results(order_test_id);
CREATE INDEX idx_results_test_code ON results(test_code);
CREATE INDEX idx_results_validated ON results(validated);

-- ============================================================
-- 4. 📮 OUTBOX QUEUE (Registered Mail Pattern)
-- ============================================================
-- Data waits here until the Core Server confirms receipt (ACK).
-- Zero data loss, even if network blinks!

CREATE TABLE IF NOT EXISTS outbox_queue (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    event_type TEXT NOT NULL,                 -- 'result_created', 'result_validated', 'order_updated'
    payload TEXT NOT NULL,                    -- JSON data to sync
    target_entity TEXT,                       -- 'results', 'orders', etc.
    target_id INTEGER,                        -- ID of the record
    priority INTEGER DEFAULT 5,               -- 1 = highest, 10 = lowest
    retry_count INTEGER DEFAULT 0,
    max_retries INTEGER DEFAULT 5,
    last_error TEXT,
    status TEXT DEFAULT 'pending' CHECK(status IN ('pending', 'processing', 'sent', 'acked', 'failed')),
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    sent_at DATETIME,
    acked_at DATETIME
);

CREATE INDEX idx_outbox_status ON outbox_queue(status);
CREATE INDEX idx_outbox_priority ON outbox_queue(priority, created_at);

-- ============================================================
-- 5. 📥 INBOX QUEUE (Messages from Server)
-- ============================================================
-- Incoming messages/orders from Core Server waiting to be processed.

CREATE TABLE IF NOT EXISTS inbox_queue (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    server_message_id TEXT UNIQUE NOT NULL,   -- ID from server for deduplication
    event_type TEXT NOT NULL,                 -- 'new_order', 'order_cancelled', 'config_update'
    payload TEXT NOT NULL,                    -- JSON data
    status TEXT DEFAULT 'pending' CHECK(status IN ('pending', 'processing', 'completed', 'failed')),
    error_message TEXT,
    received_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    processed_at DATETIME
);

CREATE INDEX idx_inbox_status ON inbox_queue(status);

-- ============================================================
-- 6. 🔌 MACHINES (Connected Lab Equipment)
-- ============================================================
-- Registry of connected machines/analyzers.

CREATE TABLE IF NOT EXISTS machines (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL,                       -- 'Sysmex XN-1000', 'Mindray BC-6800'
    manufacturer TEXT,
    model TEXT,
    serial_number TEXT,
    driver_file TEXT NOT NULL,                -- 'driver-sysmex-xn1000.js'
    connection_type TEXT CHECK(connection_type IN ('RS232', 'TCP', 'USB', 'FILE')),
    connection_config TEXT,                   -- JSON: {"port": "COM3", "baudRate": 9600}
    is_active BOOLEAN DEFAULT 1,
    last_communication DATETIME,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

-- ============================================================
-- 7. 📖 TEST DICTIONARY (The Translator)
-- ============================================================
-- Maps machine-specific codes to standard codes.
-- Solves the "WBC vs Leukocytes" problem!

CREATE TABLE IF NOT EXISTS test_dictionary (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    machine_id INTEGER,                       -- NULL = universal mapping
    raw_code TEXT NOT NULL,                   -- What the machine sends: 'W.B.C', 'Leukocytes'
    standard_code TEXT NOT NULL,              -- Our standard: 'WBC_TOTAL'
    standard_name TEXT NOT NULL,              -- 'White Blood Cell Count'
    unit_conversion_factor REAL DEFAULT 1.0,  -- Multiply raw value by this (e.g., 10 for g/dL to g/L)
    raw_unit TEXT,                            -- Unit machine sends
    standard_unit TEXT,                       -- Our standard unit
    reference_low REAL,
    reference_high REAL,
    is_active BOOLEAN DEFAULT 1,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (machine_id) REFERENCES machines(id) ON DELETE CASCADE,
    UNIQUE(machine_id, raw_code)
);

CREATE INDEX idx_dictionary_lookup ON test_dictionary(machine_id, raw_code);

-- ============================================================
-- 8. 📜 SYNC LOG (Audit Trail)
-- ============================================================
-- Track all sync activities for debugging & recovery.

CREATE TABLE IF NOT EXISTS sync_log (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    direction TEXT CHECK(direction IN ('push', 'pull')),
    event_type TEXT NOT NULL,
    entity_type TEXT,
    entity_id INTEGER,
    server_response_code INTEGER,
    server_message TEXT,
    success BOOLEAN,
    duration_ms INTEGER,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_sync_log_created ON sync_log(created_at DESC);

-- ============================================================
-- 9. ⚙️ LOCAL CONFIG (Workstation Settings)
-- ============================================================
-- Key-value store for workstation-specific settings.

CREATE TABLE IF NOT EXISTS config (
    key TEXT PRIMARY KEY,
    value TEXT,
    description TEXT,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

-- ============================================================
-- 📦 SAMPLE DATA: Machines & Dictionary
-- ============================================================

-- Sample Machines
INSERT INTO machines (name, manufacturer, model, driver_file, connection_type, connection_config) VALUES
('Sysmex XN-1000', 'Sysmex', 'XN-1000', 'driver-sysmex-xn1000.js', 'RS232', '{"port": "COM3", "baudRate": 9600}'),
('Mindray BC-6800', 'Mindray', 'BC-6800', 'driver-mindray-bc6800.js', 'TCP', '{"host": "192.168.1.50", "port": 5000}');

-- Sample Test Dictionary (The Translator)
INSERT INTO test_dictionary (machine_id, raw_code, standard_code, standard_name, raw_unit, standard_unit, unit_conversion_factor, reference_low, reference_high) VALUES
-- Sysmex mappings (machine_id = 1)
(1, 'WBC', 'WBC_TOTAL', 'White Blood Cell Count', '10^3/uL', '10^3/uL', 1.0, 4.0, 11.0),
(1, 'RBC', 'RBC_TOTAL', 'Red Blood Cell Count', '10^6/uL', '10^6/uL', 1.0, 4.5, 5.5),
(1, 'HGB', 'HGB', 'Hemoglobin', 'g/dL', 'g/L', 10.0, 120, 170),
(1, 'PLT', 'PLT_TOTAL', 'Platelet Count', '10^3/uL', '10^3/uL', 1.0, 150, 400),
-- Mindray mappings (machine_id = 2) - Different naming!
(2, 'Leukocytes', 'WBC_TOTAL', 'White Blood Cell Count', 'x10^9/L', '10^3/uL', 1.0, 4.0, 11.0),
(2, 'Erythrocytes', 'RBC_TOTAL', 'Red Blood Cell Count', 'x10^12/L', '10^6/uL', 1.0, 4.5, 5.5),
(2, 'Hb', 'HGB', 'Hemoglobin', 'g/L', 'g/L', 1.0, 120, 170),
(2, 'Thrombocytes', 'PLT_TOTAL', 'Platelet Count', 'x10^9/L', '10^3/uL', 1.0, 150, 400),
-- Universal mappings (machine_id = NULL)
(NULL, 'W.B.C', 'WBC_TOTAL', 'White Blood Cell Count', NULL, '10^3/uL', 1.0, 4.0, 11.0),
(NULL, 'White_Cells', 'WBC_TOTAL', 'White Blood Cell Count', NULL, '10^3/uL', 1.0, 4.0, 11.0);

-- Sample Config
INSERT INTO config (key, value, description) VALUES
('workstation_id', 'LAB-WS-001', 'Unique identifier for this workstation'),
('workstation_name', 'Hematology Station 1', 'Human-readable name'),
('server_url', 'https://clqms-core.example.com/api', 'Core Server API endpoint'),
('cache_days', '7', 'Number of days to keep cached orders'),
('auto_validate', 'false', 'Auto-validate results within normal range'),
('last_sync', NULL, 'Timestamp of last successful sync');

-- Sample Order (for testing)
INSERT INTO orders (server_order_id, patient_id, patient_name, patient_dob, patient_gender, order_date, priority, barcode) VALUES
('ORD-2025-001234', 'PAT-00001', 'John Smith', '1980-01-15', 'M', '2025-12-19 08:00:00', 'routine', 'LAB2025001234');

INSERT INTO order_tests (order_id, test_code, test_name) VALUES
(1, 'WBC_TOTAL', 'White Blood Cell Count'),
(1, 'RBC_TOTAL', 'Red Blood Cell Count'),
(1, 'HGB', 'Hemoglobin'),
(1, 'PLT_TOTAL', 'Platelet Count');

-- ============================================================
-- ✅ DONE! Your Edge Workstation database is ready.
-- ============================================================
