import { FastifyInstance } from "fastify";
import prisma from "../../config/database";
import { requirePermission } from "../../middleware/auth";
import { logAudit } from "../../services/audit";
import { success, error, parseId } from "../../utils/response";
import { parseBody } from "../../schemas/common";
import {
  CreateScopeTemplateSchema,
  CreateItemTemplateSchema,
  UpdateScopeTemplateSchema,
} from "../../schemas/scope-templates.schema";

interface ScopeSectionInput {
  title?: string;
  title_cz?: string;
  content?: string;
  position?: number;
}

export default async function scopeTemplatesRoutes(
  fastify: FastifyInstance,
): Promise<void> {
  // Legacy ?action= dispatcher for item templates
  fastify.get(
    "/",
    { preHandler: requirePermission("settings.templates") },
    async (request, reply) => {
      const query = request.query as Record<string, unknown>;
      const action = query.action ? String(query.action) : null;

      if (action === "items") {
        const items = await prisma.item_templates.findMany({
          where: { is_deleted: false },
          orderBy: { name: "asc" },
        });
        return success(reply, items);
      }

      // Default: scope templates
      const templates = await prisma.scope_templates.findMany({
        where: { is_deleted: false },
        include: {
          scope_template_sections: {
            where: { is_deleted: false },
            orderBy: { position: "asc" },
          },
        },
        orderBy: { name: "asc" },
      });
      return success(reply, templates);
    },
  );

  // Item template CRUD via ?action=item
  fastify.post(
    "/",
    { preHandler: requirePermission("settings.templates") },
    async (request, reply) => {
      const query = request.query as Record<string, unknown>;

      if (String(query.action) === "item") {
        const itemParsed = parseBody(CreateItemTemplateSchema, request.body);
        if ("error" in itemParsed) return error(reply, itemParsed.error, 400);
        const body = itemParsed.data;
        const itemData = {
          name: body.name ? String(body.name) : null,
          description: body.description ? String(body.description) : null,
          default_price:
            body.default_price != null ? Number(body.default_price) : 0,
          category: body.category ? String(body.category) : null,
        };

        if (body.id) {
          const itemId = Number(body.id);
          const existingItem = await prisma.item_templates.findFirst({
            where: { id: itemId, is_deleted: false },
          });
          if (!existingItem) return error(reply, "Šablona nenalezena", 404);
          await prisma.item_templates.updateMany({
            where: { id: itemId, is_deleted: false },
            data: { ...itemData, modified_at: new Date() },
          });
          await logAudit({
            request,
            authData: request.authData,
            action: "update",
            entityId: itemId,
            description: `Upravena šablona položky '${itemData.name ?? itemId}'`,
            oldValues: {
              name: existingItem.name,
              description: existingItem.description,
              default_price: existingItem.default_price,
              category: existingItem.category,
            },
            newValues: itemData,
          });
          return success(reply, { id: itemId }, 200, "Položka byla uložena");
        }

        const item = await prisma.item_templates.create({ data: itemData });
        await logAudit({
          request,
          authData: request.authData,
          action: "create",
          entityId: item.id,
          description: `Vytvořena šablona položky '${itemData.name ?? item.id}'`,
          newValues: itemData,
        });
        return success(reply, { id: item.id }, 201, "Položka byla vytvořena");
      }

      const scopeParsed = parseBody(CreateScopeTemplateSchema, request.body);
      if ("error" in scopeParsed) return error(reply, scopeParsed.error, 400);
      const body = scopeParsed.data;

      // Wrap create + sections in a single transaction so a failed
      // createMany can't leave a template row behind with no sections.
      const template = await prisma.$transaction(async (tx) => {
        const created = await tx.scope_templates.create({
          data: {
            name: body.name ? String(body.name) : null,
            title: body.title ? String(body.title) : null,
            description: body.description ? String(body.description) : null,
          },
        });

        if (Array.isArray(body.sections)) {
          await tx.scope_template_sections.createMany({
            data: (body.sections as ScopeSectionInput[]).map((s, i) => ({
              scope_template_id: created.id,
              title: s.title ?? null,
              title_cz: s.title_cz ?? null,
              content: s.content ?? null,
              position: s.position ?? i,
            })),
          });
        }

        return created;
      });

      await logAudit({
        request,
        authData: request.authData,
        action: "create",
        entityId: template.id,
        description: `Vytvořena šablona rozsahu '${template.name ?? template.id}'`,
        newValues: {
          name: template.name,
          title: template.title,
          description: template.description,
          sections: Array.isArray(body.sections) ? body.sections.length : 0,
        },
      });

      return success(reply, { id: template.id }, 201, "Šablona byla vytvořena");
    },
  );

  // Item template delete via DELETE ?action=item&id=X
  fastify.delete(
    "/",
    { preHandler: requirePermission("settings.templates") },
    async (request, reply) => {
      const query = request.query as Record<string, unknown>;

      if (String(query.action) === "item" && query.id) {
        const id = Number(query.id);
        if (!Number.isInteger(id) || id <= 0)
          return error(reply, "Neplatné ID", 400);
        const existingItem = await prisma.item_templates.findFirst({
          where: { id, is_deleted: false },
        });
        if (!existingItem) return error(reply, "Šablona nenalezena", 404);
        await prisma.item_templates.update({
          where: { id },
          data: { is_deleted: true, modified_at: new Date() },
        });
        await logAudit({
          request,
          authData: request.authData,
          action: "delete",
          entityId: id,
          description: `Smazána šablona položky '${existingItem.name ?? id}'`,
        });
        return success(reply, null, 200, "Šablona smazána");
      }

      return error(reply, "Neplatná akce", 400);
    },
  );

  fastify.get<{ Params: { id: string } }>(
    "/:id",
    { preHandler: requirePermission("settings.templates") },
    async (request, reply) => {
      const id = parseId(request.params.id, reply);
      if (id === null) return;
      const template = await prisma.scope_templates.findUnique({
        where: { id },
        include: {
          scope_template_sections: {
            where: { is_deleted: false },
            orderBy: { position: "asc" },
          },
        },
      });
      if (!template || template.is_deleted)
        return error(reply, "Šablona nenalezena", 404);
      return success(reply, template);
    },
  );

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

      const existing = await prisma.scope_templates.findUnique({
        where: { id },
      });
      if (!existing) return error(reply, "Šablona nenalezena", 404);

      await prisma.scope_templates.update({
        where: { id },
        data: {
          name: body.name !== undefined ? String(body.name) : undefined,
          title: body.title !== undefined ? String(body.title) : undefined,
          description:
            body.description !== undefined
              ? String(body.description)
              : undefined,
          modified_at: new Date(),
        },
      });

      if (Array.isArray(body.sections)) {
        await prisma.$transaction(async (tx) => {
          await tx.scope_template_sections.deleteMany({
            where: { scope_template_id: id },
          });
          await tx.scope_template_sections.createMany({
            data: (body.sections as ScopeSectionInput[]).map((s, i) => ({
              scope_template_id: id,
              title: s.title ?? null,
              title_cz: s.title_cz ?? null,
              content: s.content ?? null,
              position: s.position ?? i,
            })),
          });
        });
      }

      await logAudit({
        request,
        authData: request.authData,
        action: "update",
        entityId: id,
        description: `Upravena šablona rozsahu '${existing.name ?? id}'`,
        oldValues: {
          name: existing.name,
          title: existing.title,
          description: existing.description,
        },
        newValues: {
          name: body.name,
          title: body.title,
          description: body.description,
          sections: Array.isArray(body.sections)
            ? body.sections.length
            : undefined,
        },
      });

      return success(reply, { id }, 200, "Šablona byla uložena");
    },
  );

  fastify.delete<{ Params: { id: string } }>(
    "/:id",
    { preHandler: requirePermission("settings.templates") },
    async (request, reply) => {
      const id = parseId(request.params.id, reply);
      if (id === null) return;
      const existing = await prisma.scope_templates.findFirst({
        where: { id, is_deleted: false },
      });
      if (!existing) return error(reply, "Šablona nenalezena", 404);
      await prisma.scope_templates.update({
        where: { id },
        data: { is_deleted: true, modified_at: new Date() },
      });
      await logAudit({
        request,
        authData: request.authData,
        action: "delete",
        entityId: id,
        description: `Smazána šablona rozsahu '${existing.name ?? id}'`,
      });
      return success(reply, null, 200, "Šablona smazána");
    },
  );
}
