import { FastifyInstance } from "fastify";
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 { contentDisposition } from "../../utils/content-disposition";
import { parseBody } from "../../schemas/common";
import { config } from "../../config/env";
import {
  CreateOrderFromQuotationSchema,
  CreateOrderSchema,
  UpdateOrderSchema,
} from "../../schemas/orders.schema";
import {
  listOrders,
  getOrderTotals,
  getOrder,
  getOrderAttachment,
  createOrderFromQuotation,
  createOrder,
  updateOrder,
  deleteOrder,
  getNextOrderNumber,
} from "../../services/orders.service";

import multipart from "@fastify/multipart";

export default async function ordersRoutes(
  fastify: FastifyInstance,
): Promise<void> {
  await fastify.register(multipart, {
    limits: { fileSize: config.nas.maxUploadSize },
  });

  // GET /api/admin/orders/next-number
  fastify.get(
    "/next-number",
    { preHandler: requirePermission("orders.create") },
    async (_request, reply) => {
      const number = await getNextOrderNumber();
      return success(reply, { number, next_number: number });
    },
  );

  fastify.get(
    "/",
    { preHandler: requirePermission("orders.view") },
    async (request, reply) => {
      const query = request.query as Record<string, unknown>;
      const { page, limit, skip, sort, order, search } = parsePagination(query);

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

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

  // GET /api/admin/orders/stats — per-currency total (incl. VAT) summed over the
  // WHOLE filtered set (not one page). Must be registered BEFORE "/:id" so the
  // literal "stats" path isn't captured as an order id.
  fastify.get(
    "/stats",
    { preHandler: requirePermission("orders.view") },
    async (request, reply) => {
      const query = request.query as Record<string, unknown>;
      const result = await getOrderTotals({
        search: query.search ? String(query.search) : undefined,
        status: query.status ? String(query.status) : undefined,
        customer_id: query.customer_id ? Number(query.customer_id) : undefined,
        month: query.month ? Number(query.month) : undefined,
        year: query.year ? Number(query.year) : undefined,
      });
      return success(reply, { totals: result.totals });
    },
  );

  fastify.get<{ Params: { id: string } }>(
    "/:id",
    { preHandler: requirePermission("orders.view") },
    async (request, reply) => {
      const id = parseId(request.params.id, reply);
      if (id === null) return;
      const order = await getOrder(id);
      if (!order) return error(reply, "Objednávka nenalezena", 404);
      return success(reply, order);
    },
  );

  // GET /api/admin/orders/:id/attachment
  fastify.get<{ Params: { id: string } }>(
    "/:id/attachment",
    { preHandler: requirePermission("orders.view") },
    async (request, reply) => {
      const id = parseId(request.params.id, reply);
      if (id === null) return;
      const attachment = await getOrderAttachment(id);
      if (!attachment) return error(reply, "Příloha nenalezena", 404);

      return reply
        .type("application/pdf")
        .header(
          "Content-Disposition",
          contentDisposition("inline", attachment.filename),
        )
        .send(attachment.data);
    },
  );

  // POST /api/admin/orders — handles both JSON (manual) and multipart (from quotation)
  fastify.post(
    "/",
    { preHandler: requirePermission("orders.create") },
    async (request, reply) => {
      const isMultipart =
        request.headers["content-type"]?.includes("multipart");

      if (isMultipart) {
        const fields: Record<string, string> = {};
        let attachmentBuffer: Buffer | null = null;
        let attachmentName: string | null = null;

        const parts = request.parts();
        for await (const part of parts) {
          if (part.type === "field") {
            fields[part.fieldname] = String(part.value);
          } else if (part.type === "file" && part.fieldname === "attachment") {
            attachmentBuffer = await part.toBuffer();
            attachmentName = part.filename;
          }
        }

        // From-quotation flow (multipart with attachment)
        if (fields.quotationId) {
          // Validate via the same schema as the JSON path — `intIdFromForm`
          // is NaN-safe and rejects ≤0 / non-integer (raw parseInt would
          // silently yield NaN).
          const fromQuotParsed = parseBody(CreateOrderFromQuotationSchema, {
            quotationId: fields.quotationId,
            customerOrderNumber: fields.customerOrderNumber,
          });
          if ("error" in fromQuotParsed)
            return error(reply, fromQuotParsed.error, 400);
          const quotationId = fromQuotParsed.data.quotationId;
          const customerOrderNumber = fromQuotParsed.data.customerOrderNumber;
          const result = await createOrderFromQuotation({
            quotationId,
            customerOrderNumber,
            attachmentBuffer,
            attachmentName,
          });
          if ("error" in result)
            return error(reply, result.error!, result.status!);
          await logAudit({
            request,
            authData: request.authData,
            action: "create",
            entityType: "order",
            entityId: result.data.order_id,
            description: `Vytvořena objednávka ${result.data.order_number} z nabídky #${result.data.quotationId}`,
          });
          return success(
            reply,
            {
              order_id: result.data.order_id,
              id: result.data.id,
              order_number: result.data.order_number,
            },
            201,
            "Objednávka byla vytvořena",
          );
        }

        // Manual order (multipart, with optional PO attachment)
        const rawManual: Record<string, unknown> = { ...fields };
        if (typeof fields.items === "string" && fields.items.length > 0) {
          try {
            rawManual.items = JSON.parse(fields.items);
          } catch {
            return error(reply, "Neplatná data položek", 400);
          }
        }
        const manualParsed = parseBody(CreateOrderSchema, rawManual);
        if ("error" in manualParsed)
          return error(reply, manualParsed.error, 400);

        const result = await createOrder(
          manualParsed.data,
          attachmentBuffer,
          attachmentName,
        );
        if ("error" in result)
          return error(reply, result.error!, result.status!);
        await logAudit({
          request,
          authData: request.authData,
          action: "create",
          entityType: "order",
          entityId: result.id,
          description: `Vytvořena objednávka ${result.order_number}`,
        });
        if (result.project_id) {
          await logAudit({
            request,
            authData: request.authData,
            action: "create",
            entityType: "project",
            entityId: result.project_id,
            description: `Vytvořen projekt k objednávce ${result.order_number}`,
          });
        }
        return success(
          reply,
          { id: result.id },
          201,
          "Objednávka byla vytvořena",
        );
      }

      // === JSON body — either from-quotation (no attachment) or manual order ===
      const rawBody = request.body as Record<string, unknown>;

      // From-quotation flow via JSON (no attachment)
      if (rawBody.quotationId) {
        const fromQuotParsed = parseBody(
          CreateOrderFromQuotationSchema,
          rawBody,
        );
        if ("error" in fromQuotParsed)
          return error(reply, fromQuotParsed.error, 400);
        const quotationId = fromQuotParsed.data.quotationId;
        const customerOrderNumber = fromQuotParsed.data.customerOrderNumber;

        if (!quotationId || isNaN(quotationId)) {
          return error(reply, "Chybí ID nabídky", 400);
        }

        const result = await createOrderFromQuotation({
          quotationId,
          customerOrderNumber,
        });
        if ("error" in result)
          return error(reply, result.error!, result.status!);

        await logAudit({
          request,
          authData: request.authData,
          action: "create",
          entityType: "order",
          entityId: result.data.order_id,
          description: `Vytvořena objednávka ${result.data.order_number} z nabídky #${result.data.quotationId}`,
        });
        return success(
          reply,
          {
            order_id: result.data.order_id,
            id: result.data.id,
            order_number: result.data.order_number,
          },
          201,
          "Objednávka byla vytvořena",
        );
      }

      // Manual order creation
      const manualParsed = parseBody(CreateOrderSchema, rawBody);
      if ("error" in manualParsed) return error(reply, manualParsed.error, 400);
      const body = manualParsed.data;

      const result = await createOrder(body);
      if ("error" in result) return error(reply, result.error!, result.status!);

      await logAudit({
        request,
        authData: request.authData,
        action: "create",
        entityType: "order",
        entityId: result.id,
        description: `Vytvořena objednávka ${result.order_number}`,
      });
      if (result.project_id) {
        await logAudit({
          request,
          authData: request.authData,
          action: "create",
          entityType: "project",
          entityId: result.project_id,
          description: `Vytvořen projekt k objednávce ${result.order_number}`,
        });
      }
      return success(
        reply,
        { id: result.id },
        201,
        "Objednávka byla vytvořena",
      );
    },
  );

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

      const result = await updateOrder(id, parsed.data);
      if ("error" in result) return error(reply, result.error!, result.status!);

      await logAudit({
        request,
        authData: request.authData,
        action: "update",
        entityType: "order",
        entityId: id,
        description: `Upravena objednávka ${result.data.order_number}`,
      });
      return success(reply, { id }, 200, "Objednávka byla uložena");
    },
  );

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

      const body = request.body as Record<string, unknown> | undefined;
      const deleteFiles = !!body?.delete_files;
      const result = await deleteOrder(id, deleteFiles);
      if ("error" in result) return error(reply, result.error!, result.status!);

      await logAudit({
        request,
        authData: request.authData,
        action: "delete",
        entityType: "order",
        entityId: id,
        description: `Smazána objednávka ${result.data.order_number}`,
      });
      return success(reply, null, 200, "Objednávka smazána");
    },
  );
}
