CREATE TABLE IF NOT EXISTS "channel"
(
    "id"        UUID    NOT NULL PRIMARY KEY DEFAULT uuid_generate_v7(),
    "name"      VARCHAR NOT NULL,
    "type"      INT2    NOT NULL,
    "position"  INT2    NOT NULL,
    "server_id" UUID REFERENCES "server" ("id") ON DELETE CASCADE,      -- only for server channels
    "parent"    UUID    REFERENCES "channel" ("id") ON DELETE SET NULL, -- only for server channels
    "owner_id"  UUID    REFERENCES "user" ("id") ON DELETE SET NULL     -- only for group channels
);

-- only for dm or group channels
CREATE TABLE IF NOT EXISTS "channel_recipient"
(
    "channel_id" UUID NOT NULL REFERENCES "channel" ("id") ON DELETE CASCADE,
    "user_id"    UUID NOT NULL REFERENCES "user" ("id") ON DELETE CASCADE,
    PRIMARY KEY ("channel_id", "user_id")
);

CREATE TABLE IF NOT EXISTS "message"
(
    "id"         UUID NOT NULL PRIMARY KEY DEFAULT uuid_generate_v7(),
    "author_id"  UUID NOT NULL REFERENCES "user" ("id") ON DELETE CASCADE,
    "channel_id" UUID NOT NULL REFERENCES "channel" ("id") ON DELETE CASCADE,
    "content"    TEXT NOT NULL
);

CREATE TABLE IF NOT EXISTS "message_attachment"
(
    "message_id" UUID NOT NULL REFERENCES "message" ON DELETE CASCADE,
    "file_id"    UUID NOT NULL REFERENCES "file" ON DELETE CASCADE,
    "order"      INT2 NOT NULL,
    PRIMARY KEY ("message_id", "file_id")
);

ALTER TABLE "channel"
    ADD COLUMN "last_message_id" UUID REFERENCES "message" ("id") ON DELETE SET NULL;


CREATE OR REPLACE FUNCTION create_dm_channel(
    user1_id UUID,
    user2_id UUID,
    channel_type INT2
)
    RETURNS UUID
    LANGUAGE plpgsql
AS
$$
DECLARE
    new_channel_id UUID;
    channel_name   VARCHAR;
BEGIN
    -- Validate parameters
    IF user1_id IS NULL OR user2_id IS NULL THEN
        RAISE EXCEPTION 'Both user IDs must be provided';
    END IF;

    IF user1_id = user2_id THEN
        RAISE EXCEPTION 'Cannot create a DM channel with the same user';
    END IF;

-- Check if users exist
    IF NOT exists (SELECT 1 FROM "user" WHERE id = user1_id) OR
       NOT exists (SELECT 1 FROM "user" WHERE id = user2_id) THEN
        RAISE EXCEPTION 'One or both users do not exist';
    END IF;

-- Check if DM already exists between these users
    IF exists (SELECT 1
               FROM channel c
                        JOIN channel_recipient cr1 ON c.id = cr1.channel_id AND cr1.user_id = user1_id
                        JOIN channel_recipient cr2 ON c.id = cr2.channel_id AND cr2.user_id = user2_id
               WHERE c.type = channel_type
                 AND (SELECT count(*) FROM channel_recipient WHERE channel_id = c.id) = 2) THEN
        -- Find and return the existing channel ID
        SELECT c.id
        INTO new_channel_id
        FROM channel c
                 JOIN channel_recipient cr1 ON c.id = cr1.channel_id AND cr1.user_id = user1_id
                 JOIN channel_recipient cr2 ON c.id = cr2.channel_id AND cr2.user_id = user2_id
        WHERE c.type = channel_type
          AND (SELECT count(*) FROM channel_recipient WHERE channel_id = c.id) = 2
        LIMIT 1;

        RAISE NOTICE 'DM channel already exists between these users with ID: %', new_channel_id;
        RETURN new_channel_id;
    END IF;

-- Generate channel name (conventionally uses user IDs in DMs)
    channel_name := concat(user1_id, '-', user2_id);

    -- Create new channel
    INSERT INTO "channel" ("name", "type", "position")
    VALUES (channel_name, channel_type, 0)
    RETURNING id INTO new_channel_id;

-- Add both users as recipients
    INSERT INTO "channel_recipient" ("channel_id", "user_id")
    VALUES (new_channel_id, user1_id),
           (new_channel_id, user2_id);

    RAISE NOTICE 'DM channel created with ID: %', new_channel_id;
    RETURN new_channel_id;
END;
$$;

CREATE OR REPLACE FUNCTION create_group_channel(
    p_creator_id UUID, -- The user initiating the group creation (will be owner)
    p_recipient_user_ids UUID[], -- Array of all user IDs for the group (must include creator)
    p_group_channel_type INT2 -- The channel type identifier for groups (e.g., 1)
)
    RETURNS UUID
    LANGUAGE plpgsql
AS
$$
DECLARE
    new_channel_id                         UUID;
    existing_channel_id                    UUID;
    final_channel_name                     VARCHAR;
    unique_sorted_recipient_ids            UUID[];
    num_recipients                         INT;
    uid                                    UUID;
    -- Threshold for detailed name vs. summary name
    MAX_MEMBERS_FOR_DETAILED_NAME CONSTANT INT := 3;
BEGIN
    -- Validate and process recipient IDs
    IF p_recipient_user_ids IS NULL OR array_length(p_recipient_user_ids, 1) IS NULL THEN
        RAISE EXCEPTION 'Recipient user IDs array must be provided and not empty.';
    END IF;

    -- Get unique, sorted recipient IDs for consistent checking and to avoid duplicates.
    SELECT array_agg(DISTINCT u ORDER BY u) INTO unique_sorted_recipient_ids FROM unnest(p_recipient_user_ids) u;
    num_recipients := array_length(unique_sorted_recipient_ids, 1);

    -- Validate minimum number of recipients for a group
    IF num_recipients < 1 THEN -- Groups typically have at least 2 members
        RAISE EXCEPTION 'Group channels (type %) must have at least 2 recipients. Found %.', p_group_channel_type, num_recipients;
    END IF;

    -- Create new group channel
    INSERT INTO "channel" ("name", "type", "position", "owner_id", "server_id", "parent")
    VALUES ('Group',
            p_group_channel_type,
            0, -- Default position
            p_creator_id,
            NULL, -- Not a server channel
            NULL -- Not a nested server channel
           )
    RETURNING id INTO new_channel_id;

    -- Add all recipients to the channel_recipient table
    INSERT INTO "channel_recipient" ("channel_id", "user_id")
    VALUES (new_channel_id, p_creator_id);

    INSERT INTO "channel_recipient" ("channel_id", "user_id")
    SELECT new_channel_id, r_id
    FROM unnest(unique_sorted_recipient_ids) AS r_id;

    RAISE NOTICE 'Group channel (type %) named "%" created with ID: % by owner % for recipients: %',
        p_group_channel_type, final_channel_name, new_channel_id, p_creator_id, unique_sorted_recipient_ids;
    RETURN new_channel_id;
END;
$$;
