-- =============================================================================
-- PostGIS native geometry setup for GisUat (UAT boundaries)
-- Run once manually: PGPASSWORD='...' psql -h 10.10.10.166 -p 5432 \
--   -U architools_user -d architools_db -f prisma/gisuat-postgis-setup.sql
--
-- Idempotent — safe to re-run.
--
-- What this does:
--   1. Ensures PostGIS extension
--   2. Adds native geometry column (geom) if missing
--   3. Creates function to convert Esri ring JSON -> PostGIS geometry
--   4. Creates trigger to auto-convert on INSERT/UPDATE
--   5. Backfills existing rows
--   6. Creates GiST spatial index
--   7. Creates Martin/QGIS-friendly view 'gis_uats'
--
-- After running both SQL scripts (postgis-setup.sql + this file), Martin
-- will auto-discover these views (any table/view with a 'geom' geometry column):
--   - gis_features    (master: all GisFeature rows with geometry)
--   - gis_terenuri    (parcels from GisFeature)
--   - gis_cladiri     (buildings from GisFeature)
--   - gis_documentatii (expertize/zone/receptii from GisFeature)
--   - gis_administrativ (limite UAT/intravilan/arii speciale from GisFeature)
--   - gis_uats        (UAT boundaries from GisUat) <-- this script
--
-- All geometries are in EPSG:3844 (Stereo70).
-- =============================================================================

-- 1. Ensure PostGIS extension
CREATE EXTENSION IF NOT EXISTS postgis;

-- 2. Add native geometry column (idempotent)
DO $$
BEGIN
  IF NOT EXISTS (
    SELECT 1 FROM information_schema.columns
    WHERE table_name = 'GisUat' AND column_name = 'geom'
  ) THEN
    ALTER TABLE "GisUat" ADD COLUMN geom geometry(Geometry, 3844);
  END IF;
END $$;

-- 3. Function: convert Esri ring JSON { rings: number[][][] } -> PostGIS geometry
--    Esri rings format: each ring is an array of [x, y] coordinate pairs.
--    First ring = exterior, subsequent rings = holes.
--    Multiple outer rings (non-holes) would need MultiPolygon, but UAT boundaries
--    from eTerra typically have a single polygon with possible holes.
--
--    Strategy: build WKT POLYGON/MULTIPOLYGON from the rings array, then
--    use ST_GeomFromText with SRID 3844.
CREATE OR REPLACE FUNCTION gis_uat_esri_to_geom(geom_json jsonb)
RETURNS geometry AS $$
DECLARE
  rings jsonb;
  ring jsonb;
  coord jsonb;
  ring_count int;
  coord_count int;
  i int;
  j int;
  wkt_ring text;
  wkt text;
  first_x double precision;
  first_y double precision;
  last_x double precision;
  last_y double precision;
BEGIN
  -- Extract the rings array from the JSON
  rings := geom_json -> 'rings';

  IF rings IS NULL OR jsonb_array_length(rings) = 0 THEN
    RETURN NULL;
  END IF;

  ring_count := jsonb_array_length(rings);

  -- Build WKT POLYGON with all rings (first = exterior, rest = holes)
  wkt := 'POLYGON(';

  FOR i IN 0 .. ring_count - 1 LOOP
    ring := rings -> i;
    coord_count := jsonb_array_length(ring);

    IF coord_count < 3 THEN
      CONTINUE;  -- skip degenerate rings
    END IF;

    IF i > 0 THEN
      wkt := wkt || ', ';
    END IF;

    wkt_ring := '(';

    FOR j IN 0 .. coord_count - 1 LOOP
      coord := ring -> j;
      IF j > 0 THEN
        wkt_ring := wkt_ring || ', ';
      END IF;
      wkt_ring := wkt_ring || (coord ->> 0) || ' ' || (coord ->> 1);

      -- Track first and last coordinates to check ring closure
      IF j = 0 THEN
        first_x := (coord ->> 0)::double precision;
        first_y := (coord ->> 1)::double precision;
      END IF;
      IF j = coord_count - 1 THEN
        last_x := (coord ->> 0)::double precision;
        last_y := (coord ->> 1)::double precision;
      END IF;
    END LOOP;

    -- Close the ring if not already closed
    IF first_x != last_x OR first_y != last_y THEN
      wkt_ring := wkt_ring || ', ' || first_x::text || ' ' || first_y::text;
    END IF;

    wkt_ring := wkt_ring || ')';
    wkt := wkt || wkt_ring;
  END LOOP;

  wkt := wkt || ')';

  RETURN ST_GeomFromText(wkt, 3844);
END;
$$ LANGUAGE plpgsql IMMUTABLE;

-- 4. Trigger function: auto-convert Esri JSON -> native PostGIS on INSERT/UPDATE
CREATE OR REPLACE FUNCTION gis_uat_sync_geom()
RETURNS TRIGGER AS $$
BEGIN
  IF NEW.geometry IS NOT NULL THEN
    BEGIN
      NEW.geom := gis_uat_esri_to_geom(NEW.geometry::jsonb);
    EXCEPTION WHEN OTHERS THEN
      -- Invalid geometry JSON -> leave geom NULL rather than fail the write
      NEW.geom := NULL;
    END;
  ELSE
    NEW.geom := NULL;
  END IF;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- 5. Attach trigger (drop + recreate for idempotency)
DROP TRIGGER IF EXISTS trg_gis_uat_sync_geom ON "GisUat";
CREATE TRIGGER trg_gis_uat_sync_geom
  BEFORE INSERT OR UPDATE OF geometry ON "GisUat"
  FOR EACH ROW
  EXECUTE FUNCTION gis_uat_sync_geom();

-- 6. Backfill: convert existing Esri JSON geometries to native PostGIS
UPDATE "GisUat"
SET geom = gis_uat_esri_to_geom(geometry::jsonb)
WHERE geometry IS NOT NULL AND geom IS NULL;

-- 7. GiST spatial index for fast spatial queries
CREATE INDEX IF NOT EXISTS gis_uat_geom_idx
  ON "GisUat" USING GIST (geom);

-- =============================================================================
-- 8. Zoom-dependent views for Martin vector tiles
--    4 levels of geometry simplification for progressive loading.
--    SAFE: these are read-only views — original geom column is NEVER modified.
-- =============================================================================

-- z0-5: Very coarse overview (2000m tolerance) — country-level outlines
CREATE OR REPLACE VIEW gis_uats_z0 AS
SELECT siruta, name,
  ST_SimplifyPreserveTopology(geom, 2000) AS geom
FROM "GisUat" WHERE geom IS NOT NULL;

-- z5-8: Coarse (500m tolerance) — regional overview
CREATE OR REPLACE VIEW gis_uats_z5 AS
SELECT siruta, name,
  ST_SimplifyPreserveTopology(geom, 500) AS geom
FROM "GisUat" WHERE geom IS NOT NULL;

-- z8-12: Moderate (50m tolerance) — county/city level
CREATE OR REPLACE VIEW gis_uats_z8 AS
SELECT siruta, name, county,
  ST_SimplifyPreserveTopology(geom, 50) AS geom
FROM "GisUat" WHERE geom IS NOT NULL;

-- z12+: Original geometry — full precision, no simplification
CREATE OR REPLACE VIEW gis_uats_z12 AS
SELECT siruta, name, county, geom
FROM "GisUat" WHERE geom IS NOT NULL;

-- Keep the legacy gis_uats view for QGIS compatibility
CREATE OR REPLACE VIEW gis_uats AS
SELECT siruta, name, county,
  ST_SimplifyPreserveTopology(geom, 50) AS geom
FROM "GisUat" WHERE geom IS NOT NULL;

-- =============================================================================
-- Done! Martin serves these views as vector tiles:
--   - gis_uats_z0    (z0-5,  2000m simplification)
--   - gis_uats_z5    (z5-8,  500m)
--   - gis_uats_z8    (z8-12, 50m)
--   - gis_uats_z12   (z12+,  10m near-original)
--   - gis_uats       (legacy for QGIS, 50m)
-- Original geometry in GisUat.geom is NEVER modified.
-- SRID: 3844 (Stereo70)
-- =============================================================================
