--! Previous: sha1:2a39b3b006a8d5ec5d30ac1e5c2158d282b99acb
--! Hash: sha1:1390238abcc8e013a87b670fbcb3ae127a51ece8
--! Message: daily and VGNYJ error functions

--- Calculates the date at which /daily can be used again after the given timestamp.
CREATE OR REPLACE FUNCTION NextDailyCommand(IN lastDaily timestamp with time zone)
    RETURNS timestamp with time zone
    CALLED ON NULL INPUT
    IMMUTABLE
AS
$$
SELECT (COALESCE(lastDaily, TIMESTAMP '-infinity' AT TIME ZONE 'UTC')::date + 1)::timestamp AT TIME ZONE 'UTC'
$$ LANGUAGE 'sql';

--- Raises the VGNYJ error.
CREATE OR REPLACE PROCEDURE Error_NotYetJoined() AS
$$
BEGIN
    RAISE EXCEPTION USING
        ERRCODE = 'VGNYJ',
        MESSAGE = 'Not yet joined',
        DETAIL = 'You haven''t joined the game yet, and can''t use this command until you do.',
        HINT = 'Use the /join command to join the game!';
END;
$$ LANGUAGE 'plpgsql';

--- Runs the full /daily command.
--- Error codes:
---     VGBCG: Bad channel (game). This is not a valid channel to send game commands in.
---     VGBGG: Bad guild (game). This is not a valid guild to send game commands in.
---     VGNYJ: Not yet joined. The Discord user using has not joined the game yet.
---     VGDLY: Already used today.
CREATE OR REPLACE FUNCTION Command_Daily(
    IN requestedChannel DiscordChannel.discordId%TYPE,
    IN requestedGuild DiscordChannel.guildId%TYPE,
    IN forId DiscordUser.discordId%TYPE,
    IN newUsername DiscordUser.username%TYPE,
    IN newDiscriminator DiscordUser.discriminator%TYPE,
    OUT newLastDaily Player.lastDaily%TYPE,
    OUT newNextDaily Player.lastDaily%TYPE,
    OUT newCurrency Player.currency%TYPE,
    OUT bonus Player.currency%TYPE)
    STRICT
    VOLATILE
AS
$$
DECLARE
    playerId        Player.id%TYPE;
    playerLastDaily Player.lastDaily%TYPE;
    playerNextDaily Player.lastDaily%TYPE;
BEGIN
    CALL CheckGameCommandIn(requestedChannel, requestedGuild);
    SELECT InvokingPlayer.id, InvokingPlayer.lastDaily, NextDailyCommand(InvokingPlayer.lastdaily)
    INTO playerId, playerLastDaily, playerNextDaily
    FROM GetInvokingPlayer(forId, newUsername, newDiscriminator) AS InvokingPlayer;
    IF playerId IS NULL THEN
        CALL Error_NotYetJoined();
    END IF;
    bonus = 100;
    IF playerNextDaily > NOW() THEN
        RAISE EXCEPTION USING
            ERRCODE = 'VGDLY',
            MESSAGE = 'Already used today',
            DETAIL = format('You last used your daily command at <t:%s>. You can use it again at <t:%s>.',
                            extract(EPOCH FROM playerLastDaily)::INT,
                            extract(EPOCH FROM playerNextDaily)::INT),
            HINT = format('Wait <t:%s:R> and you can use the /daily command again to get some more currency!',
                          extract(EPOCH FROM playerNextDaily)::INT);
    ELSE
        UPDATE Player
        SET currency  = currency + bonus,
            lastDaily = NOW()
        WHERE id = playerId
        RETURNING lastDaily, currency INTO newLastDaily, newCurrency;
        newNextDaily = NextDailyCommand(newLastDaily);
    END IF;
END;
$$ LANGUAGE 'plpgsql';

--- Runs the full /pull command.
--- Error codes:
---     VGBCG: Bad channel (game). This is not a valid channel to send game commands in.
---     VGBGG: Bad guild (game). This is not a valid guild to send game commands in.
---     VGNYJ: Not yet joined. The Discord user using has not joined the game yet.
---     VGNEC: Not enough currency.
CREATE OR REPLACE FUNCTION Command_Pull(
    IN requestedChannel DiscordChannel.discordId%TYPE,
    IN requestedGuild DiscordChannel.guildId%TYPE,
    IN forId DiscordUser.discordId%TYPE,
    IN newUsername DiscordUser.username%TYPE,
    IN newDiscriminator DiscordUser.discriminator%TYPE,
    IN count INT
)
    RETURNS TABLE
            (
                summonedUnitInstanceId SummonedUnit.instanceId%TYPE,
                summonedUnitId         Unit.id%TYPE,
                summonedUnitName       Unit.name%TYPE,
                summonedUnitSubtitle   Unit.subtitle%TYPE,
                summonedUnitTierName   UnitTier.name%TYPE,
                firstTimePull          BOOLEAN,
                wasAlreadySummoned     BOOLEAN
            )
    STRICT
    VOLATILE
    ROWS 10
AS
$$
DECLARE
    playerId        Player.id%TYPE;
    cost            Player.currency%TYPE;
    oldCurrency     Player.currency%TYPE;
    playerLastDaily Player.lastDaily%TYPE;
BEGIN
    CALL CheckGameCommandIn(requestedChannel, requestedGuild);
    SELECT InvokingPlayer.id, InvokingPlayer.currency, InvokingPlayer.lastDaily
    INTO playerId, oldCurrency, playerLastDaily
    FROM GetInvokingPlayer(forId, newUsername, newDiscriminator) AS InvokingPlayer;
    IF playerId IS NULL THEN
        CALL Error_NotYetJoined();
    END IF;
    cost = 10 * count;
    UPDATE Player SET currency = currency - cost WHERE id = playerId AND currency >= cost;
    IF NOT FOUND THEN
        RAISE EXCEPTION USING
            ERRCODE = 'VGNEC',
            MESSAGE = 'Not enough currency',
            DETAIL = format('Pulling %s heroines would cost %s currency, but you only have %s currency.',
                            count, cost, oldCurrency),
            HINT = CASE NextDailyCommand(playerLastDaily) > NOW()
                       WHEN FALSE THEN 'You can use the /daily command to get some more currency for today!'
                       ELSE format('You can use the /daily command again <t:%s:R> to get some more currency!',
                                   extract(EPOCH FROM NextDailyCommand(playerLastDaily))::INT)
                END;
    END IF;
END;
$$ LANGUAGE 'plpgsql';
