'use strict';

const api = require('@btst/stack/plugins/api');
const db = require('../db.cjs');
const utils$1 = require('../utils.cjs');
const schemas = require('../schemas.cjs');
const getters = require('./getters.cjs');
const mutations = require('./mutations.cjs');
const queryKeyDefs = require('./query-key-defs.cjs');
const utils = require('../../utils.cjs');
const serializers = require('./serializers.cjs');

function createKanbanPrefetchForRoute(adapter) {
  return async function prefetchForRoute(key, qc, params) {
    switch (key) {
      case "boards": {
        const result = await getters.getAllBoards(adapter, { limit: 50, offset: 0 });
        qc.setQueryData(
          queryKeyDefs.KANBAN_QUERY_KEYS.boardsList({}),
          result.items.map(serializers.serializeBoard)
        );
        break;
      }
      case "board": {
        const boardId = params?.boardId ?? "";
        if (boardId) {
          const board = await getters.getBoardById(adapter, boardId);
          qc.setQueryData(
            queryKeyDefs.KANBAN_QUERY_KEYS.boardDetail(boardId),
            board ? serializers.serializeBoard(board) : null
          );
        }
        break;
      }
    }
  };
}
const kanbanBackendPlugin = (hooks) => api.defineBackendPlugin({
  name: "kanban",
  dbPlugin: db.kanbanSchema,
  api: (adapter) => ({
    getAllBoards: (params) => getters.getAllBoards(adapter, params),
    getBoardById: (id) => getters.getBoardById(adapter, id),
    prefetchForRoute: createKanbanPrefetchForRoute(adapter),
    // Mutations
    createTask: (input) => mutations.createKanbanTask(adapter, input),
    findOrCreateBoard: (slug, name, columnTitles) => mutations.findOrCreateKanbanBoard(adapter, slug, name, columnTitles),
    getColumnsByBoardId: (boardId) => mutations.getKanbanColumnsByBoardId(adapter, boardId)
  }),
  routes: (adapter) => {
    const listBoards = api.createEndpoint(
      "/boards",
      {
        method: "GET",
        query: schemas.BoardListQuerySchema
      },
      async (ctx) => {
        const { query, headers } = ctx;
        const context = { query, headers };
        try {
          if (hooks?.onBeforeListBoards) {
            await utils.runHookWithShim(
              () => hooks.onBeforeListBoards(query, context),
              ctx.error,
              "Unauthorized: Cannot list boards"
            );
          }
          const result = await getters.getAllBoards(adapter, query);
          if (hooks?.onBoardsRead) {
            await hooks.onBoardsRead(result.items, query, context);
          }
          return result;
        } catch (error) {
          if (hooks?.onListBoardsError) {
            await hooks.onListBoardsError(error, context);
          }
          throw error;
        }
      }
    );
    const getBoard = api.createEndpoint(
      "/boards/:id",
      {
        method: "GET"
      },
      async (ctx) => {
        const { params, headers } = ctx;
        const context = { params, headers };
        try {
          if (hooks?.onBeforeReadBoard) {
            await utils.runHookWithShim(
              () => hooks.onBeforeReadBoard(params.id, context),
              ctx.error,
              "Unauthorized: Cannot read board"
            );
          }
          const result = await getters.getBoardById(adapter, params.id);
          if (!result) {
            throw ctx.error(404, { message: "Board not found" });
          }
          if (hooks?.onBoardRead) {
            await hooks.onBoardRead(result, context);
          }
          return result;
        } catch (error) {
          if (hooks?.onReadBoardError) {
            await hooks.onReadBoardError(error, context);
          }
          throw error;
        }
      }
    );
    const createBoard = api.createEndpoint(
      "/boards",
      {
        method: "POST",
        body: schemas.createBoardSchema
      },
      async (ctx) => {
        const context = {
          body: ctx.body,
          headers: ctx.headers
        };
        try {
          if (hooks?.onBeforeCreateBoard) {
            await utils.runHookWithShim(
              () => hooks.onBeforeCreateBoard(ctx.body, context),
              ctx.error,
              "Unauthorized: Cannot create board"
            );
          }
          const { ...boardData } = ctx.body;
          const slug = utils$1.slugify(boardData.slug || boardData.name);
          if (!slug) {
            throw ctx.error(400, {
              message: "Invalid slug: must contain at least one alphanumeric character"
            });
          }
          let newBoard;
          const createdColumns = [];
          await adapter.transaction(async (tx) => {
            newBoard = await tx.create({
              model: "kanbanBoard",
              data: {
                ...boardData,
                slug,
                createdAt: /* @__PURE__ */ new Date(),
                updatedAt: /* @__PURE__ */ new Date()
              }
            });
            const defaultColumns = [
              { title: "To Do", order: 0, boardId: newBoard.id },
              { title: "In Progress", order: 1, boardId: newBoard.id },
              { title: "Done", order: 2, boardId: newBoard.id }
            ];
            for (const colData of defaultColumns) {
              const col = await tx.create({
                model: "kanbanColumn",
                data: {
                  ...colData,
                  createdAt: /* @__PURE__ */ new Date(),
                  updatedAt: /* @__PURE__ */ new Date()
                }
              });
              createdColumns.push({ ...col, tasks: [] });
            }
          });
          if (!newBoard) {
            throw ctx.error(500, {
              message: "Failed to create board"
            });
          }
          const result = { ...newBoard, columns: createdColumns };
          if (hooks?.onBoardCreated) {
            await hooks.onBoardCreated(result, context);
          }
          return result;
        } catch (error) {
          if (hooks?.onCreateBoardError) {
            await hooks.onCreateBoardError(error, context);
          }
          throw error;
        }
      }
    );
    const updateBoard = api.createEndpoint(
      "/boards/:id",
      {
        method: "PUT",
        body: schemas.updateBoardSchema.omit({ id: true })
      },
      async (ctx) => {
        const context = {
          body: ctx.body,
          params: ctx.params,
          headers: ctx.headers
        };
        try {
          if (hooks?.onBeforeUpdateBoard) {
            await utils.runHookWithShim(
              () => hooks.onBeforeUpdateBoard(
                ctx.params.id,
                { ...ctx.body, id: ctx.params.id },
                context
              ),
              ctx.error,
              "Unauthorized: Cannot update board"
            );
          }
          const { slug: rawSlug, ...restBoardData } = ctx.body;
          const slugified = rawSlug ? utils$1.slugify(rawSlug) : void 0;
          if (rawSlug && !slugified) {
            throw ctx.error(400, {
              message: "Invalid slug: must contain at least one alphanumeric character"
            });
          }
          const boardData = {
            ...restBoardData,
            ...slugified ? { slug: slugified } : {}
          };
          const updated = await adapter.update({
            model: "kanbanBoard",
            where: [{ field: "id", value: ctx.params.id }],
            update: {
              ...boardData,
              updatedAt: /* @__PURE__ */ new Date()
            }
          });
          if (!updated) {
            throw ctx.error(404, { message: "Board not found" });
          }
          if (hooks?.onBoardUpdated) {
            await hooks.onBoardUpdated(updated, context);
          }
          return updated;
        } catch (error) {
          if (hooks?.onUpdateBoardError) {
            await hooks.onUpdateBoardError(error, context);
          }
          throw error;
        }
      }
    );
    const deleteBoard = api.createEndpoint(
      "/boards/:id",
      {
        method: "DELETE"
      },
      async (ctx) => {
        const context = {
          params: ctx.params,
          headers: ctx.headers
        };
        try {
          const existingBoard = await adapter.findOne({
            model: "kanbanBoard",
            where: [
              { field: "id", value: ctx.params.id, operator: "eq" }
            ]
          });
          if (!existingBoard) {
            throw ctx.error(404, { message: "Board not found" });
          }
          if (hooks?.onBeforeDeleteBoard) {
            await utils.runHookWithShim(
              () => hooks.onBeforeDeleteBoard(ctx.params.id, context),
              ctx.error,
              "Unauthorized: Cannot delete board"
            );
          }
          await adapter.delete({
            model: "kanbanBoard",
            where: [{ field: "id", value: ctx.params.id }]
          });
          if (hooks?.onBoardDeleted) {
            await hooks.onBoardDeleted(ctx.params.id, context);
          }
          return { success: true };
        } catch (error) {
          if (hooks?.onDeleteBoardError) {
            await hooks.onDeleteBoardError(error, context);
          }
          throw error;
        }
      }
    );
    const createColumn = api.createEndpoint(
      "/columns",
      {
        method: "POST",
        body: schemas.createColumnSchema
      },
      async (ctx) => {
        const context = {
          body: ctx.body,
          headers: ctx.headers
        };
        try {
          if (hooks?.onBeforeCreateColumn) {
            await utils.runHookWithShim(
              () => hooks.onBeforeCreateColumn(ctx.body, context),
              ctx.error,
              "Unauthorized: Cannot create column"
            );
          }
          const existingColumns = await adapter.findMany({
            model: "kanbanColumn",
            where: [
              {
                field: "boardId",
                value: ctx.body.boardId,
                operator: "eq"
              }
            ]
          });
          const nextOrder = existingColumns.length > 0 ? Math.max(...existingColumns.map((c) => c.order)) + 1 : 0;
          const newColumn = await adapter.create({
            model: "kanbanColumn",
            data: {
              ...ctx.body,
              order: ctx.body.order ?? nextOrder,
              createdAt: /* @__PURE__ */ new Date(),
              updatedAt: /* @__PURE__ */ new Date()
            }
          });
          if (hooks?.onColumnCreated) {
            await hooks.onColumnCreated(newColumn, context);
          }
          return newColumn;
        } catch (error) {
          throw error;
        }
      }
    );
    const updateColumn = api.createEndpoint(
      "/columns/:id",
      {
        method: "PUT",
        body: schemas.updateColumnSchema.omit({ id: true })
      },
      async (ctx) => {
        const context = {
          body: ctx.body,
          params: ctx.params,
          headers: ctx.headers
        };
        try {
          if (hooks?.onBeforeUpdateColumn) {
            await utils.runHookWithShim(
              () => hooks.onBeforeUpdateColumn(
                ctx.params.id,
                { ...ctx.body, id: ctx.params.id },
                context
              ),
              ctx.error,
              "Unauthorized: Cannot update column"
            );
          }
          const updated = await adapter.update({
            model: "kanbanColumn",
            where: [{ field: "id", value: ctx.params.id }],
            update: {
              ...ctx.body,
              updatedAt: /* @__PURE__ */ new Date()
            }
          });
          if (!updated) {
            throw ctx.error(404, { message: "Column not found" });
          }
          if (hooks?.onColumnUpdated) {
            await hooks.onColumnUpdated(updated, context);
          }
          return updated;
        } catch (error) {
          throw error;
        }
      }
    );
    const deleteColumn = api.createEndpoint(
      "/columns/:id",
      {
        method: "DELETE"
      },
      async (ctx) => {
        const context = {
          params: ctx.params,
          headers: ctx.headers
        };
        try {
          const existingColumn = await adapter.findOne({
            model: "kanbanColumn",
            where: [
              { field: "id", value: ctx.params.id, operator: "eq" }
            ]
          });
          if (!existingColumn) {
            throw ctx.error(404, { message: "Column not found" });
          }
          if (hooks?.onBeforeDeleteColumn) {
            await utils.runHookWithShim(
              () => hooks.onBeforeDeleteColumn(ctx.params.id, context),
              ctx.error,
              "Unauthorized: Cannot delete column"
            );
          }
          await adapter.delete({
            model: "kanbanColumn",
            where: [{ field: "id", value: ctx.params.id }]
          });
          if (hooks?.onColumnDeleted) {
            await hooks.onColumnDeleted(ctx.params.id, context);
          }
          return { success: true };
        } catch (error) {
          throw error;
        }
      }
    );
    const reorderColumns = api.createEndpoint(
      "/columns/reorder",
      {
        method: "POST",
        body: schemas.reorderColumnsSchema
      },
      async (ctx) => {
        const { boardId, columnIds } = ctx.body;
        const context = {
          body: ctx.body,
          headers: ctx.headers
        };
        if (hooks?.onBeforeUpdateColumn) {
          for (let i = 0; i < columnIds.length; i++) {
            const columnId = columnIds[i];
            if (!columnId) continue;
            await utils.runHookWithShim(
              () => hooks.onBeforeUpdateColumn(
                columnId,
                { id: columnId, order: i },
                context
              ),
              ctx.error,
              "Unauthorized: Cannot reorder columns"
            );
          }
        }
        const updatedColumns = [];
        await adapter.transaction(async (tx) => {
          for (let i = 0; i < columnIds.length; i++) {
            const columnId = columnIds[i];
            if (!columnId) continue;
            const updated = await tx.update({
              model: "kanbanColumn",
              where: [
                { field: "id", value: columnId },
                { field: "boardId", value: boardId, operator: "eq" }
              ],
              update: { order: i, updatedAt: /* @__PURE__ */ new Date() }
            });
            if (updated) {
              updatedColumns.push(updated);
            }
          }
        });
        if (hooks?.onColumnUpdated) {
          for (const column of updatedColumns) {
            await hooks.onColumnUpdated(column, context);
          }
        }
        return { success: true };
      }
    );
    const createTask = api.createEndpoint(
      "/tasks",
      {
        method: "POST",
        body: schemas.createTaskSchema
      },
      async (ctx) => {
        const context = {
          body: ctx.body,
          headers: ctx.headers
        };
        try {
          if (hooks?.onBeforeCreateTask) {
            await utils.runHookWithShim(
              () => hooks.onBeforeCreateTask(ctx.body, context),
              ctx.error,
              "Unauthorized: Cannot create task"
            );
          }
          const existingTasks = await adapter.findMany({
            model: "kanbanTask",
            where: [
              {
                field: "columnId",
                value: ctx.body.columnId,
                operator: "eq"
              }
            ]
          });
          const nextOrder = existingTasks.length > 0 ? Math.max(...existingTasks.map((t) => t.order)) + 1 : 0;
          const taskData = {
            title: ctx.body.title,
            columnId: ctx.body.columnId,
            description: ctx.body.description,
            priority: ctx.body.priority || "MEDIUM",
            order: ctx.body.order ?? nextOrder,
            assigneeId: ctx.body.assigneeId ?? void 0,
            isArchived: ctx.body.isArchived ?? false,
            createdAt: /* @__PURE__ */ new Date(),
            updatedAt: /* @__PURE__ */ new Date()
          };
          const newTask = await adapter.create({
            model: "kanbanTask",
            data: taskData
          });
          if (hooks?.onTaskCreated) {
            await hooks.onTaskCreated(newTask, context);
          }
          return newTask;
        } catch (error) {
          throw error;
        }
      }
    );
    const updateTask = api.createEndpoint(
      "/tasks/:id",
      {
        method: "PUT",
        body: schemas.updateTaskSchema.omit({ id: true })
      },
      async (ctx) => {
        const context = {
          body: ctx.body,
          params: ctx.params,
          headers: ctx.headers
        };
        try {
          if (hooks?.onBeforeUpdateTask) {
            await utils.runHookWithShim(
              () => hooks.onBeforeUpdateTask(
                ctx.params.id,
                { ...ctx.body, id: ctx.params.id },
                context
              ),
              ctx.error,
              "Unauthorized: Cannot update task"
            );
          }
          const updated = await adapter.update({
            model: "kanbanTask",
            where: [{ field: "id", value: ctx.params.id }],
            update: {
              ...ctx.body,
              updatedAt: /* @__PURE__ */ new Date()
            }
          });
          if (!updated) {
            throw ctx.error(404, { message: "Task not found" });
          }
          if (hooks?.onTaskUpdated) {
            await hooks.onTaskUpdated(updated, context);
          }
          return updated;
        } catch (error) {
          throw error;
        }
      }
    );
    const deleteTask = api.createEndpoint(
      "/tasks/:id",
      {
        method: "DELETE"
      },
      async (ctx) => {
        const context = {
          params: ctx.params,
          headers: ctx.headers
        };
        try {
          const existingTask = await adapter.findOne({
            model: "kanbanTask",
            where: [
              { field: "id", value: ctx.params.id, operator: "eq" }
            ]
          });
          if (!existingTask) {
            throw ctx.error(404, { message: "Task not found" });
          }
          if (hooks?.onBeforeDeleteTask) {
            await utils.runHookWithShim(
              () => hooks.onBeforeDeleteTask(ctx.params.id, context),
              ctx.error,
              "Unauthorized: Cannot delete task"
            );
          }
          await adapter.delete({
            model: "kanbanTask",
            where: [{ field: "id", value: ctx.params.id }]
          });
          if (hooks?.onTaskDeleted) {
            await hooks.onTaskDeleted(ctx.params.id, context);
          }
          return { success: true };
        } catch (error) {
          throw error;
        }
      }
    );
    const moveTask = api.createEndpoint(
      "/tasks/move",
      {
        method: "POST",
        body: schemas.moveTaskSchema
      },
      async (ctx) => {
        const { taskId, targetColumnId, targetOrder } = ctx.body;
        const context = {
          body: ctx.body,
          headers: ctx.headers
        };
        const task = await adapter.findOne({
          model: "kanbanTask",
          where: [{ field: "id", value: taskId, operator: "eq" }]
        });
        if (!task) {
          throw ctx.error(404, { message: "Task not found" });
        }
        if (hooks?.onBeforeUpdateTask) {
          await utils.runHookWithShim(
            () => hooks.onBeforeUpdateTask(
              taskId,
              { id: taskId, columnId: targetColumnId, order: targetOrder },
              context
            ),
            ctx.error,
            "Unauthorized: Cannot move task"
          );
        }
        const updated = await adapter.update({
          model: "kanbanTask",
          where: [{ field: "id", value: taskId }],
          update: {
            columnId: targetColumnId,
            order: targetOrder,
            updatedAt: /* @__PURE__ */ new Date()
          }
        });
        if (!updated) {
          throw ctx.error(404, { message: "Task not found" });
        }
        if (hooks?.onTaskUpdated) {
          await hooks.onTaskUpdated(updated, context);
        }
        return updated;
      }
    );
    const reorderTasks = api.createEndpoint(
      "/tasks/reorder",
      {
        method: "POST",
        body: schemas.reorderTasksSchema
      },
      async (ctx) => {
        const { columnId, taskIds } = ctx.body;
        const context = {
          body: ctx.body,
          headers: ctx.headers
        };
        if (hooks?.onBeforeUpdateTask) {
          for (let i = 0; i < taskIds.length; i++) {
            const taskId = taskIds[i];
            if (!taskId) continue;
            await utils.runHookWithShim(
              () => hooks.onBeforeUpdateTask(
                taskId,
                { id: taskId, order: i },
                context
              ),
              ctx.error,
              "Unauthorized: Cannot reorder tasks"
            );
          }
        }
        const updatedTasks = [];
        await adapter.transaction(async (tx) => {
          for (let i = 0; i < taskIds.length; i++) {
            const taskId = taskIds[i];
            if (!taskId) continue;
            const updated = await tx.update({
              model: "kanbanTask",
              where: [
                { field: "id", value: taskId },
                {
                  field: "columnId",
                  value: columnId,
                  operator: "eq"
                }
              ],
              update: { order: i, updatedAt: /* @__PURE__ */ new Date() }
            });
            if (updated) {
              updatedTasks.push(updated);
            }
          }
        });
        if (hooks?.onTaskUpdated) {
          for (const task of updatedTasks) {
            await hooks.onTaskUpdated(task, context);
          }
        }
        return { success: true };
      }
    );
    return {
      listBoards,
      getBoard,
      createBoard,
      updateBoard,
      deleteBoard,
      createColumn,
      updateColumn,
      deleteColumn,
      reorderColumns,
      createTask,
      updateTask,
      deleteTask,
      moveTask,
      reorderTasks
    };
  }
});

exports.kanbanBackendPlugin = kanbanBackendPlugin;
