package com.zksy.WaterSupply;

import com.zksy.WaterSupply.WaterPipeInfo.domain.WaterPipeInfo;
import com.zksy.WaterSupply.WaterPlantInfo.domain.WaterPlantInfo;
import org.junit.jupiter.api.Test;

import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

class FacilityCoordinateModelTest {

    @Test
    void pointFacilityRetainsWgs84LongitudeAndLatitude() {
        WaterPlantInfo plant = new WaterPlantInfo();
        plant.setLongitude(new BigDecimal("113.12345678"));
        plant.setLatitude(new BigDecimal("23.12345678"));

        assertEquals(new BigDecimal("113.12345678"), plant.getLongitude());
        assertEquals(new BigDecimal("23.12345678"), plant.getLatitude());
    }

    @Test
    void pipeRetainsBothWgs84LineEndpoints() {
        WaterPipeInfo pipe = new WaterPipeInfo();
        pipe.setStartLongitude(new BigDecimal("113.10000000"));
        pipe.setStartLatitude(new BigDecimal("23.10000000"));
        pipe.setEndLongitude(new BigDecimal("113.20000000"));
        pipe.setEndLatitude(new BigDecimal("23.20000000"));

        assertEquals(new BigDecimal("113.10000000"), pipe.getStartLongitude());
        assertEquals(new BigDecimal("23.10000000"), pipe.getStartLatitude());
        assertEquals(new BigDecimal("113.20000000"), pipe.getEndLongitude());
        assertEquals(new BigDecimal("23.20000000"), pipe.getEndLatitude());
    }

    @Test
    void facilityMappersSelectCoordinateColumns() throws Exception {
        Map<String, String[]> expectedColumns = Map.of(
                "mapper/WaterSupply/WaterSourceInfo/WaterSourceInfoMapper.xml", new String[]{"longitude", "latitude"},
                "mapper/WaterSupply/WaterPlantInfo/WaterPlantInfoMapper.xml", new String[]{"longitude", "latitude"},
                "mapper/WaterSupply/WaterPumpStation/WaterPumpStationMapper.xml", new String[]{"longitude", "latitude"},
                "mapper/WaterSupply/WaterUserInfo/WaterUserInfoMapper.xml", new String[]{"longitude", "latitude"},
                "mapper/WaterSupply/WaterPipeInfo/WaterPipeInfoMapper.xml", new String[]{"start_longitude", "start_latitude", "end_longitude", "end_latitude"}
        );

        for (Map.Entry<String, String[]> mapper : expectedColumns.entrySet()) {
            try (InputStream input = getClass().getClassLoader().getResourceAsStream(mapper.getKey())) {
                assertNotNull(input, mapper.getKey());
                String xml = new String(input.readAllBytes(), StandardCharsets.UTF_8);
                for (String column : mapper.getValue()) {
                    assertTrue(xml.contains("column=\"" + column + "\""), mapper.getKey() + " resultMap should map " + column);
                    assertTrue(xml.contains(column), mapper.getKey() + " column list should include " + column);
                }
            }
        }
    }

    @Test
    void statisticsMapperQuotesKingbaseReservedValueAlias() throws Exception {
        try (InputStream input = getClass().getClassLoader().getResourceAsStream(
                "mapper/WaterSupply/PipeNetworkStatistics/PipeNetworkStatisticsMapper.xml")) {
            assertNotNull(input);
            String xml = new String(input.readAllBytes(), StandardCharsets.UTF_8);
            assertFalse(xml.contains("COUNT(*) value"), "KingbaseES reserves value as a keyword");
            assertTrue(xml.contains("COUNT(*) \"value\""));
            assertFalse(xml.contains("ORDER BY value"), "Reserved aliases must also be quoted in ORDER BY");
        }
    }

    @Test
    void statisticsMapperKeepsLayingYearDistributionTextTyped() throws Exception {
        try (InputStream input = getClass().getClassLoader().getResourceAsStream(
                "mapper/WaterSupply/PipeNetworkStatistics/PipeNetworkStatisticsMapper.xml")) {
            assertNotNull(input);
            String xml = new String(input.readAllBytes(), StandardCharsets.UTF_8);
            assertTrue(xml.contains("CAST('未填报' AS VARCHAR)"));
            assertFalse(xml.contains("CAST(laying_year AS INTEGER)"), "DDL declares laying_year as int4");
            assertTrue(xml.contains("CONCAT("), "laying year labels must use a text-returning concatenation function");
        }
    }

    @Test
    void statisticsMapperUsesTheAppUserWaterSupplyTables() throws Exception {
        try (InputStream input = getClass().getClassLoader().getResourceAsStream(
                "mapper/WaterSupply/PipeNetworkStatistics/PipeNetworkStatisticsMapper.xml")) {
            assertNotNull(input);
            String xml = new String(input.readAllBytes(), StandardCharsets.UTF_8);
            assertFalse(xml.matches("(?s).*\\bFROM\\s+(?!app_user\\.)water_(?:source_info|plant_info|pump_station|pipe_info|user_info)\\b.*"),
                    "statistics SQL must not resolve water supply tables through search_path");
            assertFalse(xml.matches("(?s).*<choose>.*>water_(?:source_info|plant_info|pump_station|pipe_info|user_info)</when>.*"),
                    "status distribution SQL must use app_user-qualified table names");
        }
    }

    @Test
    void gisMapperQuotesLocationAliasAndUsesAppUserSchema() throws Exception {
        try (InputStream input = getClass().getClassLoader().getResourceAsStream(
                "mapper/WaterSupply/WaterSupplyGisMap/WaterSupplyGisMapMapper.xml")) {
            assertNotNull(input);
            String xml = new String(input.readAllBytes(), StandardCharsets.UTF_8);
            assertTrue(xml.contains("address AS \"location\""));
            assertTrue(xml.contains("start_point AS \"location\""));
            assertTrue(xml.contains("status, \"location\", longitude, latitude"));
            assertFalse(xml.contains("address location"));
            assertFalse(xml.contains("start_point location"));
            assertFalse(xml.matches("(?s).*\\bFROM\\s+(?!app_user\\.)water_(?:source_info|plant_info|pump_station|pipe_info|user_info)\\b.*"),
                    "GIS SQL must not resolve water supply tables through search_path");
        }
    }
}
