import { and, asc, eq, inArray, isNull } from "drizzle-orm";
import { addMediaToAlbumRequestSchema, createAlbumRequestSchema } from "@familyalbum/shared";
import { ApiError, notFound } from "../../../core/errors.js";
import { db } from "../../../core/db/client.js";
import { buildAuthHooks } from "../../../core/plugins/auth.js";
import { jsonSchema } from "../../../core/lib/json-schema.js";
import { buildFamilyAuthHooks } from "../plugins/auth.js";
import { albumMedia, albums, media } from "../db/schema.js";
import { serializeMedia } from "./media.js";
export function registerAlbumRoutes(app) {
    const { authenticate } = buildAuthHooks(app);
    const { requireFamilyMember } = buildFamilyAuthHooks(app);
    app.post("/families/:familyId/albums", {
        schema: { body: jsonSchema(createAlbumRequestSchema) },
        preHandler: [
            authenticate,
            requireFamilyMember({ familyParam: "familyId" }),
        ],
    }, async (request, reply) => {
        const ctx = request.familyContext;
        const { name } = request.body;
        const a = db
            .insert(albums)
            .values({ familyId: ctx.familyId, name })
            .returning()
            .all()[0];
        reply.status(201).send({
            id: a.id,
            familyId: a.familyId,
            name: a.name,
            coverMediaId: a.coverMediaId,
            createdAt: a.createdAt.toISOString(),
        });
    });
    app.get("/families/:familyId/albums", {
        preHandler: [
            authenticate,
            requireFamilyMember({ familyParam: "familyId" }),
        ],
    }, async (request, reply) => {
        const ctx = request.familyContext;
        const rows = db
            .select()
            .from(albums)
            .where(eq(albums.familyId, ctx.familyId))
            .orderBy(albums.createdAt)
            .all();
        reply.send(rows.map((a) => ({
            id: a.id,
            familyId: a.familyId,
            name: a.name,
            coverMediaId: a.coverMediaId,
            createdAt: a.createdAt.toISOString(),
        })));
    });
    app.get("/albums/:albumId", {
        preHandler: [
            authenticate,
            requireFamilyMember({ albumParam: "albumId" }),
        ],
    }, async (request, reply) => {
        const ctx = request.familyContext;
        const params = request.params;
        const [album] = db
            .select()
            .from(albums)
            .where(eq(albums.id, params.albumId))
            .limit(1)
            .all();
        if (!album)
            throw notFound();
        const mediaRows = db
            .select({ mediaId: albumMedia.mediaId })
            .from(albumMedia)
            .where(eq(albumMedia.albumId, params.albumId))
            .orderBy(asc(albumMedia.addedAt))
            .all();
        reply.send({
            id: album.id,
            familyId: album.familyId,
            name: album.name,
            coverMediaId: album.coverMediaId,
            createdAt: album.createdAt.toISOString(),
            mediaIds: mediaRows.map((m) => m.mediaId),
        });
    });
    /**
     * Médias d'un album (ordre d'ajout) — la grille mobile a besoin des
     * métadonnées complètes (nom, mime, capturedAt…), pas seulement des ids.
     */
    app.get("/albums/:albumId/media", {
        preHandler: [
            authenticate,
            requireFamilyMember({ albumParam: "albumId" }),
        ],
    }, async (request, reply) => {
        const params = request.params;
        const [album] = db
            .select()
            .from(albums)
            .where(eq(albums.id, params.albumId))
            .limit(1)
            .all();
        if (!album)
            throw notFound();
        const rows = db
            .select({ m: media })
            .from(albumMedia)
            .innerJoin(media, eq(media.id, albumMedia.mediaId))
            .where(and(eq(albumMedia.albumId, params.albumId), isNull(media.deletedAt)))
            .orderBy(asc(albumMedia.addedAt))
            .all();
        reply.send(rows.map((r) => serializeMedia(r.m)));
    });
    app.post("/albums/:albumId/media", {
        schema: { body: jsonSchema(addMediaToAlbumRequestSchema) },
        preHandler: [
            authenticate,
            requireFamilyMember({ albumParam: "albumId" }),
        ],
    }, async (request, reply) => {
        const ctx = request.familyContext;
        const params = request.params;
        const { mediaIds } = request.body;
        // les médias doivent appartenir à la même famille que l'album
        const valid = db
            .select({ id: media.id })
            .from(media)
            .where(and(inArray(media.id, mediaIds), eq(media.familyId, ctx.familyId), isNull(media.deletedAt)))
            .all()
            .map((r) => r.id);
        if (valid.length !== mediaIds.length) {
            throw new ApiError(400, "invalid_media", "Certains médias sont invalides ou hors famille");
        }
        for (const mediaId of valid) {
            db.insert(albumMedia)
                .values({ albumId: params.albumId, mediaId })
                .onConflictDoNothing()
                .run();
        }
        reply.send({ ok: true, added: valid.length });
    });
    app.delete("/albums/:albumId/media/:mediaId", {
        preHandler: [
            authenticate,
            requireFamilyMember({ albumParam: "albumId" }),
        ],
    }, async (request, reply) => {
        const params = request.params;
        db.delete(albumMedia)
            .where(and(eq(albumMedia.albumId, params.albumId), eq(albumMedia.mediaId, params.mediaId)))
            .run();
        reply.send({ ok: true });
    });
    app.delete("/albums/:albumId", {
        preHandler: [
            authenticate,
            requireFamilyMember({ albumParam: "albumId", minRole: "coadmin" }),
        ],
    }, async (request, reply) => {
        const params = request.params;
        db.delete(albums).where(eq(albums.id, params.albumId)).run();
        reply.send({ ok: true });
    });
}
//# sourceMappingURL=albums.js.map