--! Previous: sha1:8102b0362d2ae5b73ed1d56214f7fffa445c469e
--! Hash: sha1:8a890a4c8807eb5a7aae90456ba1e7712cda502b
--! Message: SummonedUnit table

--- Connection between Players and Units, indicating how and when players have summoned this unit.
CREATE TABLE IF NOT EXISTS SummonedUnit
(
    --- The ID of this summoning instance.
    instanceId           SERIAL PRIMARY KEY       NOT NULL,
    --- The Player that summoned this unit at some point.
    playerId             INT                      NOT NULL REFERENCES Player (id) ON DELETE CASCADE ON UPDATE CASCADE,
    --- The Unit that was summoned by this Player at some point.
    unitId               INT                      NOT NULL REFERENCES Unit (id) ON DELETE CASCADE ON UPDATE CASCADE,
    --- The time and date this instance was summoned by pulling or recalling.
    summonedAt           TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
    --- True if this instance was summoned by /pull (as opposed to /recall).
    wasPulled            BOOLEAN                  NOT NULL DEFAULT FALSE,
    --- True if this instance was summoned by /recall (as opposed to /pull).
    wasRecalled          BOOLEAN                  NOT NULL DEFAULT FALSE,
    --- The timestamps when this unit was resummoned because it appeared in a /pull while already summoned.
    --- Does not include the initial summoning if that summoning happened via /pull.
    resummonings         TIMESTAMP WITH TIME ZONE ARRAY    DEFAULT NULL,
    --- The time and date this instance was desummoned by digesting or releasing.
    desummonedAt         TIMESTAMP WITH TIME ZONE          DEFAULT NULL,
    --- The summoned unit (friendly or enemy) that digested this unit, if a summoned unit was responsible and that
    --- summoned unit has not been deleted somehow.
    digestedByInstanceId INT                               DEFAULT NULL REFERENCES SummonedUnit (instanceId) ON DELETE SET NULL ON UPDATE CASCADE,
    --- True if this instance was desummoned by being digested rather than being released.
    wasDigested          BOOLEAN                           DEFAULT NULL,
    --- True if this instance was desummoned by being released rather than being digested.
    wasReleased          BOOLEAN                           DEFAULT NULL,
    --- The unit's current health. If 0, the unit is unconscious and cannot participate in fights.
    --- At -MaxHealth, the unit has been fully digested and this record will be deleted.
    currentHealth        INT                      NOT NULL,
    --- The unit's maximum health.
    maxHealth            INT                      NOT NULL CHECK (maxHealth > 0),
    --- The unit's strength.
    strength             INT                      NOT NULL CHECK (strength > 0),
    --- The unit's current health must be between maxHealth and -maxHealth (the latter of which means digestion).
    CONSTRAINT SummonedUnit_CurrentHealthBounds CHECK (
        currentHealth BETWEEN -maxHealth AND maxHealth),
    --- Exactly one of wasPulled or wasRecalled must be TRUE.
    CONSTRAINT SummonedUnit_ExactlyOneOrigin CHECK (
        ((wasPulled IS TRUE OR wasRecalled IS TRUE) AND NOT (wasPulled IS FALSE AND wasRecalled IS FALSE))),
    --- Exactly one of wasDigested or wasReleased must be TRUE if desummonedAt is set,
    --- and both must be NULL if desummonedAt is NULL.
    CONSTRAINT SummonedUnit_ExactlyOneFate CHECK (
            ((wasDigested IS TRUE OR wasReleased IS TRUE) = (desummonedAt IS NOT NULL))
            AND (wasDigested IS NULL OR wasReleased IS NULL) = (desummonedAt IS NULL)),
    --- The digesting summoned unit's instance ID must be set only if wasDigested is TRUE.
    CONSTRAINT SummonedUnit_DigesterForDigestedOnly CHECK (
        digestedByInstanceId IS NULL OR wasDigested IS TRUE)
);

--- No more than one instance of a particular unit may be summoned by the same player.
--- Once the previous instance has been desummoned (by any method), the unit may be summoned again.
CREATE UNIQUE INDEX IF NOT EXISTS SummonedUnit_OneInstancePerUnitPerPlayer
    ON SummonedUnit (playerId, unitId)
    WHERE (desummonedAt IS NULL);
