import define from "../../define.js";
import { ApiError } from "../../error.js";
import { getUser } from "../../common/getters.js";
import { MessagingMessages, UserGroups, UserGroupJoinings, Users } from "../../../../models/index.js";
import { makePaginationQuery } from "../../common/make-pagination-query.js";
import { Brackets } from "typeorm";
import { readUserMessagingMessage, readGroupMessagingMessage, deliverReadActivity } from "../../common/read-messaging-message.js";
export const meta = {
    tags: [
        "messaging"
    ],
    requireCredential: true,
    kind: "read:messaging",
    res: {
        type: "array",
        optional: false,
        nullable: false,
        items: {
            type: "object",
            optional: false,
            nullable: false,
            ref: "MessagingMessage"
        }
    },
    errors: {
        noSuchUser: {
            message: "No such user.",
            code: "NO_SUCH_USER",
            id: "11795c64-40ea-4198-b06e-3c873ed9039d"
        },
        noSuchGroup: {
            message: "No such group.",
            code: "NO_SUCH_GROUP",
            id: "c4d9f88c-9270-4632-b032-6ed8cee36f7f"
        },
        groupAccessDenied: {
            message: "You can not read messages of groups that you have not joined.",
            code: "GROUP_ACCESS_DENIED",
            id: "a053a8dd-a491-4718-8f87-50775aad9284"
        }
    }
};
export const paramDef = {
    type: "object",
    properties: {
        limit: {
            type: "integer",
            minimum: 1,
            maximum: 100,
            default: 10
        },
        sinceId: {
            type: "string",
            format: "misskey:id"
        },
        untilId: {
            type: "string",
            format: "misskey:id"
        },
        markAsRead: {
            type: "boolean",
            default: true
        }
    },
    anyOf: [
        {
            properties: {
                userId: {
                    type: "string",
                    format: "misskey:id"
                }
            },
            required: [
                "userId"
            ]
        },
        {
            properties: {
                groupId: {
                    type: "string",
                    format: "misskey:id"
                }
            },
            required: [
                "groupId"
            ]
        }
    ]
};
export default define(meta, paramDef, async (ps, user)=>{
    if (ps.userId != null) {
        // Fetch recipient (user)
        const recipient = await getUser(ps.userId).catch((e)=>{
            if (e.id === "15348ddd-432d-49c2-8a5a-8069753becff") throw new ApiError(meta.errors.noSuchUser);
            throw e;
        });
        const query = makePaginationQuery(MessagingMessages.createQueryBuilder("message"), ps.sinceId, ps.untilId).andWhere(new Brackets((qb)=>{
            qb.where(new Brackets((qb)=>{
                qb.where("message.userId = :meId").andWhere("message.recipientId = :recipientId");
            })).orWhere(new Brackets((qb)=>{
                qb.where("message.userId = :recipientId").andWhere("message.recipientId = :meId");
            }));
        })).setParameter("meId", user.id).setParameter("recipientId", recipient.id);
        const messages = await query.take(ps.limit).getMany();
        // Mark all as read
        if (ps.markAsRead) {
            readUserMessagingMessage(user.id, recipient.id, messages.filter((m)=>m.recipientId === user.id).map((x)=>x.id));
            // リモートユーザーとのメッセージだったら既読配信
            if (Users.isLocalUser(user) && Users.isRemoteUser(recipient)) {
                deliverReadActivity(user, recipient, messages);
            }
        }
        return await Promise.all(messages.map((message)=>MessagingMessages.pack(message, user, {
                populateRecipient: false
            })));
    } else if (ps.groupId != null) {
        // Fetch recipient (group)
        const recipientGroup = await UserGroups.findOneBy({
            id: ps.groupId
        });
        if (recipientGroup == null) {
            throw new ApiError(meta.errors.noSuchGroup);
        }
        // check joined
        const joining = await UserGroupJoinings.findOneBy({
            userId: user.id,
            userGroupId: recipientGroup.id
        });
        if (joining == null) {
            throw new ApiError(meta.errors.groupAccessDenied);
        }
        const query = makePaginationQuery(MessagingMessages.createQueryBuilder("message"), ps.sinceId, ps.untilId).andWhere("message.groupId = :groupId", {
            groupId: recipientGroup.id
        });
        const messages = await query.take(ps.limit).getMany();
        // Mark all as read
        if (ps.markAsRead) {
            readGroupMessagingMessage(user.id, recipientGroup.id, messages.map((x)=>x.id));
        }
        return await Promise.all(messages.map((message)=>MessagingMessages.pack(message, user, {
                populateGroup: false
            })));
    }
});
