import { FastifyInstance } from "fastify";
import prisma from "../../config/database";
import { requireAuth, 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 {
  CreateCustomerSchema,
  UpdateCustomerSchema,
} from "../../schemas/customers.schema";
import {
  encodeCustomFields,
  decodeCustomFields as decodeCustomFieldsShared,
} from "../../utils/custom-fields";

const ALLOWED_SORT_FIELDS = ["id", "name", "company_id", "city", "country"];

/** Customer-shaped wrapper over the shared codec (field_order key naming). */
function decodeCustomFields(raw: string | null): {
  custom_fields: unknown[];
  customer_field_order: string[];
} {
  const { custom_fields, field_order } = decodeCustomFieldsShared(raw);
  return { custom_fields, customer_field_order: field_order };
}

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

      const where = search
        ? {
            OR: [
              { name: { contains: search } },
              { company_id: { contains: search } },
            ],
          }
        : {};

      const [customers, total] = await Promise.all([
        prisma.customers.findMany({
          where,
          skip,
          take: limit,
          orderBy: { [sortField]: order },
          include: { _count: { select: { quotations: true } } },
        }),
        prisma.customers.count({ where }),
      ]);

      const enriched = customers.map((c) => {
        const { custom_fields, customer_field_order } = decodeCustomFields(
          c.custom_fields,
        );
        return {
          ...c,
          custom_fields,
          customer_field_order,
          quotation_count: c._count?.quotations ?? 0,
        };
      });

      return paginated(
        reply,
        enriched,
        buildPaginationMeta(total, page, limit),
      );
    },
  );

  fastify.get<{ Params: { id: string } }>(
    "/:id",
    { preHandler: requirePermission("customers.view") },
    async (request, reply) => {
      const id = parseId(request.params.id, reply);
      if (id === null) return;
      const customer = await prisma.customers.findUnique({ where: { id } });
      if (!customer) return error(reply, "Zákazník nenalezen", 404);
      const { custom_fields, customer_field_order } = decodeCustomFields(
        customer.custom_fields,
      );
      return success(reply, {
        ...customer,
        custom_fields,
        customer_field_order,
      });
    },
  );

  fastify.post(
    "/",
    { preHandler: requirePermission("customers.create") },
    async (request, reply) => {
      const parsed = parseBody(CreateCustomerSchema, request.body);
      if ("error" in parsed) return error(reply, parsed.error, 400);
      const body = parsed.data;

      const name = body.name;

      const customer = await prisma.customers.create({
        data: {
          name,
          street: body.street ? String(body.street) : null,
          city: body.city ? String(body.city) : null,
          postal_code: body.postal_code ? String(body.postal_code) : null,
          country: body.country ? String(body.country) : null,
          company_id: body.company_id ? String(body.company_id) : null,
          vat_id: body.vat_id ? String(body.vat_id) : null,
          custom_fields: encodeCustomFields(
            body.custom_fields,
            body.customer_field_order,
          ),
        },
      });

      await logAudit({
        request,
        authData: request.authData,
        action: "create",
        entityType: "customer",
        entityId: customer.id,
        description: `Vytvořen zákazník ${customer.name}`,
      });
      return success(reply, { id: customer.id }, 201, "Zákazník byl vytvořen");
    },
  );

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

      const existing = await prisma.customers.findUnique({ where: { id } });
      if (!existing) return error(reply, "Zákazník nenalezen", 404);

      await prisma.customers.update({
        where: { id },
        data: {
          name: body.name !== undefined ? String(body.name) : undefined,
          street:
            body.street !== undefined
              ? body.street
                ? String(body.street)
                : null
              : undefined,
          city:
            body.city !== undefined
              ? body.city
                ? String(body.city)
                : null
              : undefined,
          postal_code:
            body.postal_code !== undefined
              ? body.postal_code
                ? String(body.postal_code)
                : null
              : undefined,
          country:
            body.country !== undefined
              ? body.country
                ? String(body.country)
                : null
              : undefined,
          company_id:
            body.company_id !== undefined
              ? body.company_id
                ? String(body.company_id)
                : null
              : undefined,
          vat_id:
            body.vat_id !== undefined
              ? body.vat_id
                ? String(body.vat_id)
                : null
              : undefined,
          custom_fields:
            body.custom_fields !== undefined
              ? encodeCustomFields(
                  body.custom_fields,
                  body.customer_field_order,
                )
              : undefined,
        },
      });

      await logAudit({
        request,
        authData: request.authData,
        action: "update",
        entityType: "customer",
        entityId: id,
        description: `Upraven zákazník ${existing.name}`,
      });
      return success(reply, { id }, 200, "Zákazník byl uložen");
    },
  );

  fastify.delete<{ Params: { id: string } }>(
    "/:id",
    { preHandler: requirePermission("customers.delete") },
    async (request, reply) => {
      const id = parseId(request.params.id, reply);
      if (id === null) return;
      const existing = await prisma.customers.findUnique({ where: { id } });
      if (!existing) return error(reply, "Zákazník nenalezen", 404);

      // Check for FK references before deleting
      const [quotCount, orderCount, invoiceCount, projectCount] =
        await Promise.all([
          prisma.quotations.count({ where: { customer_id: id } }),
          prisma.orders.count({ where: { customer_id: id } }),
          prisma.invoices.count({ where: { customer_id: id } }),
          prisma.projects.count({ where: { customer_id: id } }),
        ]);
      if (quotCount + orderCount + invoiceCount + projectCount > 0) {
        return error(
          reply,
          "Zákazníka nelze smazat — existují propojené nabídky, objednávky, faktury nebo projekty",
          400,
        );
      }

      await prisma.customers.delete({ where: { id } });
      await logAudit({
        request,
        authData: request.authData,
        action: "delete",
        entityType: "customer",
        entityId: id,
        description: `Smazán zákazník ${existing.name}`,
      });
      return success(reply, null, 200, "Zákazník smazán");
    },
  );
}
