# Region.java

    package io.github.js0ny.ilp_coursework.data.common;

    import com.fasterxml.jackson.databind.ObjectMapper;

    import io.github.js0ny.ilp_coursework.data.request.RegionCheckRequest;

    import java.util.List;
    import java.util.Map;
    import java.util.Objects;

    /**
     * Represents the data transfer object for a region definition
     *
     * <p>This record encapsulates the data for calculating if a coordinate is inside the region
     *
     * <p>A built-in method {@code isClosedTo} is defined to check this DTO is valid or not in the mean
     * of closing polygon
     *
     * @param name The human-readable name for the region
     * @param vertices list of coordinates that forms a polygon as a region.
     *     <p>In order to define a valid region, the last element of the list should be the same as the
     *     first, or known as closed
     * @see RegionCheckRequest
     * @see io.github.js0ny.ilp_coursework.service.GpsCalculationService#checkIsInRegion(LngLat, Region)
     */
    public record Region(String name, List<LngLat> vertices) {
        /**
         * Magic number 4: For a polygon, 3 edges is required.
         *
         * <p>In this dto, edges + 1 vertices is required.
         */
        private static final int MINIMUM_VERTICES = 4;

        /**
         * Method to check if the region has a valid polygon by checking if the {@code vertices} forms a
         * closed polygon
         *
         * @return {@code true} if the {@code vertices} are able to form a polygon and form a closed
         *     polygon
         */
        public boolean isClosed() {
            if (vertices == null || vertices.size() < MINIMUM_VERTICES) {
                return false;
            }
            LngLat first = vertices.getFirst();
            LngLat last = vertices.getLast();
            return Objects.equals(last, first);
        }

        public Map<String, Object> toGeoJson() {
            try {
                ObjectMapper mapper = new ObjectMapper();

                List<List<Double>> ring =
                        vertices.stream().map(v -> List.of(v.lng(), v.lat())).toList();

                return Map.of("type", "Polygon", "coordinates", List.of(ring));

            } catch (Exception e) {
                throw new RuntimeException("Failed to generate GeoJSON", e);
            }
        }

        public String toGeoJsonString() {
            try {
                ObjectMapper mapper = new ObjectMapper();

                var geoJson = toGeoJson();

                return mapper.writeValueAsString(geoJson);
            } catch (Exception e) {
                throw new RuntimeException("Failed to generate GeoJSON", e);
            }
        }
    }