create or replace function ems.fn_site_notifications_context(p_site_id int)
returns jsonb
language sql
stable
as $fn$
  select
    case
      when not exists (select 1 from ems.site s0 where s0.id = p_site_id) then
        jsonb_build_object('error', 'not_found')
      else jsonb_build_object(
        'timezone',
        coalesce(
          nullif(trim((select s.timezone from ems.site s where s.id = p_site_id)), ''),
          'Europe/Prague'
        ),
        'mode_code',
        (select m.mode_code from ems.site_operating_mode m where m.site_id = p_site_id),
        'has_plan',
        exists (
          select 1
          from ems.planning_run pr
          where pr.site_id = p_site_id
            and pr.status = 'active'
        ),
        'tomorrow_slots',
        (
          select count(*)::int
          from ems.vw_site_effective_price v
          where v.site_id = p_site_id
            and (v.interval_start at time zone coalesce(
              nullif(trim((select s2.timezone from ems.site s2 where s2.id = p_site_id)), ''),
              'Europe/Prague'
            ))::date = (
              (
                current_timestamp at time zone coalesce(
                  nullif(trim((select s3.timezone from ems.site s3 where s3.id = p_site_id)), ''),
                  'Europe/Prague'
                )
              )::date + 1
            )
        ),
        'reserve_soc',
        (select min(ab.reserve_soc_percent)::float from ems.asset_battery ab where ab.site_id = p_site_id),
        'min_soc',
        (select min(ab.min_soc_percent)::float from ems.asset_battery ab where ab.site_id = p_site_id),
        'soc_pct',
        (select li.battery_soc_percent::float from ems.vw_latest_inverter li where li.site_id = p_site_id order by li.measured_at desc nulls last limit 1),
        'inv_measured_at',
        (select li.measured_at from ems.vw_latest_inverter li where li.site_id = p_site_id order by li.measured_at desc nulls last limit 1),
        'hb_last_seen',
        (select hb.last_seen from ems.site_heartbeat hb where hb.site_id = p_site_id limit 1),
        'price_slots',
        coalesce(
          (
            select jsonb_agg(
              jsonb_build_object(
                'interval_start', v.interval_start,
                'effective_buy_price_czk_kwh', v.effective_buy_price_czk_kwh,
                'effective_sell_price_czk_kwh', v.effective_sell_price_czk_kwh
              )
              order by v.interval_start
            )
            from ems.vw_site_effective_price v
            where v.site_id = p_site_id
              and v.interval_start >= now()
              -- Python notifikace používají jen ceny v horizontu 6 h (24×15 min slotů).
              and v.interval_start < now() + interval '6 hours'
          ),
          '[]'::jsonb
        ),
        'avg_buy',
        (
          select avg(v.effective_buy_price_czk_kwh)::float
          from ems.vw_site_effective_price v
          where v.site_id = p_site_id
            and v.interval_start::date in (current_date, current_date + 1)
        ),
        'usable_wh',
        (
          select coalesce(sum(ab.usable_capacity_wh), 0)::float
          from ems.asset_battery ab
          join ems.asset_inverter ai on ai.id = ab.inverter_id
          where ai.site_id = p_site_id
        ),
        'ev_sessions',
        coalesce(
          (
            select jsonb_agg(
              jsonb_build_object(
                'id', es.id,
                'charger_id', es.charger_id,
                'energy_delivered_wh', es.energy_delivered_wh,
                'target_soc_pct', es.target_soc_pct,
                'session_start', es.session_start,
                'soc_at_connect_pct', es.soc_at_connect_pct,
                'battery_capacity_kwh', coalesce(av_id.battery_capacity_kwh, av_def.battery_capacity_kwh),
                'make', coalesce(av_id.make, av_def.make),
                'model', coalesce(av_id.model, av_def.model),
                'default_target_soc_pct', coalesce(av_id.default_target_soc_pct, av_def.default_target_soc_pct),
                'charger_code', ac.code
              )
              order by es.id
            )
            from ems.ev_session es
            join ems.asset_ev_charger ac on ac.id = es.charger_id
            left join ems.asset_vehicle av_id on av_id.id = es.vehicle_id
            left join ems.asset_vehicle av_def
              on av_def.default_charger_id = ac.id
             and es.vehicle_id is null
            where es.site_id = p_site_id
              and es.session_end is null
          ),
          '[]'::jsonb
        ),
        'neg_windows',
        coalesce(
          (
            select jsonb_agg(
              jsonb_build_object(
                'predicted_date', p.predicted_date,
                'window_start_hour', p.window_start_hour,
                'window_end_hour', p.window_end_hour,
                'probability_pct', p.probability_pct
              )
              order by p.predicted_date, p.window_start_hour
            )
            from ems.predicted_negative_price_window p
            where p.site_id = p_site_id
              and p.predicted_date between current_date and current_date + 2
              and p.probability_pct >= 50
          ),
          '[]'::jsonb
        )
      )
    end;
$fn$;

comment on function ems.fn_site_notifications_context(int) is
  'Vstupy pro build_smart_notifications + infra pravidla (GET /notifications).';
