-- Phase 6: cached proximity scores for fast filter / sort.
-- Refreshed by `OsmRefreshViewsCron` (Sun 03:00 ICT) and on admin-trigger.

-- For each industrial park, the 3 nearest POI of each priority category.
CREATE MATERIALIZED VIEW IF NOT EXISTS "mv_park_nearest_poi" AS
SELECT
  p.id AS park_id,
  poi.category::text AS category,
  poi.id AS poi_id,
  poi.name AS poi_name,
  ROUND(ST_Distance(p.location::geography, poi.location::geography)::numeric, 0)::int AS distance_m,
  ROW_NUMBER() OVER (
    PARTITION BY p.id, poi.category
    ORDER BY ST_Distance(p.location::geography, poi.location::geography)
  ) AS rank
FROM "IndustrialPark" p
CROSS JOIN LATERAL (
  SELECT id, name, category, location
    FROM "Poi"
   WHERE "isPublic" = true
     AND category::text IN ('HOSPITAL','BANK','GAS_STATION','BUS_STATION','METRO_STATION','POLICE')
     AND ST_DWithin(location::geography, p.location::geography, 5000)
) poi;

CREATE INDEX IF NOT EXISTS "mv_park_nearest_poi_park_cat" ON "mv_park_nearest_poi"(park_id, category, rank);
CREATE UNIQUE INDEX IF NOT EXISTS "mv_park_nearest_poi_uq" ON "mv_park_nearest_poi"(park_id, category, poi_id);

-- Per-province POI density (count by category) for analytics heatmaps.
CREATE MATERIALIZED VIEW IF NOT EXISTS "mv_poi_density_by_province" AS
SELECT
  "provinceCode",
  category::text AS category,
  COUNT(*)::int AS poi_count
FROM "Poi"
WHERE "isPublic" = true
  AND "provinceCode" IS NOT NULL
GROUP BY "provinceCode", category;

CREATE INDEX IF NOT EXISTS "mv_poi_density_by_province_idx" ON "mv_poi_density_by_province"("provinceCode", category);
