-- drop dependent views
drop view v_vehiclepositions_alerts_last_position;
drop view v_vehiclepositions_all_processed_positions;
drop view v_vehiclepositions_all_trips_with_last_position;
drop view v_vehiclepositions_stop_time_delay_prediction;


-- common run messages
alter table vehiclepositions_runs_messages alter column actual_stop_timestamp_real type bigint using extract(epoch from actual_stop_timestamp_real) * 1000;
alter table vehiclepositions_runs_messages alter column actual_stop_timestamp_scheduled type bigint using extract(epoch from actual_stop_timestamp_scheduled) * 1000;


-- vp trips (+ history)
alter table vehiclepositions_trips alter column end_timestamp type bigint using extract(epoch from end_timestamp) * 1000;
alter table vehiclepositions_trips alter column start_timestamp type bigint using extract(epoch from start_timestamp) * 1000;
alter table vehiclepositions_trips_history alter column end_timestamp type bigint using extract(epoch from end_timestamp) * 1000;
alter table vehiclepositions_trips_history alter column start_timestamp type bigint using extract(epoch from start_timestamp) * 1000;


-- vp positions (+ history)
alter table vehiclepositions_positions alter column last_stop_arrival_time type bigint using extract(epoch from last_stop_arrival_time) * 1000;
alter table vehiclepositions_positions alter column last_stop_departure_time type bigint using extract(epoch from last_stop_departure_time) * 1000;
alter table vehiclepositions_positions alter column next_stop_arrival_time type bigint using extract(epoch from next_stop_arrival_time) * 1000;
alter table vehiclepositions_positions alter column next_stop_departure_time type bigint using extract(epoch from next_stop_departure_time) * 1000;
alter table vehiclepositions_positions alter column origin_timestamp type bigint using extract(epoch from origin_timestamp) * 1000;
alter table vehiclepositions_positions alter column scheduled_timestamp type bigint using extract(epoch from scheduled_timestamp) * 1000;
alter table vehiclepositions_positions alter column valid_to type bigint using extract(epoch from valid_to) * 1000;
alter table vehiclepositions_positions_history alter column last_stop_arrival_time type bigint using extract(epoch from last_stop_arrival_time) * 1000;
alter table vehiclepositions_positions_history alter column last_stop_departure_time type bigint using extract(epoch from last_stop_departure_time) * 1000;
alter table vehiclepositions_positions_history alter column next_stop_arrival_time type bigint using extract(epoch from next_stop_arrival_time) * 1000;
alter table vehiclepositions_positions_history alter column next_stop_departure_time type bigint using extract(epoch from next_stop_departure_time) * 1000;
alter table vehiclepositions_positions_history alter column origin_timestamp type bigint using extract(epoch from origin_timestamp) * 1000;
alter table vehiclepositions_positions_history alter column scheduled_timestamp type bigint using extract(epoch from scheduled_timestamp) * 1000;
alter table vehiclepositions_positions_history alter column valid_to type bigint using extract(epoch from valid_to) * 1000;


-- functions
drop function convert_timestamptz_to_iso_string (timestamptz, varchar);
create function convert_timestamp_ms_to_iso_string(timestamp_ms bigint, timezone varchar DEFAULT 'Europe/Prague') RETURNS varchar AS $$
    select TO_CHAR(DATE_TRUNC('second', TO_TIMESTAMP(timestamp_ms / 1000)) at TIME zone timezone, 'YYYY-MM-DD"T"HH24:MI:SS') || replace('+' || to_char(DATE_TRUNC('second', TO_TIMESTAMP(timestamp_ms / 1000)) at TIME zone timezone - DATE_TRUNC('second', TO_TIMESTAMP(timestamp_ms / 1000)) at TIME zone 'UTC', 'HH24:MMFM'), '+-', '-')
$$ LANGUAGE SQL IMMUTABLE;

CREATE or replace PROCEDURE vehiclepositions_data_retention(inout numberOfRows int, in dataRetentionMinutes int)
LANGUAGE plpgsql
AS $procedure$
	declare
		idsForDelete varchar(255)[];
	begin
        select array_agg(t.id) from pid.vehiclepositions_trips t
        left join pid.vehiclepositions_positions p on
            p.id = t.last_position_id
        where
            p.valid_to/1000 < extract(epoch from (NOW() - (dataRetentionMinutes || ' minutes')::interval))
            or (gtfs_trip_id is null and p.created_at < NOW() - (dataRetentionMinutes || ' minutes')::interval) -- entries with valid to is null
		into idsForDelete;

		INSERT INTO pid.vehiclepositions_trips_history
		select * from pid.vehiclepositions_trips where id = ANY(idsForDelete)
		on conflict do nothing;

		INSERT INTO pid.vehiclepositions_positions_history
		select * from pid.vehiclepositions_positions where trips_id = ANY(idsForDelete)
		on conflict do nothing;

		delete from pid.vehiclepositions_positions where trips_id = ANY(idsForDelete);
		delete from pid.vehiclepositions_trips where id = ANY(idsForDelete);

		select array_length(idsForDelete,1) into numberOfRows;
	end;
$procedure$;


-- recreate views
create view v_vehiclepositions_alerts_last_position as
  SELECT t2.created_at,
    t2.updated_at,
    t2.delay,
    t2.delay_stop_arrival,
    t2.delay_stop_departure,
    t2.next_stop_id,
    t2.shape_dist_traveled,
    t2.is_canceled,
    t2.lat,
    t2.lng,
    t2.origin_time,
    t2.origin_timestamp,
    t2.tracking,
    t2.trips_id,
    t2.create_batch_id,
    t2.created_by,
    t2.update_batch_id,
    t2.updated_by,
    t2.id,
    t2.bearing,
    t2.cis_last_stop_id,
    t2.cis_last_stop_sequence,
    t2.last_stop_id,
    t2.last_stop_sequence,
    t2.next_stop_sequence,
    t2.speed,
    t2.last_stop_arrival_time,
    t2.last_stop_departure_time,
    t2.next_stop_arrival_time,
    t2.next_stop_departure_time,
    t2.asw_last_stop_id,
    t1.gtfs_route_id,
    t1.gtfs_route_short_name,
    t1.gtfs_route_type,
    t1.gtfs_trip_id,
    t1.gtfs_trip_headsign,
    t1.vehicle_type_id,
    t1.wheelchair_accessible
   FROM (vehiclepositions_trips t1
     LEFT JOIN vehiclepositions_positions t2 ON ((t1.last_position_id = t2.id)))
  WHERE ((t2.updated_at > (now() - '00:10:00'::interval)) AND ((t2.state_position)::text = ANY (ARRAY[('on_track'::character varying)::text, ('off_track'::character varying)::text, ('at_stop'::character varying)::text, ('before_track'::character varying)::text, ('after_track'::character varying)::text, ('canceled'::character varying)::text])))
  ORDER BY t2.trips_id, t2.updated_at DESC;

comment on view v_vehiclepositions_alerts_last_position is '
Used only for alerting purposes.
';


create view v_vehiclepositions_all_processed_positions as
select
    trips_id,
	bearing,
	"delay",
	delay_stop_arrival,
	delay_stop_departure,
	vp.is_canceled,
    convert_timestamp_ms_to_iso_string(last_stop_arrival_time) as last_stop_arrival_time_isostring,
	convert_timestamp_ms_to_iso_string(last_stop_departure_time) as last_stop_departure_time_isostring,
	last_stop_id,
	last_stop_sequence,
	lat,
	lng,
    convert_timestamp_ms_to_iso_string(next_stop_arrival_time) as next_stop_arrival_time_isostring,
	convert_timestamp_ms_to_iso_string(next_stop_departure_time) as next_stop_departure_time_isostring,
	next_stop_id,
	next_stop_sequence,
	convert_timestamp_ms_to_iso_string(origin_timestamp) as origin_timestamp_isostring,
	shape_dist_traveled,
	speed,
    state_position
from
	vehiclepositions_positions vp
where state_process = 'processed';

comment on view v_vehiclepositions_all_processed_positions is '
View of all processed positions. Used for enriching trips from v_vehiclepositions_all_trips_with_last_position with all positions.
';


create view v_vehiclepositions_all_trips_with_last_position as
select
    vt.id,
	vt.agency_name_real,
	vt.agency_name_scheduled,
	vt.cis_line_id,
	vt.cis_trip_number,
	vt.gtfs_route_id,
	vt.gtfs_route_short_name,
	vt.gtfs_route_type,
	vt.gtfs_trip_headsign,
	vt.gtfs_trip_short_name,
	vt.gtfs_trip_id,
	vt.origin_route_name,
	vt.run_number,
	vt.vehicle_registration_number,
    vt.vehicle_type_id,
    vt.wheelchair_accessible,
    vt.updated_at,
	convert_timestamp_ms_to_iso_string(vt.start_timestamp) as start_timestamp_isostring,
	vp.bearing,
	vp.delay,
	vp.delay_stop_arrival,
	vp.delay_stop_departure,
	vp.is_canceled,
	vp.last_stop_id,
	vp.last_stop_sequence,
    vp.last_stop_headsign,
    vp.lat,
    vp.lng,
	vp.next_stop_id,
	vp.next_stop_sequence,
	vp.shape_dist_traveled,
	vp.speed,
	vp.state_position,
	vp.tracking,
	convert_timestamp_ms_to_iso_string(vp.last_stop_arrival_time) as last_stop_arrival_time_isostring,
	convert_timestamp_ms_to_iso_string(vp.last_stop_departure_time) as last_stop_departure_time_isostring,
	convert_timestamp_ms_to_iso_string(vp.next_stop_arrival_time) as next_stop_arrival_time_isostring,
	convert_timestamp_ms_to_iso_string(vp.next_stop_departure_time) as next_stop_departure_time_isostring,
	convert_timestamp_ms_to_iso_string(vp.origin_timestamp) as origin_timestamp_isostring
from
	vehiclepositions_trips vt
inner join vehiclepositions_positions vp on
	vt.last_position_id = vp.id
	and (vp.valid_to is null
		or vp.valid_to >= extract(epoch from now()) * 1000)
	and vp.state_process = 'processed';

comment on view v_vehiclepositions_all_trips_with_last_position is '
View of all trips with last processed position. Used for serving data to the vehiclepositions output API.
';


create view v_vehiclepositions_stop_time_delay_prediction as
with recursive stop_times as (
    select
    	rst.trip_id,
        vt.provider_source_type,
    	vp.delay,
    	coalesce(vp.last_stop_sequence, 1) as initial_stop_sequence,
        vp.state_position,
    	rst.stop_sequence,
    	rst.stop_id,
    	rst.computed_dwell_time_seconds,
    	case when vp.last_stop_sequence is null
            then vp.delay
            else vp.delay_stop_arrival
        end as arrival_delay_seconds,
    	case when vp.last_stop_sequence is null
            then predict_delay_seconds(vp.delay, rst.computed_dwell_time_seconds, vt.provider_source_type)
            when vp.state_position = 'at_stop'
                then case when vt.provider_source_type = '1' then greatest(0, vp.delay) else vp.delay end
            else vp.delay_stop_departure
        end as departure_delay_seconds
    from ropidgtfs_stop_times rst
    inner join vehiclepositions_trips vt on vt.gtfs_trip_id = rst.trip_id
    inner join vehiclepositions_positions vp on vp.id = vt.last_position_id
        and (vp.valid_to is null or vp.valid_to >= extract(epoch from now()) * 1000)
    where
        vt.gtfs_trip_id is not null
        and rst.stop_sequence = coalesce(vp.last_stop_sequence, 1)
union all
    select
    	rst.trip_id,
        previous_row.provider_source_type,
    	previous_row.delay,
    	previous_row.initial_stop_sequence,
        previous_row.state_position,
    	rst.stop_sequence,
    	rst.stop_id,
    	rst.computed_dwell_time_seconds,
    	case when rst.stop_sequence - previous_row.initial_stop_sequence = 1 and previous_row.state_position != 'at_stop'
            then previous_row.delay
            else previous_row.departure_delay_seconds
        end as arrival_delay_seconds,
        predict_delay_seconds(
            case when rst.stop_sequence - previous_row.initial_stop_sequence = 1 and previous_row.state_position != 'at_stop' then previous_row.delay else previous_row.departure_delay_seconds end,
            rst.computed_dwell_time_seconds,
            previous_row.provider_source_type
        ) as departure_delay_seconds
    from stop_times previous_row
    inner join ropidgtfs_stop_times rst on rst.trip_id = previous_row.trip_id and rst.stop_sequence = previous_row.stop_sequence + 1
)
select trip_id, stop_sequence, stop_id, arrival_delay_seconds, departure_delay_seconds
from stop_times
order by trip_id, stop_sequence;

comment on view v_vehiclepositions_stop_time_delay_prediction is '
This view contains the predicted delay of a vehicle at each stop.
';
