// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

import type { Database } from 'better-sqlite3';

import type { LoggerType } from '../../types/Logging';

export default function updateToSchemaVersion45(
  currentVersion: number,
  db: Database,
  logger: LoggerType
): void {
  if (currentVersion >= 45) {
    return;
  }

  db.transaction(() => {
    db.exec(
      `
      --- Add column to messages table

      ALTER TABLE messages ADD COLUMN storyId STRING;

      --- Update important message indices

      DROP INDEX   messages_conversation;
      CREATE INDEX messages_conversation ON messages
        (conversationId, type, storyId, received_at);

      DROP INDEX   messages_unread;
      CREATE INDEX messages_unread ON messages
        (conversationId, readStatus, type, storyId) WHERE readStatus IS NOT NULL;

      --- Update attachment indices for All Media views

      DROP INDEX   messages_hasAttachments;
      CREATE INDEX messages_hasAttachments
        ON messages (conversationId, hasAttachments, received_at)
        WHERE type IS NOT 'story' AND storyId IS NULL;

      DROP INDEX   messages_hasFileAttachments;
      CREATE INDEX messages_hasFileAttachments
        ON messages (conversationId, hasFileAttachments, received_at)
        WHERE type IS NOT 'story' AND storyId IS NULL;

      DROP INDEX   messages_hasVisualMediaAttachments;
      CREATE INDEX messages_hasVisualMediaAttachments
        ON messages (conversationId, hasVisualMediaAttachments, received_at)
        WHERE type IS NOT 'story' AND storyId IS NULL;

      --- Message insert/update triggers to exclude stories and story replies

      DROP   TRIGGER messages_on_insert;
      CREATE TRIGGER messages_on_insert AFTER INSERT ON messages
      WHEN new.isViewOnce IS NOT 1 AND new.storyId IS NULL
      BEGIN
        INSERT INTO messages_fts
          (rowid, body)
        VALUES
          (new.rowid, new.body);
      END;

      DROP   TRIGGER messages_on_update;
      CREATE TRIGGER messages_on_update AFTER UPDATE ON messages
      WHEN
        (new.body IS NULL OR old.body IS NOT new.body) AND
         new.isViewOnce IS NOT 1 AND new.storyId IS NULL
      BEGIN
        DELETE FROM messages_fts WHERE rowid = old.rowid;
        INSERT INTO messages_fts
          (rowid, body)
        VALUES
          (new.rowid, new.body);
      END;

      --- Update delete trigger to remove storyReads

      DROP   TRIGGER messages_on_delete;
      CREATE TRIGGER messages_on_delete AFTER DELETE ON messages BEGIN
        DELETE FROM messages_fts WHERE rowid = old.rowid;
        DELETE FROM sendLogPayloads WHERE id IN (
          SELECT payloadId FROM sendLogMessageIds
          WHERE messageId = old.id
        );
        DELETE FROM reactions WHERE rowid IN (
          SELECT rowid FROM reactions
          WHERE messageId = old.id
        );
        DELETE FROM storyReads WHERE storyId = old.storyId;
      END;

      --- Story Read History

      CREATE TABLE storyReads (
        authorId STRING NOT NULL,
        conversationId STRING NOT NULL,
        storyId STRING NOT NULL,
        storyReadDate NUMBER NOT NULL,

        PRIMARY KEY (authorId, storyId)
      );

      CREATE INDEX storyReads_data ON storyReads (
        storyReadDate, authorId, conversationId
      );

      --- Story Distribution Lists

      CREATE TABLE storyDistributions(
        id STRING PRIMARY KEY NOT NULL,
        name TEXT,

        avatarUrlPath TEXT,
        avatarKey BLOB,
        senderKeyInfoJson STRING
      );

      CREATE TABLE storyDistributionMembers(
        listId STRING NOT NULL REFERENCES storyDistributions(id)
          ON DELETE CASCADE
          ON UPDATE CASCADE,
        uuid STRING NOT NULL,

        PRIMARY KEY (listId, uuid)
      )
      `
    );

    db.pragma('user_version = 45');
  })();

  logger.info('updateToSchemaVersion45: success!');
}