WITH base AS (
    SELECT 
        t_stamp,
        Name,
        Full,
        Half_Full,
        Jam,
        No_Container,
        Block_Operation
    FROM lane_data
    WHERE t_stamp BETWEEN :startTime AND :endTime
),

-- Unpivot signals into rows
ev AS (
    SELECT Name, t_stamp, 'Full' AS sig, Full AS val FROM base
    UNION ALL SELECT Name, t_stamp, 'Half_Full', Half_Full FROM base
    UNION ALL SELECT Name, t_stamp, 'Jam', Jam FROM base
    UNION ALL SELECT Name, t_stamp, 'No_Container', No_Container FROM base
    UNION ALL SELECT Name, t_stamp, 'Block_Operation', Block_Operation FROM base
),

-- Add previous and next values, and find falling edges
ch AS (
    SELECT
        Name,
        sig,
        t_stamp,
        val,
        LAG(val) OVER (PARTITION BY Name, sig ORDER BY t_stamp)  AS prev_val,
        LEAD(val) OVER (PARTITION BY Name, sig ORDER BY t_stamp) AS next_val,
        LEAD(t_stamp) OVER (PARTITION BY Name, sig ORDER BY t_stamp) AS next_ts
    FROM ev
),

-- Mark rising and falling edges
edges AS (
    SELECT
        Name,
        sig,
        t_stamp,
        val,
        CASE 
            WHEN val = 1 AND (prev_val = 0 OR prev_val IS NULL) THEN 1  -- rising edge
            ELSE 0
        END AS is_rising,
        CASE 
            WHEN val = 0 AND prev_val = 1 THEN 1  -- falling edge
            ELSE 0
        END AS is_falling
    FROM ch
),

-- Find interval starts (rising edges)
starts AS (
    SELECT
        Name,
        sig,
        t_stamp AS start_ts
    FROM edges
    WHERE is_rising = 1
),

-- Find interval ends (falling edges)
ends AS (
    SELECT
        Name,
        sig,
        t_stamp AS end_ts
    FROM edges
    WHERE is_falling = 1
),

-- Match each start with the next falling edge (or endTime if none exists)
intervals AS (
    SELECT
        s.Name,
        s.sig,
        s.start_ts,
        COALESCE(
            (SELECT MIN(e.end_ts) 
             FROM ends e 
             WHERE e.Name = s.Name 
               AND e.sig = s.sig 
               AND e.end_ts > s.start_ts),
            :endTime
        ) AS end_ts
    FROM starts s
),

-- Sum durations
dur AS (
    SELECT
        Name,
        SUM(CASE WHEN sig = 'Full'            THEN TIMESTAMPDIFF(SECOND, start_ts, end_ts) ELSE 0 END) AS Full_Duration_Sec,
        SUM(CASE WHEN sig = 'Half_Full'       THEN TIMESTAMPDIFF(SECOND, start_ts, end_ts) ELSE 0 END) AS Half_Full_Duration_Sec,
        SUM(CASE WHEN sig = 'Jam'             THEN TIMESTAMPDIFF(SECOND, start_ts, end_ts) ELSE 0 END) AS Jam_Duration_Sec,
        SUM(CASE WHEN sig = 'No_Container'    THEN TIMESTAMPDIFF(SECOND, start_ts, end_ts) ELSE 0 END) AS No_Container_Duration_Sec,
        SUM(CASE WHEN sig = 'Block_Operation' THEN TIMESTAMPDIFF(SECOND, start_ts, end_ts) ELSE 0 END) AS Block_Operation_Duration_Sec
    FROM intervals
    GROUP BY Name
)

SELECT
    :startTime AS `Start Time`,
    :endTime AS `End Time`,
    d.Name AS `Lane ID`,
    CASE 
        WHEN d.Name LIKE 'S01%' THEN 'S01'
        WHEN d.Name LIKE 'S02%' THEN 'S02'
        ELSE 'N/A'
    END AS `Sorter`,
    COALESCE(Full_Duration_Sec, 0) AS `Full Duration Sec`,
    COALESCE(Half_Full_Duration_Sec, 0) AS `Half Full Duration Sec`,
    COALESCE(Jam_Duration_Sec, 0) AS `Jam Duration Sec`,
    COALESCE(No_Container_Duration_Sec, 0) AS `No Container Duration Sec`,
    COALESCE(Block_Operation_Duration_Sec, 0) AS `Block Operation Duration Sec`
FROM dur d

UNION ALL

SELECT
    :startTime, :endTime,
    'N/A', 'N/A',
    0,0,0,0,0
WHERE NOT EXISTS (SELECT 1 FROM dur)

ORDER BY `Lane ID`;
