import { NextResponse } from "next/server";
import { z } from "zod";
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
import { resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
import { LockMode } from "@mikro-orm/core";
import { StaffTimeEntry, StaffTimeEntrySegment } from "../../../../../data/entities.js";
import { getStaffMemberByUserId } from "../../../../../lib/staffMemberResolver.js";
import {
  resolveUserFeatures,
  runStaffMutationGuardAfterSuccess,
  runStaffMutationGuards
} from "../../../../guards.js";
import { emitStaffEvent } from "../../../../../events.js";
import { createLogger } from "@open-mercato/shared/lib/logger";
const logger = createLogger("staff");
function extractEntryIdFromUrl(request) {
  if (!request?.url) return null;
  try {
    const url = new URL(request.url);
    const match = url.pathname.match(/\/time-entries\/([^/]+)\/timer-start/);
    return match?.[1] ?? null;
  } catch {
    return null;
  }
}
const metadata = {
  POST: { requireAuth: true, requireFeatures: ["staff.timesheets.manage_own"] }
};
async function POST(req) {
  try {
    const container = await createRequestContainer();
    const auth = await getAuthFromRequest(req);
    const { translate } = await resolveTranslations();
    if (!auth) throw new CrudHttpError(401, { error: translate("staff.errors.unauthorized", "Unauthorized") });
    const scope = await resolveOrganizationScopeForRequest({ container, auth, request: req });
    const tenantId = scope?.tenantId ?? auth.tenantId ?? null;
    const organizationId = scope?.selectedId ?? auth.orgId ?? null;
    if (!tenantId || !organizationId) {
      throw new CrudHttpError(400, { error: translate("staff.errors.missingScope", "Missing tenant or organization scope.") });
    }
    const em = container.resolve("em").fork();
    const scopeCtx = { tenantId, organizationId };
    const entryId = extractEntryIdFromUrl(req);
    if (!entryId) {
      throw new CrudHttpError(400, { error: translate("staff.timesheets.errors.missingEntryId", "Missing entry ID.") });
    }
    const entry = await findOneWithDecryption(
      em,
      StaffTimeEntry,
      { id: entryId, tenantId, organizationId, deletedAt: null },
      {},
      scopeCtx
    );
    if (!entry) {
      throw new CrudHttpError(404, { error: translate("staff.timesheets.errors.entryNotFound", "Time entry not found.") });
    }
    const staffMember = await getStaffMemberByUserId(em, auth.sub, tenantId, organizationId);
    if (!staffMember || entry.staffMemberId !== staffMember.id) {
      throw new CrudHttpError(403, { error: translate("staff.timesheets.errors.notOwner", "You can only manage your own time entries.") });
    }
    if (entry.startedAt) {
      return NextResponse.json(
        { error: translate("staff.timesheets.errors.timerAlreadyStarted", "Timer is already started for this entry.") },
        { status: 409 }
      );
    }
    const guardResult = await runStaffMutationGuards(
      container,
      {
        tenantId,
        organizationId,
        userId: auth.sub ?? "",
        resourceKind: "staff.timesheets.time_entry",
        resourceId: entry.id,
        operation: "update",
        requestMethod: req.method,
        requestHeaders: req.headers
      },
      resolveUserFeatures(auth)
    );
    if (!guardResult.ok) {
      return NextResponse.json(
        guardResult.errorBody ?? { error: "Operation blocked by guard" },
        { status: guardResult.errorStatus ?? 422 }
      );
    }
    const now = await em.transactional(async (trx) => {
      const lockedEntry = await findOneWithDecryption(
        trx,
        StaffTimeEntry,
        { id: entryId, tenantId, organizationId, deletedAt: null },
        { lockMode: LockMode.PESSIMISTIC_WRITE },
        scopeCtx
      );
      if (!lockedEntry) {
        throw new CrudHttpError(404, { error: translate("staff.timesheets.errors.entryNotFound", "Time entry not found.") });
      }
      if (lockedEntry.startedAt) {
        throw new CrudHttpError(409, {
          error: translate("staff.timesheets.errors.timerAlreadyStarted", "Timer is already started for this entry.")
        });
      }
      const otherRunningEntry = await findOneWithDecryption(
        trx,
        StaffTimeEntry,
        {
          tenantId,
          organizationId,
          staffMemberId: lockedEntry.staffMemberId,
          id: { $ne: lockedEntry.id },
          startedAt: { $ne: null },
          endedAt: null,
          deletedAt: null
        },
        {},
        scopeCtx
      );
      if (otherRunningEntry) {
        throw new CrudHttpError(409, {
          error: translate(
            "staff.timesheets.errors.timerAlreadyRunning",
            "Another timer is already running. Stop it before starting a new one."
          )
        });
      }
      const startedAt = /* @__PURE__ */ new Date();
      lockedEntry.startedAt = startedAt;
      lockedEntry.source = "timer";
      const segmentData = {
        tenantId,
        organizationId,
        timeEntryId: lockedEntry.id,
        startedAt,
        segmentType: "work"
      };
      trx.create(StaffTimeEntrySegment, segmentData);
      await trx.flush();
      return startedAt;
    });
    void emitStaffEvent("staff.timesheets.time_entry.timer_started", {
      id: entry.id,
      staffMemberId: entry.staffMemberId,
      tenantId: entry.tenantId,
      organizationId: entry.organizationId,
      startedAt: now.toISOString()
    }, { persistent: true }).catch((err) => {
      logger.error("staff.timesheets emit timer_started failed", { err });
    });
    if (guardResult.afterSuccessCallbacks.length) {
      await runStaffMutationGuardAfterSuccess(guardResult.afterSuccessCallbacks, {
        tenantId,
        organizationId,
        userId: auth.sub ?? "",
        resourceKind: "staff.timesheets.time_entry",
        resourceId: entry.id,
        operation: "update",
        requestMethod: req.method,
        requestHeaders: req.headers
      });
    }
    return NextResponse.json({ ok: true }, { status: 200 });
  } catch (err) {
    if (err instanceof CrudHttpError) {
      return NextResponse.json(err.body, { status: err.status });
    }
    const { translate } = await resolveTranslations();
    logger.error("staff.timesheets.time-entries.timer-start failed", { err });
    return NextResponse.json(
      { error: translate("staff.timesheets.errors.timerStart", "Failed to start timer.") },
      { status: 400 }
    );
  }
}
const openApi = {
  tag: "Staff",
  summary: "Start timer for a time entry",
  methods: {
    POST: {
      summary: "Start timer for a time entry",
      description: "Starts the timer on a time entry by setting startedAt and creating an initial work segment.",
      responses: [
        { status: 200, description: "Timer started", schema: z.object({ ok: z.literal(true) }) },
        { status: 404, description: "Time entry not found", schema: z.object({ error: z.string() }) },
        { status: 409, description: "Timer already started, or another timer is already running for this staff member", schema: z.object({ error: z.string() }) },
        { status: 401, description: "Unauthorized", schema: z.object({ error: z.string() }) }
      ]
    }
  }
};
export {
  POST,
  metadata,
  openApi
};
//# sourceMappingURL=route.js.map
