import { requireAuth } from "../security/http-auth.js";
import { assertOwnership } from "../security/ownership.js";
export function registerRepoProposalRoutes(app, config, deps) {
    const { repoService, repoProposalService } = deps;
    const validStatuses = new Set(["open", "in_progress", "done"]);
    const validPriorities = new Set(["low", "normal", "high"]);
    const datePattern = /^\d{4}-\d{2}-\d{2}$/;
    function normalizeTags(value) {
        if (value === undefined)
            return undefined;
        if (!Array.isArray(value))
            return [];
        return [...new Set(value
                .filter((tag) => typeof tag === "string")
                .map((tag) => tag.trim().toLowerCase())
                .filter(Boolean))]
            .slice(0, 12);
    }
    function normalizeDueDate(value) {
        if (value === undefined)
            return undefined;
        if (value === null || value === "")
            return null;
        return typeof value === "string" && datePattern.test(value) ? value : null;
    }
    function getOwnedRepo(repoId, userId) {
        const repo = repoService.getById(repoId);
        return repo?.userId === userId ? repo : null;
    }
    function getOwnedProposal(id, userId) {
        const proposal = repoProposalService.getById(id);
        return proposal?.userId === userId ? proposal : null;
    }
    app.get("/api/repos/:repoId/proposals", async (request, reply) => {
        const user = await requireAuth(request, reply, config.jwtSecret);
        if (!user)
            return;
        const repo = getOwnedRepo(request.params.repoId, user.id);
        if (!assertOwnership(reply, repo, user.id, "Repository not found"))
            return;
        return { proposals: repoProposalService.listByRepo(repo.id) };
    });
    app.get("/api/repos/:repoId/todos", async (request, reply) => {
        const user = await requireAuth(request, reply, config.jwtSecret);
        if (!user)
            return;
        const repo = getOwnedRepo(request.params.repoId, user.id);
        if (!assertOwnership(reply, repo, user.id, "Repository not found"))
            return;
        return { todos: repoProposalService.listByRepo(repo.id) };
    });
    app.post("/api/repos/:repoId/proposals", async (request, reply) => {
        const user = await requireAuth(request, reply, config.jwtSecret);
        if (!user)
            return;
        const repo = getOwnedRepo(request.params.repoId, user.id);
        if (!assertOwnership(reply, repo, user.id, "Repository not found"))
            return;
        const body = request.body;
        const message = body.message?.trim() ?? "";
        if (!message) {
            return reply.status(400).send({ error: "message is required" });
        }
        const proposal = repoProposalService.create({
            repoId: repo.id,
            userId: user.id,
            message,
            status: validStatuses.has(body.status ?? "") ? body.status : undefined,
            priority: validPriorities.has(body.priority ?? "") ? body.priority : undefined,
            dueDate: normalizeDueDate(body.dueDate),
            tags: normalizeTags(body.tags),
            sourceThreadId: body.sourceThreadId,
            sourceThreadTitle: body.sourceThreadTitle,
        });
        return reply.status(201).send({ proposal });
    });
    app.post("/api/repos/:repoId/todos", async (request, reply) => {
        const user = await requireAuth(request, reply, config.jwtSecret);
        if (!user)
            return;
        const repo = getOwnedRepo(request.params.repoId, user.id);
        if (!assertOwnership(reply, repo, user.id, "Repository not found"))
            return;
        const body = request.body;
        const message = body.message?.trim() ?? "";
        if (!message) {
            return reply.status(400).send({ error: "message is required" });
        }
        const todo = repoProposalService.create({
            repoId: repo.id,
            userId: user.id,
            message,
            status: validStatuses.has(body.status ?? "") ? body.status : undefined,
            priority: validPriorities.has(body.priority ?? "") ? body.priority : undefined,
            dueDate: normalizeDueDate(body.dueDate),
            tags: normalizeTags(body.tags),
            sourceThreadId: body.sourceThreadId,
            sourceThreadTitle: body.sourceThreadTitle,
        });
        return reply.status(201).send({ todo });
    });
    app.patch("/api/repo-proposals/:id", async (request, reply) => {
        const user = await requireAuth(request, reply, config.jwtSecret);
        if (!user)
            return;
        const existing = getOwnedProposal(request.params.id, user.id);
        if (!assertOwnership(reply, existing, user.id, "Todo not found"))
            return;
        const body = request.body;
        const message = body.message?.trim();
        if (message !== undefined && !message) {
            return reply.status(400).send({ error: "message must not be empty" });
        }
        if (body.status !== undefined && !validStatuses.has(body.status)) {
            return reply.status(400).send({ error: "invalid status" });
        }
        if (body.priority !== undefined && !validPriorities.has(body.priority)) {
            return reply.status(400).send({ error: "invalid priority" });
        }
        const proposal = repoProposalService.update(existing.id, {
            message,
            status: body.status,
            priority: body.priority,
            dueDate: normalizeDueDate(body.dueDate),
            tags: normalizeTags(body.tags),
        });
        return { proposal };
    });
    app.patch("/api/jait-todos/:id", async (request, reply) => {
        const user = await requireAuth(request, reply, config.jwtSecret);
        if (!user)
            return;
        const existing = getOwnedProposal(request.params.id, user.id);
        if (!assertOwnership(reply, existing, user.id, "Todo not found"))
            return;
        const body = request.body;
        const message = body.message?.trim();
        if (message !== undefined && !message) {
            return reply.status(400).send({ error: "message must not be empty" });
        }
        if (body.status !== undefined && !validStatuses.has(body.status)) {
            return reply.status(400).send({ error: "invalid status" });
        }
        if (body.priority !== undefined && !validPriorities.has(body.priority)) {
            return reply.status(400).send({ error: "invalid priority" });
        }
        const todo = repoProposalService.update(existing.id, {
            message,
            status: body.status,
            priority: body.priority,
            dueDate: normalizeDueDate(body.dueDate),
            tags: normalizeTags(body.tags),
        });
        return { todo };
    });
    app.delete("/api/repo-proposals/:id", async (request, reply) => {
        const user = await requireAuth(request, reply, config.jwtSecret);
        if (!user)
            return;
        const existing = getOwnedProposal(request.params.id, user.id);
        if (!assertOwnership(reply, existing, user.id, "Todo not found"))
            return;
        repoProposalService.delete(existing.id);
        return { ok: true };
    });
    app.delete("/api/jait-todos/:id", async (request, reply) => {
        const user = await requireAuth(request, reply, config.jwtSecret);
        if (!user)
            return;
        const existing = getOwnedProposal(request.params.id, user.id);
        if (!assertOwnership(reply, existing, user.id, "Todo not found"))
            return;
        repoProposalService.delete(existing.id);
        return { ok: true };
    });
}
//# sourceMappingURL=repo-proposals.js.map