import { Users, DriveFiles, Notes } from "../../../../models/index.js";
import { MAX_NOTE_TEXT_LENGTH } from "../../../../const.js";
import { ApiError } from "../../error.js";
import define from "../../define.js";
import { HOUR } from "../../../../const.js";
import editNote from "../../../../services/note/edit.js";
export const meta = {
    tags: [
        "notes"
    ],
    requireCredential: true,
    limit: {
        duration: HOUR,
        max: 300
    },
    kind: "write:notes",
    res: {
        type: "object",
        optional: false,
        nullable: false,
        ref: "Note"
    },
    errors: {
        cannotCreateAlreadyExpiredPoll: {
            message: "Poll is already expired.",
            code: "CANNOT_CREATE_ALREADY_EXPIRED_POLL",
            id: "04da457d-b083-4055-9082-955525eda5a5"
        },
        accountLocked: {
            message: "You migrated. Your account is now locked.",
            code: "ACCOUNT_LOCKED",
            id: "d390d7e1-8a5e-46ed-b625-06271cafd3d3"
        },
        needsEditId: {
            message: "You need to specify `editId`.",
            code: "NEEDS_EDIT_ID",
            id: "d697edc8-8c73-4de8-bded-35fd198b79e5"
        },
        noSuchNote: {
            message: "No such note.",
            code: "NO_SUCH_NOTE",
            id: "eef6c173-3010-4a23-8674-7c4fcaeba719"
        },
        youAreNotTheAuthor: {
            message: "You are not the author of this note.",
            code: "YOU_ARE_NOT_THE_AUTHOR",
            id: "c6e61685-411d-43d0-b90a-a448d2539001"
        },
        notLocalUser: {
            message: "You are not a local user.",
            code: "NOT_LOCAL_USER",
            id: "b907f407-2aa0-4283-800b-a2c56290b822"
        },
        cannotAddPollToPost: {
            message: "You cannot add a poll to a post.",
            code: "CANNOT_ADD_POLL",
            id: "e6a00055-21c8-4d69-a4d3-c26731cf6f18"
        },
        cannotRemovePollFromPost: {
            message: "You cannot remove a poll from a post.",
            code: "CANNOT_REMOVE_POLL",
            id: "7c4889f1-cb50-4a36-a740-9d04f097479b"
        }
    }
};
export const paramDef = {
    type: "object",
    properties: {
        editId: {
            type: "string",
            format: "misskey:id"
        },
        text: {
            type: "string",
            maxLength: MAX_NOTE_TEXT_LENGTH,
            nullable: true
        },
        cw: {
            type: "string",
            nullable: true,
            maxLength: 250
        },
        fileIds: {
            type: "array",
            uniqueItems: true,
            minItems: 1,
            maxItems: 16,
            items: {
                type: "string",
                format: "misskey:id"
            }
        },
        poll: {
            type: "object",
            nullable: true,
            properties: {
                choices: {
                    type: "array",
                    uniqueItems: true,
                    minItems: 2,
                    maxItems: 10,
                    items: {
                        type: "string",
                        minLength: 1,
                        maxLength: 50
                    }
                },
                multiple: {
                    type: "boolean",
                    default: false
                },
                expiresAt: {
                    type: "integer",
                    nullable: true
                },
                expiredAfter: {
                    type: "integer",
                    nullable: true,
                    minimum: 1
                }
            },
            required: [
                "choices"
            ]
        }
    },
    anyOf: [
        {
            // note with text, files and poll are optional
            properties: {
                text: {
                    type: "string",
                    minLength: 1,
                    maxLength: MAX_NOTE_TEXT_LENGTH,
                    nullable: false
                }
            },
            required: [
                "text"
            ]
        },
        {
            // note with files, text and poll are optional
            required: [
                "fileIds"
            ]
        },
        {
            // note with poll, text and files are optional
            properties: {
                poll: {
                    type: "object",
                    nullable: false
                }
            },
            required: [
                "poll"
            ]
        }
    ]
};
export default define(meta, paramDef, async (ps, user)=>{
    if (user.movedToUri != null) throw new ApiError(meta.errors.accountLocked);
    if (!Users.isLocalUser(user)) {
        throw new ApiError(meta.errors.notLocalUser);
    }
    if (!ps.editId) {
        throw new ApiError(meta.errors.needsEditId);
    }
    let note = await Notes.findOneBy({
        id: ps.editId
    });
    if (!note) {
        throw new ApiError(meta.errors.noSuchNote);
    }
    if (note.userId !== user.id) {
        throw new ApiError(meta.errors.youAreNotTheAuthor);
    }
    if (ps.poll?.expiresAt && new Date(ps.poll.expiresAt).getTime() < new Date().getTime()) {
        throw new ApiError(meta.errors.cannotCreateAlreadyExpiredPoll);
    }
    if (!note.hasPoll && ps.poll) {
        throw new ApiError(meta.errors.cannotAddPollToPost);
    }
    if (note.hasPoll && !ps.poll) {
        throw new ApiError(meta.errors.cannotRemovePollFromPost);
    }
    let files = [];
    const fileIds = ps.fileIds ?? null;
    if (fileIds != null) {
        files = await DriveFiles.createQueryBuilder("file").where("file.userId = :userId AND file.id IN (:...fileIds)", {
            userId: user.id,
            fileIds
        }).orderBy('array_position(ARRAY[:...fileIds], "id"::text)').setParameters({
            fileIds
        }).getMany();
    }
    note = await editNote(user, note, {
        text: ps.text,
        cw: ps.cw,
        poll: ps.poll ? {
            choices: ps.poll.choices,
            multiple: ps.poll.multiple,
            expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null
        } : null,
        files: files
    });
    return Notes.pack(note, user);
});
