-- =============================================================================
-- Отчет повременного учета работоспособности периферийного оборудования
-- Период: май 2026
-- Исключены устройства, начинающиеся на IRZ
-- Тип оборудования берется из инвентаризации Zabbix (поле type)
-- Координаты: широта + долгота из полей location_lat и location_lon
-- =============================================================================


WITH 
-- 1. Получаем все проверки ICMP за период
checks AS (
    SELECT 
        h.host AS host_name,
        COALESCE(h.name, h.host) AS visible_name,
        -- Тип оборудования из инвентаризации (поле type), если пусто - берем hardware
        COALESCE(hinv."name", 'не указан') AS equipment_type,
        -- Номер объекта ИТС РО (храним в поле notes инвентаризации)
        COALESCE(hinv.notes, '') AS object_number,
        -- Координаты: объединяем широту и долготу через пробел
        CASE 
            WHEN hinv.location_lat IS NOT NULL AND hinv.location_lon IS NOT NULL 
                 AND hinv.location_lat != '' AND hinv.location_lon != ''
            THEN hinv.location_lat || ' ' || hinv.location_lon
            WHEN hinv.location_lat IS NOT NULL AND hinv.location_lat != '' 
            THEN hinv.location_lat
            WHEN hinv.location_lon IS NOT NULL AND hinv.location_lon != '' 
            THEN hinv.location_lon
            ELSE ''
        END AS coordinates,
        -- Время проверки с учетом часового пояса
        TO_TIMESTAMP(hx.clock) AT TIME ZONE 'Europe/Moscow' AS ts,
        -- Статус: 1 = доступно, 0 = недоступно
        hx.value AS status
    FROM hosts h
    INNER JOIN items i 
        ON i.hostid = h.hostid 
        AND i.key_ = 'icmpping'
        AND i.status = 0
        AND i.value_type = 3  -- unsigned numeric
    INNER JOIN history_uint hx 
        ON hx.itemid = i.itemid
    LEFT JOIN host_inventory hinv 
        ON hinv.hostid = h.hostid
    WHERE 
        -- Только мониторимые хосты
        h.status = 0
        and COALESCE(h.name, h.host) not like '%WIMAX'
        -- Исключаем оборудование, начинающееся на IRZ (любой регистр)
        -- AND UPPER(h.host) NOT LIKE 'IRZ%'
        -- Период: май 2026 года (измените под свои даты)
        and hinv.notes is not null and hinv.notes <> ''
        --and hinv.notes = 'ОБЪЕКТ № 67' --and hinv.name like '%Маршрутизатор%'
        and CAST(nullif(regexp_replace(hinv.notes, 'ОБЪЕКТ №\s*', '', 'g'),'') as INTEGER) 
        --between 1 and 85
        in (1,2,4,5,8,9,11,12,14,24,25,27,28,29,30,31,32,34,35,36,38,40,41,42,43,44,45,46,48,49,50,51,53,54,55,57,58,60,62,63,64,65,66,67,68,69,70,76,77,81,82,84,85) 
        --AND hx.clock >= EXTRACT(EPOCH FROM TIMESTAMP '2026-06-01 00:00:00')
        --AND hx.clock < EXTRACT(EPOCH FROM TIMESTAMP '2026-06-05 00:00:00')
        AND TO_TIMESTAMP(hx.clock) >= to_date(${start_dt}, 'yyyymmdd') - interval '1 day'
        AND TO_TIMESTAMP(hx.clock) <= to_date(${end_dt}, 'yyyymmdd') + interval '1 day'  
), -- 2. Добавляем предыдущий статус для определения моментов смены
checks_with_prev AS (
    SELECT 
        *,
        LAG(status) OVER (PARTITION BY host_name ORDER BY ts) AS prev_status,
        coalesce(lead(ts) OVER (PARTITION BY host_name ORDER BY ts), date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + interval '1 month') AS next_ts
    FROM checks
),  --3. Определяем моменты смены статуса (начало нового интервала)
status_changes AS (
    SELECT 
        host_name,
	    visible_name,
	    equipment_type,
	    object_number,
	    coordinates,
	    ts,
	    status, 
	    prev_status,
	    case 
		    when DATE(next_ts) > DATE(ts) then date_trunc('day', next_ts) + interval '00:00:00'
	    	else next_ts - interval '1 sec'
	    end as next_ts, 
	    case 
		    when DATE(next_ts) > DATE(ts) then date_trunc('day', next_ts) + interval '00:00:00'
	    	else next_ts 
	    end as next_check_time, 
        CASE WHEN status != prev_status THEN 1 
            ELSE 0 
        END AS is_start
    FROM checks_with_prev
    union all 
    SELECT
	    host_name,
	    visible_name,
	    equipment_type,
	    object_number,
	    coordinates,
	    date_trunc('day', next_ts) + interval '00:00:00' as ts,
	    status, 
	    prev_status,
	    next_ts - interval '1 sec' as next_ts,
	    next_ts as next_check_time, 
	    1 as is_start
     FROM checks_with_prev
     where DATE(next_ts) > DATE(ts) 
), -- 4. Нумеруем интервалы для каждого устройства
intervals AS (
    SELECT 
        *,
        SUM(is_start) OVER (PARTITION BY host_name ORDER BY ts) AS interval_id
    FROM status_changes
    WHERE status IS NOT null
    and date_trunc('day', ts) >= to_date(${start_dt}, 'yyyymmdd') and date_trunc('day', ts) <= to_date(${end_dt}, 'yyyymmdd')
), -- 5. Агрегируем каждый непрерывный интервал
grouped_intervals AS (
    SELECT 
        host_name,
        visible_name,
        equipment_type,
        object_number,
        coordinates,
        max(regexp_replace(object_number, 'ОБЪЕКТ №\s*', '', 'g'))::int as object_num,
        MIN(ts) AS time_start,
        MAX(next_ts) AS time_end,
        MAX(next_check_time) AS time_end_all,
        MAX(status) AS status
    FROM intervals
    GROUP BY 
        host_name, 
        visible_name,
        equipment_type,
        object_number,
        coordinates,
        interval_id
), -- 5_1. Определение маршрутизатора (заглушка)
router as 
(
	select  
		m.host_name,
        m.visible_name,
        m.equipment_type,
        v.object_number,
        v.coordinates,
        v.object_num,
        v.time_start,
        v.time_end,
        v.time_end_all,
        v.status
	from grouped_intervals v 
	join 
	(
		select host_name, visible_name, object_number, equipment_type, date_trunc('day', time_start) as time_start_dt, object_num
		from grouped_intervals 
		where equipment_type like 'Маршрутизатор%'
		group by 1,2,3,4,5,6
	) m on m.object_num = v.object_num
	where v.equipment_type like 'Видеокамера%'
		and time_start_dt = date_trunc('day', v.time_start)
), union_zab as 
(
	select *
		, case 			
			when equipment_type like 'Метеостанция%' then '1'
			when equipment_type like 'Видеокамера%' then '2'
			when equipment_type like 'Маршрутизатор%' then '3'
			when object_num = 38 and  equipment_type like 'Детектор транспортных потоков CTfind DTM 1' then 'Детектор транспортных потоков №1'
			when object_num = 38 and  equipment_type like 'Детектор транспортных потоков CTfind DTM 2' then 'Детектор транспортных потоков №2'
			else equipment_type
		end as equipment_id 
		, DATE(time_start) AS date_check
		, row_number() over(partition by DATE(time_start), object_num, equipment_type order by time_start desc) as rn
	from  
	(
		select *  from grouped_intervals where equipment_type not like 'Маршрутизатор%'
		union all
		select * from router
	) u  
), sum_interval as 
(
	select 
	    equipment_id,
	    object_num,
	    date_check,		    
	    case 
			when available_hours = '1 day' then '24:00:00'::interval
	        else available_hours::interval
	   	end as available_hours
	from 
	(
		SELECT 
	    	equipment_id,
	    	object_num,
			date_check, 
		    sum(time_end_all - time_start) AS available_hours 
		FROM union_zab u
		where status = 1 
		GROUP BY equipment_id, object_num, date_check
	) s
), gant as 
(	
	select DATE(date_check) as date_check, object_name, equipment_type, coordinates
		, regexp_replace(object_name, 'ОБЪЕКТ №\s*', '', 'g')::int as object_num
		, case 			
			when equipment_type like 'Метеостанция%' then '1'
			when equipment_type like 'Видеокамера%' then '2'
			when equipment_type like 'Роутер%' then '3'
			else equipment_type
		end as equipment_id
		, time_start as sum_hours
        , coalesce(LPAD(FLOOR(time_start)::INT::TEXT, 2, '0') || ':' ||
        	LPAD(FLOOR((time_start- FLOOR(time_start)::INT) * 60)::INT::TEXT, 2, '0') || ':' ||
        	LPAD(ROUND(((time_start - FLOOR(time_start)::INT) * 60 - FLOOR((time_start- FLOOR(time_start)::INT) * 60)::INT) * 60)::INT::TEXT, 2, '0'), '00:00:00')::interval as aval
	from 
	(
		select object_name, equipment_type, d01 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) as date_check from gantt_contractor 
		union all 
		select object_name, equipment_type, d02 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '1 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d03 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '2 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d04 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '3 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d05 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '4 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d06 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '5 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d07 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '6 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d08 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '7 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d09 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '8 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d10 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '9 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d11 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '10 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d12 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '11 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d13 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '12 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d14 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '13 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d15 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '14 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d16 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '15 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d17 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '16 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d18 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '17 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d19 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '18 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d20 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '19 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d21 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '20 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d22 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '21 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d23 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '22 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d24 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '23 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d25 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '24 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d26 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '25 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d27 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '26 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d28 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '27 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d29 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '28 day'from gantt_contractor 
		union all 
		select object_name, equipment_type, d30 as time_start, coordinates, date_trunc('month', to_date(${start_dt}, 'yyyymmdd')) + INTERVAL '29 day'from gantt_contractor 
	) g 	
	where date_check >= to_date(${start_dt}, 'yyyymmdd') and date_check <= to_date(${end_dt}, 'yyyymmdd')
), gant_interval as 
(
	select date_check, object_name, equipment_type, object_num, equipment_id, coordinates
		, 1 as status, INTERVAL '00:00:00' as time_start_tm, INTERVAL '24:00:00' as time_end_tm
	from gant 
	where sum_hours = 24
	union all
	select date_check, object_name, equipment_type, object_num, equipment_id, coordinates
		, 1 as status, INTERVAL '00:00:00' as time_start_tm, aval::interval as time_end_tm
	from gant 
	where sum_hours > 0 and sum_hours < 24
	union all
	select date_check, object_name, equipment_type, object_num, equipment_id, coordinates
		, 0 as status, aval::interval + INTERVAL '1 second' as time_start_tm, INTERVAL '00:00:00' as time_end_tm
	from gant 
	where sum_hours > 0 and sum_hours < 24
	union all
	select date_check, object_name, equipment_type, object_num, equipment_id, coordinates
		, 0 as status, INTERVAL '00:00:00' as time_start_tm, INTERVAL '24:00:00' as time_end_tm
	from gant 
	where sum_hours = 0
	union all
	select date_check, object_name, equipment_type, object_num, equipment_id, coordinates
		, 0 as status, aval::interval, aval::interval
	from gant 
	where sum_hours is null
), gener as 
(
	select g.*, i.available_hours, g.time_end_tm - i.available_hours as diff_tm
		, case when g.time_end_tm > i.available_hours then 1 else 0 end as diff_fl
	from gant_interval g
	left join sum_interval i on g.object_num = i.object_num 
		and g.equipment_id = i.equipment_id
		and g.date_check = i.date_check
	where abs(extract('minute' from g.time_end_tm - i.available_hours)::int) > 5
		and g.status = 1 
	union all 
	select g.*, i.available_hours, INTERVAL '00:00:00' as diff_tm, null as diff_fl
	from gant_interval g
	left join sum_interval i on g.object_num = i.object_num 
		and g.equipment_id = i.equipment_id
		and g.date_check = i.date_check
	where i.available_hours is null
), gener_gant_interval as 
(
	select gi.date_check, g.equipment_id, g.object_num, z.status
		, case 
			when z.status = 1 and z.rn = 1 then z.time_start - DATE_trunc('day', z.time_start) - diff_tm
			when z.status = 0 and z.rn = 2 then z.time_start - DATE_trunc('day', z.time_start) 
			when z.status = 0 and z.rn = 1 then z.time_start - DATE_trunc('day', z.time_start) - diff_tm
			when z.status = 1 and z.rn = 2 then z.time_start - DATE_trunc('day', z.time_start) 
			else z.time_start - DATE_trunc('day', z.time_start)
		end as time_start_tm
		, case 
			when z.status = 1 and z.rn = 1 then z.time_end - DATE_trunc('day', z.time_end)
			when z.status = 0 and z.rn = 2 then z.time_end - DATE_trunc('day', z.time_end) - diff_tm
			when z.status = 0 and z.rn = 1 then z.time_end - DATE_trunc('day', z.time_end)
			when z.status = 1 and z.rn = 2 then z.time_end - DATE_trunc('day', z.time_end) - diff_tm
			else z.time_end - DATE_trunc('day', z.time_end)
		end as time_end_tm
	from gener g 
	join gant_interval gi on g.object_num = gi.object_num and g.equipment_id = gi.equipment_id and g.date_check = gi.date_check	
	join union_zab z  on g.object_num = z.object_num and g.equipment_id = z.equipment_id and g.date_check = z.date_check	
	where g.diff_fl = 1 --в zabbix <
	union
	select gi.date_check, g.equipment_id, g.object_num, z.status
		, case 
			when z.status = 1 and z.rn = 1 then z.time_start - DATE_trunc('day', z.time_start) + diff_tm
			when z.status = 0 and z.rn = 2 then z.time_start - DATE_trunc('day', z.time_start) 
			when z.status = 0 and z.rn = 1 then z.time_start - DATE_trunc('day', z.time_start) + diff_tm
			when z.status = 1 and z.rn = 2 then z.time_start - DATE_trunc('day', z.time_start) 
			else z.time_start - DATE_trunc('day', z.time_start)
		end as time_start_tm
		, case 
			when z.status = 1 and z.rn = 1 then z.time_end - DATE_trunc('day', z.time_end)
			when z.status = 0 and z.rn = 2 then z.time_end - DATE_trunc('day', z.time_end) + diff_tm
			when z.status = 0 and z.rn = 1 then z.time_end - DATE_trunc('day', z.time_end)
			when z.status = 1 and z.rn = 2 then z.time_end - DATE_trunc('day', z.time_end) + diff_tm
			else z.time_end - DATE_trunc('day', z.time_end)
		end as time_end_tm
	from gener g 
	join gant_interval gi on g.object_num = gi.object_num and g.equipment_id = gi.equipment_id and g.date_check = gi.date_check	
	join union_zab z  on g.object_num = z.object_num and g.equipment_id = z.equipment_id and g.date_check = z.date_check	
	where g.diff_fl = 0 --в zabbix >
), main as 
(
	select g.date_check as date_check
		, coalesce(u.object_num, g.object_num) as object_num
		, coalesce(u.equipment_id, g.equipment_id) as equipment_id
		, coalesce(u.equipment_type, g.equipment_type) as equipment_type
		, coalesce(u.object_number, g.object_name) as object_name
		, greatest(u.coordinates::varchar, g.coordinates::varchar) as coordinates
	from gant g
	left join union_zab u on u.object_num = g.object_num 
			and g.equipment_id = u.equipment_id
	group by 1,2,3,4,5,6
)
-- 6. Финальный вывод отчета
SELECT 
    ROW_NUMBER() OVER (order by m.date_check, m.object_num nulls last, m.equipment_type, u.time_start) AS "№ п/п",
    TO_CHAR(DATE(m.date_check), 'DD.MM.YYYY') AS "Дата",
    m.equipment_type as "Тип оборудования",
    m.object_name  as "Номер_объекта_ИТС_РО",
    m.coordinates as "Координаты_расположения",
    TO_CHAR(u.time_start, 'HH24:MI:SS') AS "Время начала статуса",
    TO_CHAR(u.time_end, 'HH24:MI:SS') as "Время окончания статуса",
    CASE 
        WHEN u.status = 1 THEN 'доступно'
        ELSE 'недоступно'
    END AS "Статус"
FROM main m
join 
(
	select *
	from 
	(
		select gi.date_check, gi.equipment_id, gi.object_num, gi.status, gi.time_start_tm as time_start, gi.time_end_tm as time_end
		from gener g 
		join gant_interval gi on g.object_num = gi.object_num and g.equipment_id = gi.equipment_id and g.date_check = gi.date_check		
		where g.diff_fl is null
		union all
		select date_check, equipment_id, object_num, status, time_start_tm, time_end_tm
		from gener_gant_interval 
		union all
		select uz.date_check, uz.equipment_id, uz.object_num, uz.status, uz.time_start - DATE_trunc('day', uz.time_start), uz.time_end - DATE_trunc('day', uz.time_start)
		from union_zab uz
		left join gener_gant_interval ggi on uz.object_num = ggi.object_num and uz.equipment_id = ggi.equipment_id and uz.date_check = ggi.date_check
		where ggi.date_check is null
	) r
) u on m.object_num = u.object_num and m.equipment_id = u.equipment_id and m.date_check = u.date_check
ORDER BY 1
;