-- ScadaLink Machine Data Database seed script
-- Populates ScadaLinkMachineData with realistic SCADA/MES tables,
-- sample data, and stored procedures for development and testing.
--
-- Run after setup.sql:
--   docker exec -i scadalink-mssql /opt/mssql-tools18/bin/sqlcmd \
--     -S localhost -U sa -P 'ScadaLink_Dev1#' -C \
--     -i /docker-entrypoint-initdb.d/machinedata_seed.sql

USE ScadaLinkMachineData;
GO

-- =========================================================================
-- Tables
-- =========================================================================

-- Tag history: time-series data collected from OPC UA / custom protocols
IF OBJECT_ID('dbo.TagHistory', 'U') IS NULL
CREATE TABLE dbo.TagHistory (
    Id            BIGINT IDENTITY(1,1) PRIMARY KEY,
    TagPath       NVARCHAR(256)  NOT NULL,
    Timestamp     DATETIME2(3)   NOT NULL,
    Value         FLOAT          NULL,
    StringValue   NVARCHAR(512)  NULL,
    Quality       TINYINT        NOT NULL DEFAULT 192,  -- 192 = Good
    SiteId        NVARCHAR(64)   NOT NULL,
    INDEX IX_TagHistory_TagPath_Timestamp (TagPath, Timestamp DESC),
    INDEX IX_TagHistory_SiteId_Timestamp (SiteId, Timestamp DESC)
);
GO

-- Production counts: shift/line production totals
IF OBJECT_ID('dbo.ProductionCounts', 'U') IS NULL
CREATE TABLE dbo.ProductionCounts (
    Id            BIGINT IDENTITY(1,1) PRIMARY KEY,
    SiteId        NVARCHAR(64)   NOT NULL,
    LineName      NVARCHAR(128)  NOT NULL,
    ShiftDate     DATE           NOT NULL,
    ShiftNumber   TINYINT        NOT NULL,
    GoodCount     INT            NOT NULL DEFAULT 0,
    RejectCount   INT            NOT NULL DEFAULT 0,
    Efficiency    DECIMAL(5,2)   NULL,
    RecordedAt    DATETIME2(3)   NOT NULL DEFAULT SYSUTCDATETIME(),
    INDEX IX_ProductionCounts_Site_Date (SiteId, ShiftDate DESC)
);
GO

-- Equipment events: state changes, faults, maintenance
IF OBJECT_ID('dbo.EquipmentEvents', 'U') IS NULL
CREATE TABLE dbo.EquipmentEvents (
    Id            BIGINT IDENTITY(1,1) PRIMARY KEY,
    SiteId        NVARCHAR(64)   NOT NULL,
    EquipmentId   NVARCHAR(128)  NOT NULL,
    EventType     NVARCHAR(32)   NOT NULL,  -- 'StateChange', 'Fault', 'Maintenance', 'Alarm'
    PreviousState NVARCHAR(64)   NULL,
    NewState      NVARCHAR(64)   NOT NULL,
    Description   NVARCHAR(512)  NULL,
    Timestamp     DATETIME2(3)   NOT NULL,
    INDEX IX_EquipmentEvents_Equipment_Time (EquipmentId, Timestamp DESC),
    INDEX IX_EquipmentEvents_Site_Type (SiteId, EventType, Timestamp DESC)
);
GO

-- Batch records: production batch tracking
IF OBJECT_ID('dbo.BatchRecords', 'U') IS NULL
CREATE TABLE dbo.BatchRecords (
    Id            BIGINT IDENTITY(1,1) PRIMARY KEY,
    BatchId       NVARCHAR(64)   NOT NULL UNIQUE,
    SiteId        NVARCHAR(64)   NOT NULL,
    RecipeId      NVARCHAR(64)   NOT NULL,
    Status        NVARCHAR(32)   NOT NULL DEFAULT 'InProgress',  -- 'InProgress', 'Complete', 'Aborted'
    StartTime     DATETIME2(3)   NOT NULL,
    EndTime       DATETIME2(3)   NULL,
    TotalQuantity DECIMAL(10,2)  NULL,
    Operator      NVARCHAR(128)  NULL,
    Notes         NVARCHAR(1024) NULL,
    INDEX IX_BatchRecords_Site_Status (SiteId, Status),
    INDEX IX_BatchRecords_StartTime (StartTime DESC)
);
GO

-- Alarm history: historical alarm events
IF OBJECT_ID('dbo.AlarmHistory', 'U') IS NULL
CREATE TABLE dbo.AlarmHistory (
    Id            BIGINT IDENTITY(1,1) PRIMARY KEY,
    SiteId        NVARCHAR(64)   NOT NULL,
    AlarmName     NVARCHAR(256)  NOT NULL,
    Severity      TINYINT        NOT NULL,  -- 1=Low, 2=Medium, 3=High, 4=Critical
    State         NVARCHAR(32)   NOT NULL,  -- 'Active', 'Acknowledged', 'Cleared'
    ActivatedAt   DATETIME2(3)   NOT NULL,
    AcknowledgedAt DATETIME2(3)  NULL,
    ClearedAt     DATETIME2(3)   NULL,
    AcknowledgedBy NVARCHAR(128) NULL,
    Message       NVARCHAR(512)  NULL,
    INDEX IX_AlarmHistory_Site_Active (SiteId, State, ActivatedAt DESC),
    INDEX IX_AlarmHistory_Severity (Severity, ActivatedAt DESC)
);
GO

-- =========================================================================
-- Stored Procedures
-- =========================================================================

-- Get tag history for a tag path within a date range
IF OBJECT_ID('dbo.usp_GetTagHistory', 'P') IS NOT NULL DROP PROCEDURE dbo.usp_GetTagHistory;
GO
CREATE PROCEDURE dbo.usp_GetTagHistory
    @TagPath    NVARCHAR(256),
    @StartTime  DATETIME2(3),
    @EndTime    DATETIME2(3),
    @MaxRows    INT = 10000
AS
BEGIN
    SET NOCOUNT ON;
    SELECT TOP (@MaxRows)
        TagPath, Timestamp, Value, StringValue, Quality, SiteId
    FROM dbo.TagHistory
    WHERE TagPath = @TagPath
      AND Timestamp >= @StartTime
      AND Timestamp <= @EndTime
    ORDER BY Timestamp DESC;
END;
GO

-- Get production summary for a site over a date range
IF OBJECT_ID('dbo.usp_GetProductionSummary', 'P') IS NOT NULL DROP PROCEDURE dbo.usp_GetProductionSummary;
GO
CREATE PROCEDURE dbo.usp_GetProductionSummary
    @SiteId     NVARCHAR(64),
    @StartDate  DATE,
    @EndDate    DATE
AS
BEGIN
    SET NOCOUNT ON;
    SELECT
        LineName,
        SUM(GoodCount) AS TotalGood,
        SUM(RejectCount) AS TotalReject,
        SUM(GoodCount) + SUM(RejectCount) AS TotalProduced,
        CASE
            WHEN SUM(GoodCount) + SUM(RejectCount) > 0
            THEN CAST(SUM(GoodCount) * 100.0 / (SUM(GoodCount) + SUM(RejectCount)) AS DECIMAL(5,2))
            ELSE 0
        END AS YieldPercent,
        AVG(Efficiency) AS AvgEfficiency,
        COUNT(DISTINCT ShiftDate) AS DaysReported
    FROM dbo.ProductionCounts
    WHERE SiteId = @SiteId
      AND ShiftDate >= @StartDate
      AND ShiftDate <= @EndDate
    GROUP BY LineName
    ORDER BY LineName;
END;
GO

-- Insert a batch record (used by CachedWrite from scripts)
IF OBJECT_ID('dbo.usp_InsertBatchRecord', 'P') IS NOT NULL DROP PROCEDURE dbo.usp_InsertBatchRecord;
GO
CREATE PROCEDURE dbo.usp_InsertBatchRecord
    @BatchId       NVARCHAR(64),
    @SiteId        NVARCHAR(64),
    @RecipeId      NVARCHAR(64),
    @TotalQuantity DECIMAL(10,2) = NULL,
    @Operator      NVARCHAR(128) = NULL,
    @Notes         NVARCHAR(1024) = NULL
AS
BEGIN
    SET NOCOUNT ON;
    INSERT INTO dbo.BatchRecords (BatchId, SiteId, RecipeId, Status, StartTime, TotalQuantity, Operator, Notes)
    VALUES (@BatchId, @SiteId, @RecipeId, 'InProgress', SYSUTCDATETIME(), @TotalQuantity, @Operator, @Notes);

    SELECT SCOPE_IDENTITY() AS Id, @BatchId AS BatchId;
END;
GO

-- Complete or abort a batch
IF OBJECT_ID('dbo.usp_CompleteBatch', 'P') IS NOT NULL DROP PROCEDURE dbo.usp_CompleteBatch;
GO
CREATE PROCEDURE dbo.usp_CompleteBatch
    @BatchId       NVARCHAR(64),
    @Status        NVARCHAR(32),  -- 'Complete' or 'Aborted'
    @TotalQuantity DECIMAL(10,2) = NULL,
    @Notes         NVARCHAR(1024) = NULL
AS
BEGIN
    SET NOCOUNT ON;
    UPDATE dbo.BatchRecords
    SET Status = @Status,
        EndTime = SYSUTCDATETIME(),
        TotalQuantity = COALESCE(@TotalQuantity, TotalQuantity),
        Notes = COALESCE(@Notes, Notes)
    WHERE BatchId = @BatchId
      AND Status = 'InProgress';

    IF @@ROWCOUNT = 0
        THROW 50001, 'Batch not found or not in progress.', 1;

    SELECT BatchId, Status, StartTime, EndTime, TotalQuantity
    FROM dbo.BatchRecords
    WHERE BatchId = @BatchId;
END;
GO

-- Get recent equipment events
IF OBJECT_ID('dbo.usp_GetEquipmentEvents', 'P') IS NOT NULL DROP PROCEDURE dbo.usp_GetEquipmentEvents;
GO
CREATE PROCEDURE dbo.usp_GetEquipmentEvents
    @SiteId      NVARCHAR(64),
    @EquipmentId NVARCHAR(128) = NULL,
    @EventType   NVARCHAR(32) = NULL,
    @Hours       INT = 24
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @Since DATETIME2(3) = DATEADD(HOUR, -@Hours, SYSUTCDATETIME());

    SELECT
        EquipmentId, EventType, PreviousState, NewState, Description, Timestamp
    FROM dbo.EquipmentEvents
    WHERE SiteId = @SiteId
      AND Timestamp >= @Since
      AND (@EquipmentId IS NULL OR EquipmentId = @EquipmentId)
      AND (@EventType IS NULL OR EventType = @EventType)
    ORDER BY Timestamp DESC;
END;
GO

-- Get active alarms for a site
IF OBJECT_ID('dbo.usp_GetActiveAlarms', 'P') IS NOT NULL DROP PROCEDURE dbo.usp_GetActiveAlarms;
GO
CREATE PROCEDURE dbo.usp_GetActiveAlarms
    @SiteId       NVARCHAR(64),
    @MinSeverity  TINYINT = 1
AS
BEGIN
    SET NOCOUNT ON;
    SELECT
        AlarmName, Severity, State, ActivatedAt, AcknowledgedAt,
        AcknowledgedBy, Message
    FROM dbo.AlarmHistory
    WHERE SiteId = @SiteId
      AND State IN ('Active', 'Acknowledged')
      AND Severity >= @MinSeverity
    ORDER BY Severity DESC, ActivatedAt DESC;
END;
GO

-- =========================================================================
-- Sample Data
-- =========================================================================

-- Tag history (last few hours of data for two sites)
DECLARE @now DATETIME2(3) = SYSUTCDATETIME();

INSERT INTO dbo.TagHistory (TagPath, Timestamp, Value, Quality, SiteId) VALUES
('SiteA/Pump-001/Pressure',    DATEADD(MINUTE, -120, @now), 45.2,  192, 'SiteA'),
('SiteA/Pump-001/Pressure',    DATEADD(MINUTE, -110, @now), 46.1,  192, 'SiteA'),
('SiteA/Pump-001/Pressure',    DATEADD(MINUTE, -100, @now), 44.8,  192, 'SiteA'),
('SiteA/Pump-001/Pressure',    DATEADD(MINUTE,  -90, @now), 47.3,  192, 'SiteA'),
('SiteA/Pump-001/Pressure',    DATEADD(MINUTE,  -80, @now), 45.9,  192, 'SiteA'),
('SiteA/Pump-001/Flow',        DATEADD(MINUTE, -120, @now), 120.5, 192, 'SiteA'),
('SiteA/Pump-001/Flow',        DATEADD(MINUTE, -110, @now), 121.2, 192, 'SiteA'),
('SiteA/Pump-001/Flow',        DATEADD(MINUTE, -100, @now), 119.8, 192, 'SiteA'),
('SiteA/Tank-001/Level',       DATEADD(MINUTE, -120, @now), 72.0,  192, 'SiteA'),
('SiteA/Tank-001/Level',       DATEADD(MINUTE, -110, @now), 73.5,  192, 'SiteA'),
('SiteA/Tank-001/Level',       DATEADD(MINUTE, -100, @now), 75.1,  192, 'SiteA'),
('SiteA/Tank-001/Level',       DATEADD(MINUTE,  -90, @now), 76.8,  192, 'SiteA'),
('SiteA/Tank-001/Temperature', DATEADD(MINUTE, -120, @now), 65.3,  192, 'SiteA'),
('SiteA/Tank-001/Temperature', DATEADD(MINUTE, -110, @now), 65.5,  192, 'SiteA'),
('SiteA/Conv-001/Speed',       DATEADD(MINUTE, -120, @now), 2.4,   192, 'SiteA'),
('SiteA/Conv-001/Speed',       DATEADD(MINUTE, -110, @now), 0.0,     0, 'SiteA'),  -- Bad quality (stopped)
('SiteA/Conv-001/Speed',       DATEADD(MINUTE, -100, @now), 2.3,   192, 'SiteA'),
('SiteB/Mixer-001/RPM',        DATEADD(MINUTE, -120, @now), 450.0, 192, 'SiteB'),
('SiteB/Mixer-001/RPM',        DATEADD(MINUTE, -110, @now), 452.0, 192, 'SiteB'),
('SiteB/Mixer-001/RPM',        DATEADD(MINUTE, -100, @now), 448.0, 192, 'SiteB'),
('SiteB/Mixer-001/Temperature',DATEADD(MINUTE, -120, @now), 82.1,  192, 'SiteB'),
('SiteB/Mixer-001/Temperature',DATEADD(MINUTE, -110, @now), 83.0,  192, 'SiteB');

-- Production counts (last 3 days, 2 shifts per day)
DECLARE @today DATE = CAST(SYSUTCDATETIME() AS DATE);

INSERT INTO dbo.ProductionCounts (SiteId, LineName, ShiftDate, ShiftNumber, GoodCount, RejectCount, Efficiency) VALUES
('SiteA', 'Line-1', DATEADD(DAY, -2, @today), 1, 4100, 82,  92.5),
('SiteA', 'Line-1', DATEADD(DAY, -2, @today), 2, 3900, 95,  91.2),
('SiteA', 'Line-2', DATEADD(DAY, -2, @today), 1, 3050, 120, 88.1),
('SiteA', 'Line-2', DATEADD(DAY, -2, @today), 2, 2900, 105, 87.5),
('SiteA', 'Line-1', DATEADD(DAY, -1, @today), 1, 4200, 75,  93.1),
('SiteA', 'Line-1', DATEADD(DAY, -1, @today), 2, 4050, 88,  92.0),
('SiteA', 'Line-2', DATEADD(DAY, -1, @today), 1, 3100, 98,  89.2),
('SiteA', 'Line-2', DATEADD(DAY, -1, @today), 2, 3000, 110, 88.0),
('SiteA', 'Line-1', @today,                    1, 2100, 40,  93.5),
('SiteA', 'Line-2', @today,                    1, 1550, 65,  88.8),
('SiteB', 'Mixing',  DATEADD(DAY, -1, @today), 1, 850,  12,  95.0),
('SiteB', 'Mixing',  DATEADD(DAY, -1, @today), 2, 820,  15,  94.2),
('SiteB', 'Packing', DATEADD(DAY, -1, @today), 1, 1600, 45,  90.5),
('SiteB', 'Packing', DATEADD(DAY, -1, @today), 2, 1550, 50,  89.8);

-- Equipment events
INSERT INTO dbo.EquipmentEvents (SiteId, EquipmentId, EventType, PreviousState, NewState, Description, Timestamp) VALUES
('SiteA', 'PUMP-001', 'StateChange', 'Idle',    'Running', 'Shift start',                  DATEADD(HOUR, -8, @now)),
('SiteA', 'PUMP-001', 'Fault',       'Running', 'Faulted', 'Overcurrent detected',         DATEADD(HOUR, -5, @now)),
('SiteA', 'PUMP-001', 'StateChange', 'Faulted', 'Running', 'Manual reset by operator',     DATEADD(HOUR, -4, @now)),
('SiteA', 'TANK-001', 'Alarm',       NULL,      'HighLevel','Tank level exceeded 90%',      DATEADD(HOUR, -3, @now)),
('SiteA', 'TANK-001', 'Alarm',       NULL,      'Normal',   'Tank level returned to normal',DATEADD(HOUR, -2, @now)),
('SiteA', 'CONV-001', 'Maintenance', 'Running', 'Maintenance', 'Scheduled belt inspection', DATEADD(HOUR, -6, @now)),
('SiteA', 'CONV-001', 'StateChange', 'Maintenance', 'Running', 'Maintenance complete',      DATEADD(HOUR, -5, @now)),
('SiteB', 'MIXER-001','StateChange', 'Idle',    'Running', 'Batch R-100 started',           DATEADD(HOUR, -7, @now)),
('SiteB', 'MIXER-001','StateChange', 'Running', 'Idle',    'Batch R-100 complete',          DATEADD(HOUR, -3, @now));

-- Batch records
INSERT INTO dbo.BatchRecords (BatchId, SiteId, RecipeId, Status, StartTime, EndTime, TotalQuantity, Operator, Notes) VALUES
('BATCH-20260314-001', 'SiteA', 'R-100', 'Complete',   DATEADD(HOUR, -26, @now), DATEADD(HOUR, -22, @now), 450.00, 'jsmith',   'Normal run'),
('BATCH-20260314-002', 'SiteA', 'R-200', 'Complete',   DATEADD(HOUR, -20, @now), DATEADD(HOUR, -16, @now), 380.50, 'jsmith',   'Slight yield loss on Material-B'),
('BATCH-20260315-001', 'SiteB', 'R-100', 'Complete',   DATEADD(HOUR, -10, @now), DATEADD(HOUR,  -6, @now), 445.00, 'mdoe',     NULL),
('BATCH-20260315-002', 'SiteA', 'R-150', 'Aborted',    DATEADD(HOUR,  -8, @now), DATEADD(HOUR,  -7, @now), NULL,   'jsmith',   'Material-A out of spec, aborted early'),
('BATCH-20260316-001', 'SiteA', 'R-100', 'InProgress', DATEADD(HOUR,  -2, @now), NULL,                     NULL,   'bwilson',  'Current batch');

-- Alarm history
INSERT INTO dbo.AlarmHistory (SiteId, AlarmName, Severity, State, ActivatedAt, AcknowledgedAt, ClearedAt, AcknowledgedBy, Message) VALUES
('SiteA', 'Tank-001 High Level',       3, 'Cleared',      DATEADD(HOUR, -3, @now), DATEADD(HOUR, -3, @now), DATEADD(HOUR, -2, @now), 'jsmith',  'Level exceeded 90% setpoint'),
('SiteA', 'Pump-001 Overcurrent',      4, 'Cleared',      DATEADD(HOUR, -5, @now), DATEADD(HOUR, -5, @now), DATEADD(HOUR, -4, @now), 'jsmith',  'Current draw 15.2A (limit 12A)'),
('SiteA', 'Conv-001 Belt Slip',        2, 'Active',       DATEADD(HOUR, -1, @now), NULL,                    NULL,                    NULL,      'Belt speed deviation >5%'),
('SiteA', 'Tank-001 Temperature High', 3, 'Acknowledged', DATEADD(MINUTE, -30, @now), DATEADD(MINUTE, -25, @now), NULL,               'bwilson', 'Temperature 68.2C (limit 65C)'),
('SiteB', 'Mixer-001 Vibration',       2, 'Active',       DATEADD(HOUR, -2, @now), NULL,                    NULL,                    NULL,      'Vibration level elevated');
GO

PRINT 'ScadaLinkMachineData seed complete.';
PRINT 'Tables: TagHistory, ProductionCounts, EquipmentEvents, BatchRecords, AlarmHistory';
PRINT 'Stored Procedures: usp_GetTagHistory, usp_GetProductionSummary, usp_InsertBatchRecord, usp_CompleteBatch, usp_GetEquipmentEvents, usp_GetActiveAlarms';
GO
