package cn.edu.whu.boot.allocation.mapper;

import cn.edu.whu.boot.allocation.entities.TaskCellData;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface TaskCellDataMapper {
    @Select("SELECT id, task_id, table_name, data_id, cell_geohash FROM task_cell_data WHERE id = #{id}")
    @Results(
            {
                    @Result(property = "taskId", column = "task_id"),
                    @Result(property = "tableName", column = "table_name"),
                    @Result(property = "dataId", column = "data_id"),
                    @Result(property = "cellGeohash", column = "cell_geohash")
            }
    )
    TaskCellData findById(@Param("id") int id);

    @Select("SELECT id, task_id, table_name, data_id, cell_geohash FROM task_cell_data WHERE task_id = #{taskId}")
    @Results(
            {
                    @Result(property = "taskId", column = "task_id"),
                    @Result(property = "tableName", column = "table_name"),
                    @Result(property = "dataId", column = "data_id"),
                    @Result(property = "cellGeohash", column = "cell_geohash")
            }
    )
    List<TaskCellData> findByTaskId(@Param("taskId") int taskId);

    @Select("SELECT id, task_id, table_name, data_id, cell_geohash " +
            "FROM task_cell_data " +
            "WHERE task_id = #{taskId} AND cell_geohash = #{cellGeohash}")
    @Results(
            {
                    @Result(property = "taskId", column = "task_id"),
                    @Result(property = "tableName", column = "table_name"),
                    @Result(property = "dataId", column = "data_id"),
                    @Result(property = "cellGeohash", column = "cell_geohash")
            }
    )
    List<TaskCellData> findByTaskIdAndCellGeohash(@Param("taskId") int taskId , @Param("cellGeohash") String cellGeohash);

    @Select("SELECT id, task_id, table_name, data_id, cell_geohash FROM task_cell_data WHERE task_id = #{taskId} AND cell_geohash = #{cellGeohash} and table_name = #{tableName}")
    @Results(
            {
                    @Result(property = "taskId", column = "task_id"),
                    @Result(property = "tableName", column = "table_name"),
                    @Result(property = "dataId", column = "data_id"),
                    @Result(property = "cellGeohash", column = "cell_geohash")
            }
    )
    List<TaskCellData> findByTaskIdAndTableNameAndCellGeohash(@Param("taskId") int taskId , @Param("tableName") String tableName ,
                                                              @Param("cellGeohash") String cellGeohash);

    @Select("SELECT id, task_id, table_name, data_id, cell_geohash FROM task_cell_data WHERE task_id = #{taskId} AND table_name = #{tableName} AND data_id = #{dataId}")
    @Results(
            {
                    @Result(property = "taskId", column = "task_id"),
                    @Result(property = "tableName", column = "table_name"),
                    @Result(property = "dataId", column = "data_id"),
                    @Result(property = "cellGeohash", column = "cell_geohash")
            }
    )
    TaskCellData findByTaskIdAndTableNameAndDataId(@Param("taskId") int taskId ,@Param("tableName") String tableName , @Param("dataId") long dataId);

    @Select({"<script>",
            "SELECT id, task_id, table_name, data_id, cell_geohash",
            "FROM task_cell_data",
            "WHERE task_id = #{taskId} AND cell_geohash IN",
            "<foreach item='geohash' index='index' collection='geohashes'",
            "open='(' separator=',' close=')'>",
            "#{geohash}",
            "</foreach>",
            "</script>"})
    @Results(
            {
                    @Result(property = "taskId", column = "task_id"),
                    @Result(property = "tableName", column = "table_name"),
                    @Result(property = "dataId", column = "data_id"),
                    @Result(property = "cellGeohash", column = "cell_geohash")
            }
    )
    List<TaskCellData> findByTaskIdAndCellGeohashIn(@Param("taskId") int taskId , @Param("geohashes") List<String> geohashes);

    @Select({"<script>",
            "SELECT id, task_id, table_name, data_id, cell_geohash",
            "FROM task_cell_data",
            "WHERE task_id = #{taskId} AND data_id IN",
            "<foreach item='data' index='index' collection='dataIds'",
            "open='(' separator=',' close=')'>",
            "#{data}",
            "</foreach>",
            "</script>"})
    @Results(
            {
                    @Result(property = "taskId", column = "task_id"),
                    @Result(property = "tableName", column = "table_name"),
                    @Result(property = "dataId", column = "data_id"),
                    @Result(property = "cellGeohash", column = "cell_geohash")
            }
    )
    List<TaskCellData> findByTaskIdAndDataIdIn(@Param("taskId") int taskId , @Param("dataIds") List<Integer> dataIds);

    @Select("SELECT id, task_id, table_name, data_id, cell_geohash " +
            "FROM task_cell_data " +
            "WHERE task_id = #{taskId} AND data_id = #{dataId}")
    @Results(
            {
                    @Result(property = "taskId", column = "task_id"),
                    @Result(property = "tableName", column = "table_name"),
                    @Result(property = "dataId", column = "data_id"),
                    @Result(property = "cellGeohash", column = "cell_geohash")
            }
    )
    TaskCellData findByTaskIdAndDataId(@Param("taskId") int taskId , @Param("dataId") int dataId);

    @Select("INSERT INTO task_cell_data(task_id, table_name, data_id, cell_geohash)" +
            " VALUES(#{taskId}, #{tableName}, #{dataId}, #{cellGeohash}) RETURNING id")
    int insert(TaskCellData taskCellData);

    @Insert({
            "<script>",
            "INSERT INTO task_cell_data(task_id, table_name, data_id, cell_geohash)",
            "VALUES" +
                    "<foreach item='item' index='item' collection='list' open='' separator=',' close=''>" +
                    "(" +
                    "#{item.taskId}, #{item.tableName}, #{item.dataId}, #{item.cellGeohash}",
            ")" +
                    "</foreach>",
            "</script>"})
    void insertForeach(@Param("list") List<TaskCellData> list);

    @Select("UPDATE task_cell_data SET task_id = #{taskId}, table_name = #{tableName}, data_id = #{dataId}, cell_geohash = #{cellGeohash} WHERE id = #{id} RETURNING id")
    @Options(flushCache = Options.FlushCachePolicy.TRUE)
    int update(TaskCellData taskCellData);

    @Delete("DELETE FROM task_cell_data WHERE task_id = #{taskId}")
    void deleteByTaskId(@Param("taskId") int taskId);

    @Delete("DELETE FROM task_cell_data WHERE task_id = #{taskId} AND table_name = #{tableName} AND data_id = #{dataId}")
    void deleteByTaskIdAndTableNameAndDataId(@Param("taskId") int taskId, @Param("tableName") String tableName, @Param("dataId") long dataId);

    @Select(
            "SELECT table_name, data_id, cell_geohash " +
                    "FROM task_cell_data " +
                    "WHERE task_id = #{taskId} " +
                    "AND cell_geohash = (SELECT cell_geohash FROM task_cell_data WHERE data_id = #{dataId})"
    )
    @Results(
            {
                    @Result(property = "tableName", column = "table_name"),
                    @Result(property = "dataId", column = "data_id"),
                    @Result(property = "cellGeohash", column = "cell_geohash")
            }
    )
    List<TaskCellData> findInTheSameTaskAndCell(@Param("taskId") int taskId, @Param("dataId") long dataId);

    @Select({
            "<script>",
            "SELECT cell_geohash FROM task_cell_data ",
            "WHERE task_id = #{taskId} AND table_name = #{tableName} AND data_id IN ",
            "(<foreach item='dataId' collection='dataIds' separator=','>#{dataId}</foreach>)",
            "</script>"
    })
    List<String> findCellGeohashByTaskIdAndTableNameAndDataId(@Param("taskId") int taskId, @Param("tableName") String tableName, @Param("dataIds") List<Long> dataIds);

    @Select({
            "<script>",
            "SELECT cell_geohash FROM task_cell_data WHERE task_id = #{taskId} AND table_name = #{tableName} " +
                    "AND data_id IN (<foreach item='dataId' collection='dataIds' separator=','>#{dataId}</foreach>) " +
                    "AND cell_geohash NOT IN " +
                    "(SELECT tuc.cell_geohash FROM task_user_cell tuc WHERE tuc.task_id = #{taskId} AND tuc.user_id = #{userId})",
            "</script>"
    })
    List<String> findCellsWhereUserIsAbsent(@Param("taskId") int taskId, @Param("tableName") String table, @Param("userId") Integer reviewerId, @Param("dataIds") List<Long> dataIds);
}
