import define from "../../define.js";
import { Instances } from "../../../../models/index.js";
import { fetchMeta } from "../../../../misc/fetch-meta.js";
import { sqlLikeEscape } from "../../../../misc/sql-like-escape.js";
export const meta = {
    tags: [
        "federation"
    ],
    requireCredential: false,
    requireCredentialPrivateMode: true,
    res: {
        type: "array",
        optional: false,
        nullable: false,
        items: {
            type: "object",
            optional: false,
            nullable: false,
            ref: "FederationInstance"
        }
    }
};
export const paramDef = {
    type: "object",
    properties: {
        host: {
            type: "string",
            nullable: true,
            description: "Omit or use `null` to not filter by host."
        },
        blocked: {
            type: "boolean",
            nullable: true
        },
        notResponding: {
            type: "boolean",
            nullable: true
        },
        suspended: {
            type: "boolean",
            nullable: true
        },
        federating: {
            type: "boolean",
            nullable: true
        },
        silenced: {
            type: "boolean",
            nullable: true
        },
        subscribing: {
            type: "boolean",
            nullable: true
        },
        publishing: {
            type: "boolean",
            nullable: true
        },
        limit: {
            type: "integer",
            minimum: 1,
            maximum: 100,
            default: 30
        },
        offset: {
            type: "integer",
            default: 0
        },
        sort: {
            type: "string"
        }
    },
    required: []
};
export default define(meta, paramDef, async (ps, me)=>{
    if (!me) {
        ps.blocked = false;
        ps.suspended = false;
        ps.silenced = false;
    }
    const query = Instances.createQueryBuilder("instance");
    switch(ps.sort){
        case "+pubSub":
            query.orderBy("instance.followingCount", "DESC").orderBy("instance.followersCount", "DESC");
            break;
        case "-pubSub":
            query.orderBy("instance.followingCount", "ASC").orderBy("instance.followersCount", "ASC");
            break;
        case "+notes":
            query.orderBy("instance.notesCount", "DESC");
            break;
        case "-notes":
            query.orderBy("instance.notesCount", "ASC");
            break;
        case "+users":
            query.orderBy("instance.usersCount", "DESC");
            break;
        case "-users":
            query.orderBy("instance.usersCount", "ASC");
            break;
        case "+following":
            query.orderBy("instance.followingCount", "DESC");
            break;
        case "-following":
            query.orderBy("instance.followingCount", "ASC");
            break;
        case "+followers":
            query.orderBy("instance.followersCount", "DESC");
            break;
        case "-followers":
            query.orderBy("instance.followersCount", "ASC");
            break;
        case "+caughtAt":
            query.orderBy("instance.caughtAt", "DESC");
            break;
        case "-caughtAt":
            query.orderBy("instance.caughtAt", "ASC");
            break;
        case "+lastCommunicatedAt":
            query.orderBy("instance.lastCommunicatedAt", "DESC");
            break;
        case "-lastCommunicatedAt":
            query.orderBy("instance.lastCommunicatedAt", "ASC");
            break;
        default:
            query.orderBy("instance.id", "DESC");
            break;
    }
    if (typeof ps.blocked === "boolean") {
        const meta = await fetchMeta(true);
        if (ps.blocked) {
            if (meta.blockedHosts.length === 0) {
                return [];
            }
            query.andWhere("instance.host IN (:...blocks)", {
                blocks: meta.blockedHosts
            });
        } else if (meta.blockedHosts.length > 0) {
            query.andWhere("instance.host NOT IN (:...blocks)", {
                blocks: meta.blockedHosts
            });
        }
    }
    if (typeof ps.silenced === "boolean") {
        const meta = await fetchMeta(true);
        if (ps.silenced) {
            if (meta.silencedHosts.length === 0) {
                return [];
            }
            query.andWhere("instance.host IN (:...silences)", {
                silences: meta.silencedHosts
            });
        } else if (meta.silencedHosts.length > 0) {
            query.andWhere("instance.host NOT IN (:...silences)", {
                silences: meta.silencedHosts
            });
        }
    }
    if (typeof ps.notResponding === "boolean") {
        if (ps.notResponding) {
            query.andWhere("instance.isNotResponding = TRUE");
        } else {
            query.andWhere("instance.isNotResponding = FALSE");
        }
    }
    if (typeof ps.suspended === "boolean") {
        if (ps.suspended) {
            query.andWhere("instance.isSuspended = TRUE");
        } else {
            query.andWhere("instance.isSuspended = FALSE");
        }
    }
    if (typeof ps.federating === "boolean") {
        if (ps.federating) {
            query.andWhere("((instance.followingCount > 0) OR (instance.followersCount > 0))");
        } else {
            query.andWhere("((instance.followingCount = 0) AND (instance.followersCount = 0))");
        }
    }
    if (typeof ps.subscribing === "boolean") {
        if (ps.subscribing) {
            query.andWhere("instance.followersCount > 0");
        } else {
            query.andWhere("instance.followersCount = 0");
        }
    }
    if (typeof ps.publishing === "boolean") {
        if (ps.publishing) {
            query.andWhere("instance.followingCount > 0");
        } else {
            query.andWhere("instance.followingCount = 0");
        }
    }
    if (ps.host) {
        query.andWhere("instance.host like :host", {
            host: `%${sqlLikeEscape(ps.host.toLowerCase())}%`
        });
    }
    const instances = await query.take(ps.limit).skip(ps.offset).getMany();
    return await Instances.packMany(instances, me !== null);
});
