import { Brackets } from "typeorm";
import { Followings, Users } from "../../../../models/index.js";
import define from "../../define.js";
import { sqlLikeEscape } from "../../../../misc/sql-like-escape.js";
export const meta = {
    tags: [
        "users"
    ],
    requireCredential: false,
    requireCredentialPrivateMode: true,
    description: "Search for a user by username and/or host.",
    res: {
        type: "array",
        optional: false,
        nullable: false,
        items: {
            type: "object",
            optional: false,
            nullable: false,
            ref: "User"
        }
    }
};
export const paramDef = {
    type: "object",
    properties: {
        username: {
            type: "string",
            nullable: true
        },
        host: {
            type: "string",
            nullable: true
        },
        limit: {
            type: "integer",
            minimum: 1,
            maximum: 100,
            default: 10
        },
        maxDaysSinceLastActive: {
            type: "integer",
            minimum: 1,
            maximum: 1000,
            nullable: true
        },
        detail: {
            type: "boolean",
            default: true
        }
    },
    anyOf: [
        {
            required: [
                "username"
            ]
        },
        {
            required: [
                "host"
            ]
        }
    ]
};
// TODO: avatar,bannerをJOINしたいけどエラーになる
export default define(meta, paramDef, async (ps, me)=>{
    const activeThreshold = ps.maxDaysSinceLastActive ? new Date(Date.now() - 1000 * 60 * 60 * 24 * ps.maxDaysSinceLastActive) : null;
    if (ps.host) {
        const q = Users.createQueryBuilder("user").where("user.isSuspended = FALSE").andWhere("user.host LIKE :host", {
            host: `${sqlLikeEscape(ps.host.toLowerCase())}%`
        });
        if (ps.username) {
            q.andWhere("user.usernameLower LIKE :username", {
                username: `${sqlLikeEscape(ps.username.toLowerCase())}%`
            });
        }
        q.andWhere("user.updatedAt IS NOT NULL");
        q.orderBy("user.updatedAt", "DESC");
        const users = await q.take(ps.limit).getMany();
        return await Users.packMany(users, me, {
            detail: ps.detail
        });
    } else if (ps.username) {
        let users = [];
        if (me) {
            const followingQuery = Followings.createQueryBuilder("following").select("following.followeeId").where("following.followerId = :followerId", {
                followerId: me.id
            });
            const query = Users.createQueryBuilder("user").where(`user.id IN (${followingQuery.getQuery()})`).andWhere("user.isSuspended = FALSE").andWhere("user.usernameLower LIKE :username", {
                username: `${sqlLikeEscape(ps.username.toLowerCase())}%`
            });
            if (activeThreshold) {
                query.andWhere(new Brackets((qb)=>{
                    qb.where("user.updatedAt IS NULL").orWhere("user.updatedAt > :activeThreshold", {
                        activeThreshold: activeThreshold
                    });
                }));
            }
            query.setParameters(followingQuery.getParameters());
            users = await query.orderBy("user.usernameLower", "ASC").take(ps.limit).getMany();
            if (users.length < ps.limit) {
                const otherQuery = await Users.createQueryBuilder("user").where(`user.id NOT IN (${followingQuery.getQuery()})`).andWhere("user.isSuspended = FALSE").andWhere("user.usernameLower LIKE :username", {
                    username: `${sqlLikeEscape(ps.username.toLowerCase())}%`
                }).andWhere("user.updatedAt IS NOT NULL");
                otherQuery.setParameters(followingQuery.getParameters());
                const otherUsers = await otherQuery.orderBy("user.updatedAt", "DESC").take(ps.limit - users.length).getMany();
                users = users.concat(otherUsers);
            }
        } else {
            users = await Users.createQueryBuilder("user").where("user.isSuspended = FALSE").andWhere("user.usernameLower LIKE :username", {
                username: `${sqlLikeEscape(ps.username.toLowerCase())}%`
            }).andWhere("user.updatedAt IS NOT NULL").orderBy("user.updatedAt", "DESC").take(ps.limit - users.length).getMany();
        }
        return await Users.packMany(users, me, {
            detail: !!ps.detail
        });
    }
    return [];
});
