import { FastifyInstance } from "fastify";
import { z } from "zod";
import { requirePermission } from "../../middleware/auth";
import { logAudit } from "../../services/audit";
import { success, error, parseId, paginated } from "../../utils/response";
import { parsePagination, buildPaginationMeta } from "../../utils/pagination";
import { parseBody } from "../../schemas/common";
import {
  UpdateProjectSchema,
  CreateProjectSchema,
  CreateProjectNoteSchema,
} from "../../schemas/projects.schema";
import {
  listProjects,
  getProject,
  createProject,
  getNextProjectNumber,
  updateProject,
  deleteProject,
  createProjectNote,
  deleteProjectNote,
} from "../../services/projects.service";

// Body for DELETE /:id — optional delete_files flag. The body may be absent on
// a DELETE request, so default to an empty object and coerce truthy flags.
const DeleteProjectSchema = z.object({
  delete_files: z
    .union([z.boolean(), z.string(), z.number()])
    .optional()
    .transform((v) => v === true || v === 1 || v === "1" || v === "true"),
});

export default async function projectsRoutes(
  fastify: FastifyInstance,
): Promise<void> {
  fastify.get(
    "/",
    { preHandler: requirePermission("projects.view") },
    async (request, reply) => {
      const query = request.query as Record<string, unknown>;
      const { page, limit, skip, sort, order, search } = parsePagination(query);

      const parsedCustomerId = query.customer_id
        ? Number(query.customer_id)
        : undefined;
      const customerId =
        parsedCustomerId !== undefined && Number.isFinite(parsedCustomerId)
          ? parsedCustomerId
          : undefined;

      const result = await listProjects({
        page,
        limit,
        skip,
        sort,
        order,
        search,
        status: query.status ? String(query.status) : undefined,
        customer_id: customerId,
      });

      return paginated(
        reply,
        result.data,
        buildPaginationMeta(result.total, page, limit),
      );
    },
  );

  // GET /api/admin/projects/next-number — preview the next shared number
  fastify.get(
    "/next-number",
    { preHandler: requirePermission("projects.create") },
    async (_request, reply) => {
      const number = await getNextProjectNumber();
      return success(reply, { number, next_number: number });
    },
  );

  // POST /api/admin/projects — create a standalone (manual) project
  fastify.post(
    "/",
    { preHandler: requirePermission("projects.create") },
    async (request, reply) => {
      const parsed = parseBody(CreateProjectSchema, request.body);
      if ("error" in parsed) return error(reply, parsed.error, 400);

      const result = await createProject(parsed.data);
      if ("error" in result)
        return error(reply, result.error, (result as any).status ?? 400);

      await logAudit({
        request,
        authData: request.authData,
        action: "create",
        entityType: "project",
        entityId: result.id,
        description: `Vytvořen projekt ${result.project_number}`,
      });
      return success(reply, { id: result.id }, 201, "Projekt byl vytvořen");
    },
  );

  fastify.get<{ Params: { id: string } }>(
    "/:id",
    { preHandler: requirePermission("projects.view") },
    async (request, reply) => {
      const id = parseId(request.params.id, reply);
      if (id === null) return;
      const project = await getProject(id);
      if (!project) return error(reply, "Projekt nenalezen", 404);
      return success(reply, project);
    },
  );

  fastify.put<{ Params: { id: string } }>(
    "/:id",
    { preHandler: requirePermission("projects.edit") },
    async (request, reply) => {
      const id = parseId(request.params.id, reply);
      if (id === null) return;
      const parsed = parseBody(UpdateProjectSchema, request.body);
      if ("error" in parsed) return error(reply, parsed.error, 400);

      const result = await updateProject(id, parsed.data);
      if (!result) return error(reply, "Projekt nenalezen", 404);
      if ("error" in result) {
        return error(reply, result.error, (result as any).status ?? 400);
      }

      await logAudit({
        request,
        authData: request.authData,
        action: "update",
        entityType: "project",
        entityId: id,
        description: `Upraven projekt ${result.name}`,
      });
      return success(reply, { id }, 200, "Projekt byl uložen");
    },
  );

  // POST /api/admin/projects/:id/notes
  fastify.post<{ Params: { id: string } }>(
    "/:id/notes",
    { preHandler: requirePermission("projects.edit") },
    async (request, reply) => {
      const projectId = parseId(request.params.id, reply);
      if (projectId === null) return;
      const parsed = parseBody(CreateProjectNoteSchema, request.body);
      if ("error" in parsed) return error(reply, parsed.error, 400);
      const authData = request.authData!;

      const note = await createProjectNote(projectId, {
        userId: authData.userId,
        firstName: authData.firstName,
        lastName: authData.lastName,
        content: parsed.data.content ?? undefined,
      });
      if (note && "error" in note) {
        return error(reply, note.error, (note as any).status ?? 400);
      }

      await logAudit({
        request,
        authData,
        action: "create",
        entityType: "project",
        entityId: projectId,
        description: `Přidána poznámka projektu`,
      });

      return success(reply, { note }, 201, "Poznámka byla přidána");
    },
  );

  // DELETE /api/admin/projects/:id/notes/:noteId
  fastify.delete<{ Params: { id: string; noteId: string } }>(
    "/:id/notes/:noteId",
    { preHandler: requirePermission("projects.edit") },
    async (request, reply) => {
      const noteId = parseId(request.params.noteId, reply);
      if (noteId === null) return;
      const projectId = parseId(request.params.id, reply);
      if (projectId === null) return;

      const note = await deleteProjectNote(projectId, noteId);
      if (!note) return error(reply, "Poznámka nenalezena", 404);

      await logAudit({
        request,
        authData: request.authData,
        action: "delete",
        entityType: "project",
        entityId: projectId,
        description: `Smazána poznámka projektu`,
      });
      return success(reply, null, 200, "Poznámka smazána");
    },
  );

  fastify.delete<{ Params: { id: string } }>(
    "/:id",
    { preHandler: requirePermission("projects.delete") },
    async (request, reply) => {
      const id = parseId(request.params.id, reply);
      if (id === null) return;

      const parsed = parseBody(DeleteProjectSchema, request.body ?? {});
      if ("error" in parsed) return error(reply, parsed.error, 400);
      const deleteFiles = parsed.data.delete_files;
      const result = await deleteProject(id, deleteFiles);
      if ("error" in result) {
        if (result.error === "not_found")
          return error(reply, "Projekt nenalezen", 404);
        if (result.error === "has_order")
          return error(
            reply,
            "Nelze smazat projekt propojený s objednávkou. Nejdříve smažte objednávku.",
            400,
          );
        return error(reply, "Neznámá chyba", 500);
      }

      await logAudit({
        request,
        authData: request.authData,
        action: "delete",
        entityType: "project",
        entityId: id,
        description: `Smazán projekt ${result.name}`,
      });
      return success(reply, null, 200, "Projekt smazán");
    },
  );
}
