import { Brackets } from "typeorm";
import { Notes, MemorietViews } from "../../../../models/index.js";
import { genId } from "../../../../misc/gen-id.js";
import define from "../../define.js";
import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js";
import { generateBlockedUserQuery } from "../../common/generate-block-query.js";
import { generateVisibilityQuery } from "../../common/generate-visibility-query.js";
export const meta = {
    tags: [
        "memoriet"
    ],
    requireCredential: false,
    requireCredentialPrivateMode: true,
    res: {
        type: "array",
        optional: false,
        nullable: false,
        items: {
            type: "object",
            optional: false,
            nullable: false,
            properties: {
                id: {
                    type: "string",
                    optional: false,
                    nullable: false
                },
                expiresAt: {
                    type: "string",
                    optional: false,
                    nullable: true
                },
                textLayers: {
                    type: "array",
                    optional: false,
                    nullable: false,
                    items: {
                        type: "object",
                        optional: false,
                        nullable: false
                    }
                },
                viewerCount: {
                    type: "number",
                    optional: false,
                    nullable: true
                },
                note: {
                    type: "object",
                    optional: false,
                    nullable: false,
                    ref: "Note"
                }
            }
        }
    }
};
export const paramDef = {
    type: "object",
    properties: {
        limit: {
            type: "integer",
            minimum: 1,
            maximum: 50,
            default: 20
        },
        offset: {
            type: "integer",
            minimum: 0,
            default: 0
        },
        userId: {
            type: "string",
            format: "misskey:id",
            nullable: true
        }
    },
    required: []
};
export default define(meta, paramDef, async (ps, user)=>{
    const query = Notes.createQueryBuilder("note").innerJoinAndSelect("note.user", "user").leftJoinAndSelect("note.reply", "reply").leftJoinAndSelect("note.renote", "renote").leftJoinAndSelect("reply.user", "replyUser").leftJoinAndSelect("renote.user", "renoteUser").innerJoin("memoriet", "memoriet", "memoriet.noteId = note.id").addSelect("memoriet.id", "memoriet_id").addSelect("memoriet.userId", "memoriet_userId").addSelect("memoriet.createdAt", "memoriet_createdAt").addSelect("memoriet.expiresAt", "memoriet_expiresAt").addSelect("memoriet.textLayers", "memoriet_textLayers").andWhere(new Brackets((qb)=>{
        qb.where("memoriet.expiresAt IS NULL").orWhere("memoriet.expiresAt > :now", {
            now: new Date()
        });
    }));
    if (ps.userId) query.andWhere("note.userId = :userId", {
        userId: ps.userId
    });
    generateVisibilityQuery(query, user);
    if (user) generateMutedUserQuery(query, user);
    if (user) generateBlockedUserQuery(query, user);
    const { entities, raw } = await query.orderBy("memoriet.createdAt", "DESC").skip(ps.offset).take(ps.limit).getRawAndEntities();
    if (user) {
        const now = new Date();
        for (const row of raw){
            if (row.memoriet_userId === user.id) continue;
            await MemorietViews.query(`INSERT INTO "memoriet_view" ("id", "createdAt", "viewedAt", "memorietId", "viewerId") VALUES ($1, $2, $3, $4, $5) ON CONFLICT ("memorietId", "viewerId") DO UPDATE SET "viewedAt" = EXCLUDED."viewedAt"`, [
                genId(),
                now,
                now,
                row.memoriet_id,
                user.id
            ]);
        }
    }
    const memorietIds = raw.map((row)=>row.memoriet_id);
    const viewerCounts = new Map();
    if (user && memorietIds.length > 0) {
        const counts = await MemorietViews.createQueryBuilder("view").select("view.memorietId", "memorietId").addSelect("COUNT(*)", "count").where("view.memorietId IN (:...memorietIds)", {
            memorietIds
        }).groupBy("view.memorietId").getRawMany();
        for (const count of counts){
            viewerCounts.set(count.memorietId, Number(count.count));
        }
    }
    const packed = await Notes.packMany(entities, user);
    return packed.map((note, index)=>({
            id: raw[index].memoriet_id,
            expiresAt: raw[index].memoriet_expiresAt?.toISOString?.() ?? raw[index].memoriet_expiresAt ?? null,
            textLayers: raw[index].memoriet_textLayers ?? [],
            viewerCount: user && raw[index].memoriet_userId === user.id ? viewerCounts.get(raw[index].memoriet_id) ?? 0 : null,
            note
        }));
});
