package incheon.cmm.g2f.layer.mapper;

import java.util.List;
import java.util.Map;
import java.util.Set;

import incheon.cmm.g2f.layer.vo.FlightPhotoLayerSearchRequestDTO;
import incheon.cmm.g2f.layer.vo.FlightPhotoLyrVO;
import incheon.cmm.g2f.layer.vo.TaskLayerSearchRequestDTO;
import incheon.cmm.g2f.layer.vo.TaskLayerVO;
import org.apache.ibatis.annotations.DeleteProvider;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.SelectProvider;
import org.apache.ibatis.annotations.UpdateProvider;

/**
 * G2F 공통 매퍼 인터페이스
 * 공간 데이터 편집 API를 위한 동적 SQL 처리
 * 메타데이터 조회는 @Select, 동적 SQL은 @Provider 사용
 */
@org.egovframe.rte.psl.dataaccess.mapper.Mapper @incheon.com.config.annotation.MainDB
public interface G2FLayerMapper {

    /**
     * 사용자 레이어 메타데이터 조회
     */
    @Select("""
        SELECT user_lyr_id, user_id, lyr_phys_nm, cntm, spce_ty
        FROM icmrb.user_lyr 
        WHERE user_lyr_id = #{layerId}::BIGINT
        """)
    Map<String, Object> selectUserLayerMetadata(String layerId);

    /**
     * 업무 레이어 메타데이터 조회
     */
    @Select("""
        SELECT task_lyr_id, lyr_phys_nm, cntm, spce_ty
        FROM iccom.task_lyr 
        WHERE task_lyr_id = #{layerId}::BIGINT
        """)
    Map<String, Object> selectTaskLayerMetadata(String layerId);

    /**
     * 테이블 컬럼 메타데이터 조회
     * gid, geom 컬럼은 제외하고 조회
     */
    @Select("""
        SELECT column_name, data_type, is_nullable
        FROM information_schema.columns 
        WHERE table_schema = #{schemaName} AND table_name = #{tableName}
        AND column_name != 'gid' AND column_name != 'geom'
        ORDER BY ordinal_position
        """)
    List<Map<String, Object>> selectTableColumns(@Param("schemaName") String schemaName, @Param("tableName") String tableName);

    /**
     * 테이블 컬럼 메타데이터 조회
     * gid, geom 컬럼은 제외하고 조회
     */
    @Select("""
         SELECT c.column_name,
                c.data_type,
                c.is_nullable,
                CASE
                  WHEN kcu.column_name IS NOT NULL THEN 'YES'
                  ELSE 'NO'
                END AS isPrimaryKey
         FROM information_schema.columns c
         LEFT JOIN information_schema.table_constraints tc
           ON c.table_schema = tc.table_schema
           AND c.table_name = tc.table_name
           AND tc.constraint_type = 'PRIMARY KEY'
         LEFT JOIN information_schema.key_column_usage kcu
           ON tc.constraint_name = kcu.constraint_name
           AND kcu.column_name = c.column_name
           AND tc.table_schema = kcu.table_schema
           AND tc.table_name = kcu.table_name
         WHERE c.table_schema = #{schemaName}
           AND c.table_name = #{tableName}
           AND c.column_name NOT IN ('gid', 'geom')
         ORDER BY c.ordinal_position
        """)
    List<Map<String, Object>> uisSelectTableColumns(@Param("schemaName") String schemaName, @Param("tableName") String tableName);


    /**
     * 청크 배치 INSERT (RETURNING *)
     * PostgreSQL의 INSERT ... RETURNING *을 사용하여 저장된 모든 컬럼 정보를 반환
     * @SelectProvider를 사용하는 이유: RETURNING은 결과 집합을 반환하므로 SELECT로 처리
     */
    //@InsertProvider(type = G2FSqlProvider.class, method = "batchInsertLayerFeatures")
    //int batchInsertLayerFeatures(Map<String, Object> params);
    @SelectProvider(type = G2FSqlProvider.class, method = "batchInsertLayerFeatures")
    List<Map<String, Object>> batchInsertLayerFeatures(Map<String, Object> params);

    /**
     * 청크 배치 UPDATE (@UpdateProvider)
     * CASE WHEN 방식으로 배치 처리
     */
    @UpdateProvider(type = G2FSqlProvider.class, method = "batchUpdateLayerFeatures")
    int batchUpdateLayerFeatures(Map<String, Object> params);

    /**
     * 배치 DELETE (@DeleteProvider)
     * ID 배열을 받아 IN 절로 삭제
     */
    @DeleteProvider(type = G2FSqlProvider.class, method = "deleteLayerFeatures")
    int deleteLayerFeatures(Map<String, Object> params);

    /**
     * 피처 조회 (검증용)
     * 테스트와 검증을 위한 개별 피처 조회
     */
    @SelectProvider(type = G2FSqlProvider.class, method = "selectLayerFeature")
    Map<String, Object> selectLayerFeature(Map<String, Object> params);

    /**
     * 업무 레이어 리스트 조회
     */
    List<TaskLayerVO> selectTaskLayerList(TaskLayerSearchRequestDTO requestDTO);

    /**
     * 업무 레이어 리스트 조회 (권한 체크)
     */
    List<TaskLayerVO> selectTaskLayerListNotInGroupCd(@Param("request") TaskLayerSearchRequestDTO searchVO, @Param("removedGroupCd") Set<String> removedGroupCd);

    /**
     * 업무 레이어 Count
     */
    long selectTaskLayerListTotCnt(TaskLayerSearchRequestDTO requestDTO);

    /**
     * 업무 레이어 Count (권한 체크)
     */
    long selectTaskLayerListNotInGroupCdTotCnt(@Param("request") TaskLayerSearchRequestDTO searchVO, @Param("removedGroupCd") Set<String> removedGroupCd);

    /**
     * 항공 사진 레이어 리스트 조회
     */
    List<FlightPhotoLyrVO> selectFlightPhotoLayerList(@Param("request") FlightPhotoLayerSearchRequestDTO requestDTO, @Param("otsdRlsEn") Boolean otsdRlsEn);

    /**
     * 항공 사진 레이어 Count
     */
    long selectFlightPhotoLayerListTotCnt(@Param("request") FlightPhotoLayerSearchRequestDTO requestDTO, @Param("otsdRlsEn") Boolean otsdRlsEn);

    /**
     * 업무 레이어 조회
     */
    TaskLayerVO selectTaskLayerById(int taskLyrId);

    /**
     * ID로 항공 사진 레이어 조회
     */
    FlightPhotoLyrVO selectFlightPhotoLayerById(int flightLyrId);

    /**
     * ID 목록으로 항공 사진 레이어 조회
     */
    List<FlightPhotoLyrVO> selectFlightPhotoLayerInIds(Set<Integer> flightLyrIds);

    /**
     * 이력 테이블 존재 여부 확인
     * information_schema를 통해 안전하게 테이블 존재 여부 확인
     */
    @Select("""
        SELECT EXISTS (
            SELECT 1 FROM information_schema.tables
            WHERE table_schema = #{schemaName}
            AND table_name = #{tableName}
        )
        """)
    Boolean checkHistoryTableExists(@Param("schemaName") String schemaName, @Param("tableName") String tableName);

    /**
     * 이력 테이블 INSERT - Added (STTS_CD='C')
     * 새로운 피처 추가 이력 저장
     */
    @InsertProvider(type = G2FSqlProvider.class, method = "batchInsertHistoryAdded")
    int batchInsertHistoryAdded(Map<String, Object> params);

    /**
     * 이력 테이블 INSERT - Modified (STTS_CD='U')
     * 피처 수정 이력 저장
     */
    @InsertProvider(type = G2FSqlProvider.class, method = "batchInsertHistoryModified")
    int batchInsertHistoryModified(Map<String, Object> params);

    /**
     * 이력 테이블 INSERT - Deleted (STTS_CD='D')
     * 피처 삭제 이력 저장 (gid만 저장)
     */
    @InsertProvider(type = G2FSqlProvider.class, method = "batchInsertHistoryDeleted")
    int batchInsertHistoryDeleted(Map<String, Object> params);

}