package com.pandoli365.bibimbap.mapper;

import com.pandoli365.bibimbap.data.GameData;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Options;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import java.util.List;

@Mapper
public interface GamesMapper {

    @Select("""
            SELECT
                g.id,
                g.user_id AS userId,
                g.name,
                u.display_name AS creator,
                g.creator_note AS creatorNote,
                g.git_url AS gitUrl,
                g.webgl_path AS webglPath,
                g.thumbnail_url AS thumbnailUrl,
                g.like_count AS likeCount,
                g.is_visible AS visible,
                g.sort_order AS sortOrder,
                g.created_at AS createdAt,
                g.updated_at AS updatedAt
            FROM games g
            JOIN users u ON u.id = g.user_id
            WHERE g.id = #{id}
              AND g.is_delete IS NOT TRUE
              AND u.is_delete IS NOT TRUE
            """)
    GameData getGame(long id);

    @Select("""
            SELECT
                g.id,
                g.user_id AS userId,
                g.name,
                u.display_name AS creator,
                g.creator_note AS creatorNote,
                g.git_url AS gitUrl,
                g.webgl_path AS webglPath,
                g.thumbnail_url AS thumbnailUrl,
                g.like_count AS likeCount,
                g.is_visible AS visible,
                g.sort_order AS sortOrder,
                g.created_at AS createdAt,
                g.updated_at AS updatedAt
            FROM games g
            JOIN users u ON u.id = g.user_id
            WHERE g.is_visible IS NOT FALSE
              AND g.is_delete IS NOT TRUE
              AND u.is_delete IS NOT TRUE
            ORDER BY g.sort_order ASC, g.created_at DESC, g.id DESC
            """)
    List<GameData> getVisibleGames();

    @Select("""
            SELECT
                g.id,
                g.user_id AS userId,
                g.name,
                u.display_name AS creator,
                g.creator_note AS creatorNote,
                g.git_url AS gitUrl,
                g.webgl_path AS webglPath,
                g.thumbnail_url AS thumbnailUrl,
                g.like_count AS likeCount,
                g.is_visible AS visible,
                g.sort_order AS sortOrder,
                g.created_at AS createdAt,
                g.updated_at AS updatedAt
            FROM games g
            JOIN users u ON u.id = g.user_id
            WHERE g.is_visible IS NOT FALSE
              AND g.is_delete IS NOT TRUE
              AND u.is_delete IS NOT TRUE
              AND (
                  g.name ILIKE CONCAT('%', #{query}, '%')
                  OR u.display_name ILIKE CONCAT('%', #{query}, '%')
                  OR g.creator_note ILIKE CONCAT('%', #{query}, '%')
              )
            ORDER BY g.sort_order ASC, g.created_at DESC, g.id DESC
            """)
    List<GameData> searchVisibleGames(@Param("query") String query);

    @Select("""
            SELECT
                g.id,
                g.user_id AS userId,
                g.name,
                u.display_name AS creator,
                g.creator_note AS creatorNote,
                g.git_url AS gitUrl,
                g.webgl_path AS webglPath,
                g.thumbnail_url AS thumbnailUrl,
                g.like_count AS likeCount,
                g.is_visible AS visible,
                g.sort_order AS sortOrder,
                g.created_at AS createdAt,
                g.updated_at AS updatedAt
            FROM games g
            JOIN users u ON u.id = g.user_id
            WHERE g.user_id = #{userId}
              AND g.is_delete IS NOT TRUE
              AND u.is_delete IS NOT TRUE
            ORDER BY g.updated_at DESC, g.created_at DESC, g.id DESC
            """)
    List<GameData> getGamesByUserId(@Param("userId") long userId);

    @Insert("""
            INSERT INTO games (
                user_id,
                name,
                creator_note,
                git_url,
                webgl_path,
                thumbnail_url,
                is_visible,
                sort_order
            ) VALUES (
                #{userId},
                #{name},
                #{creatorNote},
                #{gitUrl},
                #{webglPath},
                #{thumbnailUrl},
                #{visible},
                #{sortOrder}
            )
            """)
    @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id")
    int addGame(GameData game);

    @Select("""
            SELECT COALESCE(MAX(sort_order), 0) + 1
            FROM games
            WHERE is_delete IS NOT TRUE
            """)
    int nextSortOrder();

    @Update("""
            UPDATE games
            SET
                user_id = #{userId},
                name = #{name},
                creator_note = #{creatorNote},
                git_url = #{gitUrl},
                webgl_path = #{webglPath},
                thumbnail_url = #{thumbnailUrl},
                is_visible = #{visible},
                sort_order = #{sortOrder},
                updated_at = now()
            WHERE id = #{id}
              AND is_delete IS NOT TRUE
            """)
    int updateGame(GameData game);

    @Update("""
            UPDATE game_comments
            SET
                is_delete = true,
                deleted_at = COALESCE(deleted_at, now())
            WHERE game_id = #{gameId}
              AND is_delete IS NOT TRUE
            """)
    int softDeleteGameComments(@Param("gameId") long gameId);

    @Delete("""
            DELETE FROM game_likes
            WHERE game_id = #{gameId}
            """)
    int deleteGameLikes(@Param("gameId") long gameId);

    @Update("""
            UPDATE games
            SET
                is_delete = true,
                updated_at = now()
            WHERE id = #{id}
              AND is_delete IS NOT TRUE
            """)
    int softDeleteGame(@Param("id") long id);
}
