import { IsNull } from "typeorm";
import { Users, Followings, UserProfiles } from "../../../../models/index.js";
import { toPunyNullable } from "../../../../misc/convert-host.js";
import define from "../../define.js";
import { ApiError } from "../../error.js";
import { makePaginationQuery } from "../../common/make-pagination-query.js";
export const meta = {
    tags: [
        "users"
    ],
    requireCredential: false,
    requireCredentialPrivateMode: true,
    description: "Show everyone that follows this user.",
    res: {
        type: "array",
        optional: false,
        nullable: false,
        items: {
            type: "object",
            optional: false,
            nullable: false,
            ref: "Following"
        }
    },
    errors: {
        noSuchUser: {
            message: "No such user.",
            code: "NO_SUCH_USER",
            id: "27fa5435-88ab-43de-9360-387de88727cd"
        },
        forbidden: {
            message: "Forbidden.",
            code: "FORBIDDEN",
            id: "3c6a84db-d619-26af-ca14-06232a21df8a"
        },
        nullFollowers: {
            message: "No followers found.",
            code: "NULL_FOLLOWERS",
            id: "174a6507-a6c2-4925-8e5d-92fd08aedc9e"
        }
    }
};
export const paramDef = {
    type: "object",
    properties: {
        sinceId: {
            type: "string",
            format: "misskey:id"
        },
        untilId: {
            type: "string",
            format: "misskey:id"
        },
        limit: {
            type: "integer",
            minimum: 1,
            maximum: 100,
            default: 10
        }
    },
    anyOf: [
        {
            properties: {
                userId: {
                    type: "string",
                    format: "misskey:id"
                }
            },
            required: [
                "userId"
            ]
        },
        {
            properties: {
                username: {
                    type: "string"
                },
                host: {
                    type: "string",
                    nullable: true,
                    description: "The local host is represented with `null`."
                }
            },
            required: [
                "username",
                "host"
            ]
        }
    ]
};
export default define(meta, paramDef, async (ps, me)=>{
    const user = await Users.findOneBy(ps.userId != null ? {
        id: ps.userId
    } : {
        usernameLower: ps.username.toLowerCase(),
        host: toPunyNullable(ps.host) ?? IsNull()
    });
    if (user == null) {
        throw new ApiError(meta.errors.noSuchUser);
    }
    const profile = await UserProfiles.findOneByOrFail({
        userId: user.id
    });
    if (profile.ffVisibility === "private") {
        if (me == null || me.id !== user.id) {
            throw new ApiError(meta.errors.forbidden);
        }
    } else if (profile.ffVisibility === "followers") {
        if (me == null) {
            throw new ApiError(meta.errors.forbidden);
        } else if (me.id !== user.id) {
            const isFollowed = await Followings.exist({
                where: {
                    followeeId: user.id,
                    followerId: me.id
                }
            });
            if (!isFollowed) {
                throw new ApiError(meta.errors.nullFollowers);
            }
        }
    }
    const query = makePaginationQuery(Followings.createQueryBuilder("following"), ps.sinceId, ps.untilId).andWhere("following.followeeId = :userId", {
        userId: user.id
    }).innerJoinAndSelect("following.follower", "follower");
    const followings = await query.take(ps.limit).getMany();
    return await Followings.packMany(followings, me, {
        populateFollower: true
    });
});
