WITH DISABLE_EVENTS AS (
	/* Group related active & clear events into a single row */
	SELECT
		id,
		NOT eventtype AS eventtype,
		IF(eventtype = 1, COALESCE(LEAD(eventid, 1) OVER w, source), eventid) AS eventid,
		source, /* Unique alarm path in Ignition */
        eventtime,
		displaypath /* Get description */
	FROM alarm_events
	/* The range for both start/end allows for index optimizations */
	WHERE eventtime BETWEEN (:startDate - INTERVAL 4 DAY) AND (:endDate + INTERVAL 4 DAY)
	  /* Filter for disabled messages, full messages, and jam messages */
	  AND displaypath = "HMI Chute Disabled"
      AND (source LIKE "%MCP05/%" or source LIKE "%MCP06/%")
	  /* Filter out system events and filter for active/clear events only */
	  AND eventflags & 1 != 1 AND eventtype IN (0, 1)
    WINDOW w AS (PARTITION BY source ORDER BY eventtime ASC)
), ENABLES AS (
	/* Group related active & clear events into a single row */
	SELECT
		eventid,
		SUBSTRING_INDEX(ANY_VALUE(ddevice.strvalue), '.', 1) AS lane,
        GREATEST(COALESCE(MIN(IF(eventtype=0, eventtime, NULL)), (:startDate - INTERVAL 4 DAY)), :startDate) AS starttime,
        LEAST(COALESCE(MAX(IF(eventtype=1, eventtime, NULL)), LEAST(NOW(), (:endDate + INTERVAL 4 DAY))), :endDate) AS endtime,
		ANY_VALUE(displaypath) AS displaypath /* Get description */
	FROM DISABLE_EVENTS e
	JOIN alarm_event_data ddevice ON e.id = ddevice.id AND ddevice.propname = "Device"
	GROUP BY eventid
    HAVING endtime >= :startDate AND starttime <= :endDate
	ORDER BY starttime ASC
), STATES AS (
	/* Group related active & clear events into a single row */
	SELECT
		eventid,
		SUBSTRING_INDEX(ANY_VALUE(ddevice.strvalue), '.', 1) AS lane,
        GREATEST(COALESCE(MIN(IF(eventtype=0, eventtime, NULL)), (:startDate - INTERVAL 4 DAY)), :startDate) AS starttime,
        LEAST(COALESCE(MAX(IF(eventtype=1, eventtime, NULL)), LEAST(NOW(), (:endDate + INTERVAL 4 DAY))), :endDate) AS endtime,
		ANY_VALUE(displaypath) AS displaypath /* Get description */
	FROM alarm_events e
	JOIN alarm_event_data ddevice ON e.id = ddevice.id AND ddevice.propname = "Device"
	/* The range for both start/end allows for index optimizations */
	WHERE eventtime BETWEEN (:startDate - INTERVAL 4 DAY) AND (:endDate + INTERVAL 4 DAY)
	  /* Filter for disabled messages, full messages, and jam messages */
	  AND displaypath IN ("Full", "Full Warn", "25% Full Warn", "50% Full Warn", "75% Full Warn", "Jammed", "EStop or Faulted", "Extend PX Faulted", "Retract PX Faulted")
      AND (source LIKE "%MCP05/%" or source LIKE "%MCP06/%")
	  /* Filter out system events and clear events only */
	  AND eventflags & 1 != 1 AND eventtype IN (0, 1)
	GROUP BY eventid
    HAVING endtime >= :startDate AND starttime <= :endDate
), COMBINED AS (
	SELECT
		/* Meta */
		MIN(LEAST(e.starttime, COALESCE(s.starttime, e.starttime))) AS firsttime, /* Get the earliest it's been active in the given time range */
		MAX(GREATEST(e.endtime, COALESCE(s.endtime, e.endtime))) AS lasttime, /* Get the latest it's been active in the given time range */
		MAX(e.lane) AS lane, /* Use latest id to get the latest metadata */
		/* Durations */
		TIME_TO_SEC(TIMEDIFF(e.endtime, e.starttime)) AS enabled_duration,
		SUM(IF(s.displaypath="25% Full Warn", TIME_TO_SEC(TIMEDIFF(LEAST(e.endtime, s.endtime), GREATEST(e.starttime, s.starttime))), 0)) AS full25_duration,
		SUM(IF(s.displaypath IN ("Full Warn", "50% Full Warn"), TIME_TO_SEC(TIMEDIFF(LEAST(e.endtime, s.endtime), GREATEST(e.starttime, s.starttime))), 0)) AS full50_duration,
		SUM(IF(s.displaypath="75% Full Warn", TIME_TO_SEC(TIMEDIFF(LEAST(e.endtime, s.endtime), GREATEST(e.starttime, s.starttime))), 0)) AS full75_duration,
		SUM(IF(s.displaypath="Full", TIME_TO_SEC(TIMEDIFF(LEAST(e.endtime, s.endtime), GREATEST(e.starttime, s.starttime))), 0)) AS full100_duration,
		SUM(IF(s.displaypath="Jammed", TIME_TO_SEC(TIMEDIFF(LEAST(e.endtime, s.endtime), GREATEST(e.starttime, s.starttime))), 0)) AS jammed_duration,
		SUM(IF(s.displaypath IN ("EStop or Faulted", "Extend PX Faulted", "Retract PX Faulted"), TIME_TO_SEC(TIMEDIFF(LEAST(e.endtime, s.endtime), GREATEST(e.starttime, s.starttime))), 0)) AS faulted_duration#,
		/* Max Durations */
		#TIME_TO_SEC(TIMEDIFF(e.endtime, e.starttime)) AS enabled_duration_max,
		#MAX(IF(s.displaypath="25% Full Warn", TIME_TO_SEC(TIMEDIFF(LEAST(e.endtime, s.endtime), GREATEST(e.starttime, s.starttime))), 0)) AS full25_duration_max,
		#MAX(IF(s.displaypath IN ("Full Warn", "50% Full Warn"), TIME_TO_SEC(TIMEDIFF(LEAST(e.endtime, s.endtime), GREATEST(e.starttime, s.starttime))), 0)) AS full50_duration_max,
		#MAX(IF(s.displaypath="75% Full Warn", TIME_TO_SEC(TIMEDIFF(LEAST(e.endtime, s.endtime), GREATEST(e.starttime, s.starttime))), 0)) AS full75_duration_max,
		#MAX(IF(s.displaypath="Full", TIME_TO_SEC(TIMEDIFF(LEAST(e.endtime, s.endtime), GREATEST(e.starttime, s.starttime))), 0)) AS full100_duration_max,
		#MAX(IF(s.displaypath="Jammed", TIME_TO_SEC(TIMEDIFF(LEAST(e.endtime, s.endtime), GREATEST(e.starttime, s.starttime))), 0)) AS jammed_duration_max,
		#MAX(IF(s.displaypath IN ("EStop or Faulted", "Extend PX Faulted", "Retract PX Faulted"), TIME_TO_SEC(TIMEDIFF(LEAST(e.endtime, s.endtime), GREATEST(e.starttime, s.starttime))), 0)) AS faulted_duration_max
	FROM ENABLES e
	LEFT JOIN STATES s ON e.lane = s.lane AND e.starttime <= s.endtime AND e.endtime >= s.starttime
	GROUP BY e.eventid
)
SELECT
	DATE_FORMAT(MIN(firsttime), '%Y-%m-%d %T') AS firsttime,
    DATE_FORMAT(MAX(lasttime), '%Y-%m-%d %T') AS lasttime,
	lane,
    CAST(SEC_TO_TIME(SUM(enabled_duration)) AS CHAR) AS enabled_duration,
    CAST(SEC_TO_TIME(SUM(enabled_duration - full100_duration - jammed_duration - faulted_duration)) AS CHAR) AS available_duration,
    CAST(SEC_TO_TIME(SUM(enabled_duration - full25_duration - full50_duration - full75_duration - full100_duration - jammed_duration - faulted_duration)) AS CHAR) AS empty_duration,
	CAST(SEC_TO_TIME(SUM(full25_duration)) AS CHAR) AS full25_duration,
	CAST(SEC_TO_TIME(SUM(full50_duration)) AS CHAR) AS full50_duration,
	CAST(SEC_TO_TIME(SUM(full75_duration)) AS CHAR) AS full75_duration,
	CAST(SEC_TO_TIME(SUM(full100_duration)) AS CHAR) AS full100_duration,
	CAST(SEC_TO_TIME(SUM(jammed_duration)) AS CHAR) AS jammed_duration,
	CAST(SEC_TO_TIME(SUM(faulted_duration)) AS CHAR) AS faulted_duration,
    /* Inbound OEE (Loop's Efficiency) wants to have 25%/50%/75%/100% full all the time ==> 100% */
    /* (Full25 + Full50 + Full75 + Full100) / (Enabled - Jammed - Faulted) */
    SUM(full25_duration + full50_duration + full75_duration + full100_duration) / SUM(enabled_duration - jammed_duration - faulted_duration) AS inbound_oee,
    /* Induct OEE (Operator's Efficiency) wants to have Empty or 25%/50%/75% full all the time ==> 100%, and is penalized for the time with active jams */
    /* (Empty + Full25 + Full50 + Full75) / (Enabled - Faulted) */
    SUM((enabled_duration - full100_duration - jammed_duration - faulted_duration)) / SUM(enabled_duration - faulted_duration) AS induct_oee
FROM COMBINED c
GROUP BY lane
ORDER BY lane;