import { In, IsNull } from "typeorm";
import { resolveUser } from "../../../../remote/resolve-user.js";
import { Users } from "../../../../models/index.js";
import define from "../../define.js";
import { apiLogger } from "../../logger.js";
import { ApiError } from "../../error.js";
import { fetchMeta } from "../../../../misc/fetch-meta.js";
import { shouldHideEUsersFor } from "../../common/generate-minor-badge-visibility-query.js";
export const meta = {
    tags: [
        "users"
    ],
    // TODO: determine if should allow this in private mode or to create a new endpoint just for 2fa
    requireCredential: false,
    requireCredentialPrivateMode: false,
    description: "Show the properties of a user.",
    res: {
        optional: false,
        nullable: false,
        oneOf: [
            {
                type: "object",
                ref: "UserDetailed"
            },
            {
                type: "array",
                items: {
                    type: "object",
                    ref: "UserDetailed"
                }
            }
        ]
    },
    errors: {
        failedToResolveRemoteUser: {
            message: "Failed to resolve remote user.",
            code: "FAILED_TO_RESOLVE_REMOTE_USER",
            id: "ef7b9be4-9cba-4e6f-ab41-90ed171c7d3c",
            kind: "server"
        },
        noSuchUser: {
            message: "No such user.",
            code: "NO_SUCH_USER",
            id: "4362f8dc-731f-4ad8-a694-be5a88922a24"
        }
    }
};
export const paramDef = {
    type: "object",
    anyOf: [
        {
            properties: {
                userId: {
                    type: "string"
                }
            },
            required: [
                "userId"
            ]
        },
        {
            properties: {
                userIds: {
                    type: "array",
                    uniqueItems: true,
                    items: {
                        type: "string"
                    }
                }
            },
            required: [
                "userIds"
            ]
        },
        {
            properties: {
                username: {
                    type: "string"
                },
                host: {
                    type: "string",
                    nullable: true,
                    description: "The local host is represented with `null`."
                }
            },
            required: [
                "username"
            ]
        }
    ]
};
export default define(meta, paramDef, async (ps, me)=>{
    let user;
    const isAdminOrModerator = me && (me.isAdmin || me.isModerator);
    if (ps.userIds) {
        if (ps.userIds.length === 0) {
            return [];
        }
        const isUrl = ps.userIds[0].startsWith("http");
        let users;
        if (isUrl) {
            users = await Users.findBy(isAdminOrModerator ? {
                uri: In(ps.userIds)
            } : {
                uri: In(ps.userIds),
                isSuspended: false
            });
        } else {
            users = await Users.findBy(isAdminOrModerator ? {
                id: In(ps.userIds)
            } : {
                id: In(ps.userIds),
                isSuspended: false
            });
        }
        // リクエストされた通りに並べ替え
        const _users = [];
        for (const id of ps.userIds){
            const res = users.find((x)=>isUrl ? x.uri === id : x.id === id);
            if (res && !(shouldHideEUsersFor(me) && res.id !== me.id && (res.minorBadges ?? []).includes("E"))) _users.push(res);
        }
        return await Promise.all(_users.map((u)=>Users.pack(u, me, {
                detail: true
            })));
    } else {
        // Lookup user
        if (typeof ps.host === "string" && typeof ps.username === "string") {
            user = await resolveUser(ps.username, ps.host).catch((e)=>{
                apiLogger.warn(`failed to resolve remote user: ${e}`);
                throw new ApiError(meta.errors.failedToResolveRemoteUser);
            });
        } else {
            const q = ps.userId != null ? ps.userId.startsWith("http") ? {
                uri: ps.userId
            } : {
                id: ps.userId
            } : {
                usernameLower: ps.username.toLowerCase(),
                host: IsNull()
            };
            user = await Users.findOneBy(q);
        }
        if (user == null || !isAdminOrModerator && user.isSuspended || shouldHideEUsersFor(me) && user.id !== me.id && (user.minorBadges ?? []).includes("E")) {
            throw new ApiError(meta.errors.noSuchUser);
        }
        // apiLogger.debug(`packed (detailed): ${JSON.stringify(await Users.pack(user, me, {detail: true}))}`);
        // apiLogger.debug(`packed (private): ${JSON.stringify(await Users.pack(user, me, {detail: true, isPrivateMode: true}))}`);
        const serverMeta = await fetchMeta();
        return await Users.pack(user, me, {
            detail: true,
            isPrivateMode: me !== null ? false : serverMeta.privateMode
        });
    }
});
