--! Previous: sha1:c36f619890ff43d233e58abb4c5b9d5a4e556ca3
--! Hash: sha1:3a9ed9f26777390a1dccadc516bade27ffddf684
--! Message: pull command gets tiers

ALTER TABLE UnitTier
    ADD COLUMN IF NOT EXISTS pullWeightLower FLOAT NOT NULL DEFAULT 0,
    ADD COLUMN IF NOT EXISTS pullWeightUpper FLOAT NOT NULL DEFAULT 0;

--- Updates the UnitTier pull weight bounds to span from 0.0 to 1.0 and match the weights given.
CREATE OR REPLACE PROCEDURE UnitTier_UpdatePullWeightBounds() AS
$$
WITH weights AS (
    SELECT UnitTier.id                               AS id,
           (sum(UnitTier.pullWeight) OVER (ORDER BY UnitTier.sortOrder) - UnitTier.pullWeight)::FLOAT /
           (sum(UnitTier.pullWeight) OVER ())::FLOAT AS newPullWeightLower,
           (sum(pullWeight) OVER (ORDER BY sortOrder))::FLOAT /
           (sum(pullWeight) OVER ())::FLOAT          AS newPullWeightUpper
    FROM UnitTier
)
UPDATE UnitTier
SET pullWeightLower = weights.newPullWeightLower,
    pullWeightUpper = weights.newPullWeightUpper
FROM weights
WHERE weights.id = UnitTier.id;
$$ LANGUAGE 'sql';

CALL UnitTier_UpdatePullWeightBounds();

DROP TRIGGER IF EXISTS UnitTier_UpdatePullWeightBounds_Trigger ON UnitTier;
CREATE OR REPLACE FUNCTION UnitTier_UpdatePullWeightBounds_TriggerFunc() RETURNS TRIGGER AS
$$
BEGIN
    CALL UnitTier_UpdatePullWeightBounds();
END;
$$
    LANGUAGE 'plpgsql';
--- Automatically updates the pull weight bounds whenever the table changes.
CREATE TRIGGER UnitTier_UpdatePullWeightBounds_Trigger
    AFTER INSERT OR UPDATE OF pullWeight OR DELETE
    ON UnitTier
    FOR EACH STATEMENT
EXECUTE PROCEDURE UnitTier_UpdatePullWeightBounds_TriggerFunc();

DROP FUNCTION IF EXISTS 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
);
--- 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,
                summonedUnitTierId     UnitTier.id%TYPE,
                summonedUnitTierName   UnitTier.name%TYPE,
                summonCost             Player.currency%TYPE,
                resultingCurrency      Player.currency%TYPE,
                firstTimePull          BOOLEAN,
                wasAlreadySummoned     BOOLEAN
            )
    STRICT
    VOLATILE
    ROWS 10
AS
$$
DECLARE
    costPerSummon CONSTANT INT := 10;
    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
        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 IF;
    cost = costPerSummon * 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 playerLastDaily IS NULL OR playerLastDaily < NOW() - '1 day'::interval
                       WHEN TRUE THEN 'Try using the /daily command to get some more currency for today!'
                       ELSE format('Wait %s and you can use the /daily command to get some more currency!',
                                   (playerLastDaily + '1 day'::interval) - NOW())
                END;
    END IF;
    RETURN QUERY
        WITH rng AS (SELECT summonId, random() AS tierRandom FROM generate_series(1, count) AS series(summonId))
        SELECT NULL::INTEGER                              AS summonedUnitInstanceId,
               NULL::INTEGER                              AS summonedUnitId,
               NULL::VARCHAR                              AS summonedUnitName,
               NULL::VARCHAR                              AS summonedUnitSubtitle,
               t.id                                       AS summonedUnitTierId,
               t.name                                     AS summonedUnitTierName,
               costPerSummon                              AS summonCost,
               oldCurrency - (costPerSummon * r.summonId) AS resultingCurrency,
               NULL::BOOLEAN                              AS firstTimePull,
               NULL::BOOLEAN                              AS wasAlreadySummoned
        FROM rng AS r
                 INNER JOIN UnitTier AS t ON (t.pullWeightLower <= r.tierRandom AND t.pullWeightUpper > r.tierRandom);
END;
$$ LANGUAGE 'plpgsql';
