// src/server/features/reference_books/inventory.routes.ts
// HTTP handlers for inventory routes with approval workflow

import { FastifyPluginAsync } from 'fastify';
import { ZodTypeProvider } from 'fastify-type-provider-zod';
import { z } from 'zod';
import * as inventoryService from './inventory.service';
import {
  inventoryCreateSchema,
  inventoryUpdateSchema,
  inventoryEntryResponseSchema,
  inventoryPendingEntryResponseSchema,
  inventoryParamsSchema,
  inventoryQuerySchema,
} from './inventory.schema';
import type { CreateInventoryRequestWithAdmin, UpdateInventoryRequestWithAdmin } from './inventory.service';
import { requireRole } from '../../shared/lib/auth';
import { AppError } from '../../shared/lib/errors';

// UUID regex for route constraints (8-4-4-4-12 hex characters)
const UUID_REGEX = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}';

const inventoryRoutes: FastifyPluginAsync = async (fastify, opts) => {
  const server = fastify.withTypeProvider<ZodTypeProvider>();

  // Create inventory entry
  server.post('/inventory', {
    preHandler: requireRole('ADMIN', 'MANAGER'),
    schema: {
      body: inventoryCreateSchema,
      response: {
        201: inventoryEntryResponseSchema,
      },
    },
    handler: async (request: any) => {
      // Преобразуем number в string для decimal полей
      const body: CreateInventoryRequestWithAdmin = {
        ...request.body,
        quantity: request.body.quantity ? String(request.body.quantity) : undefined,
        weightPerUnit: request.body.weightPerUnit ? String(request.body.weightPerUnit) : undefined,
        isAdmin: request.user?.role === 'ADMIN',
        createdBy: request.user?.id || undefined,
      };

      const result = await inventoryService.createInventoryEntry(body);
      return result;
    },
  });

  // Get all inventory entries with filters
  server.get('/inventory', {
    preHandler: requireRole('ADMIN', 'MANAGER', 'MAID'),
    schema: {
      query: inventoryQuerySchema,
      response: {
        200: z.array(inventoryEntryResponseSchema),
      },
    },
    handler: async (request: any) => {
      const { category, status, archived } = request.query;

      // Handle category filter (if provided)
      if (category) {
        const allEntries = await inventoryService.getAllInventoryEntries(archived, status);
        return allEntries.filter(entry => entry.category === category);
      }

      return await inventoryService.getAllInventoryEntries(archived, status);
    },
  });

  // Get all pending inventory entries (shortcut)
  server.get('/inventory/pending', {
    preHandler: requireRole('ADMIN', 'MANAGER'),
    schema: {
      response: {
        200: z.array(inventoryPendingEntryResponseSchema),
      },
    },
    handler: async () => {
      return await inventoryService.getInventoryPendingEntries();
    },
  });

  // Get inventory entry by ID
  server.get('/inventory/:id(' + UUID_REGEX + ')', {
    preHandler: requireRole('ADMIN', 'MANAGER', 'MAID'),
    schema: {
      params: inventoryParamsSchema,
      response: {
        200: inventoryEntryResponseSchema,
        404: z.object({
          success: z.literal(false),
          error: z.object({
            message: z.string(),
            code: z.string(),
          }),
        }),
      },
    },
    handler: async (request: any) => {
      const { id } = request.params;

      const entry = await inventoryService.getInventoryEntryById(id);

      if (!entry) {
        throw new AppError('Inventory entry not found', 404, 'NOT_FOUND');
      }

      return entry;
    },
  });

  // Update inventory entry
  server.put('/inventory/:id(' + UUID_REGEX + ')', {
    preHandler: requireRole('ADMIN', 'MANAGER'),
    schema: {
      params: inventoryParamsSchema,
      body: inventoryUpdateSchema,
      response: {
        200: inventoryEntryResponseSchema,
        404: z.object({
          success: z.literal(false),
          error: z.object({
            message: z.string(),
            code: z.string(),
          }),
        }),
      },
    },
    handler: async (request: any) => {
      const { id } = request.params;

      // Преобразуем number в string для decimal полей
      const body: UpdateInventoryRequestWithAdmin = {
        ...request.body,
        quantity: request.body.quantity !== undefined ? String(request.body.quantity) : undefined,
        weightPerUnit: request.body.weightPerUnit !== undefined ? String(request.body.weightPerUnit) : undefined,
        isAdmin: request.user?.role === 'ADMIN',
        updatedBy: request.user?.id || undefined,
      };

      const updated = await inventoryService.updateInventoryEntry(id, body);

      return updated;
    },
  });

  // Archive inventory entry
  server.delete('/inventory/:id(' + UUID_REGEX + ')', {
    preHandler: requireRole('ADMIN', 'MANAGER'),
    schema: {
      params: inventoryParamsSchema,
      response: {
        200: z.object({
          success: z.literal(true),
          message: z.string(),
        }),
        404: z.object({
          success: z.literal(false),
          error: z.object({
            message: z.string(),
            code: z.string(),
          }),
        }),
      },
    },
    handler: async (request: any) => {
      const { id } = request.params;

      // Проверяем, существует ли запись
      const exists = await inventoryService.getInventoryEntryById(id);
      if (!exists) {
        throw new AppError('Inventory entry not found', 404, 'NOT_FOUND');
      }

      await inventoryService.deleteInventoryEntry(id, request.user?.id || 'unknown', request.user?.role === 'ADMIN');

      return {
        success: true as const,
        message: 'Inventory entry archived',
      };
    },
  });

  // Approve inventory entry (Admin only)
  server.post('/inventory/:id(' + UUID_REGEX + ')/approve', {
    preHandler: requireRole('ADMIN'),
    schema: {
      params: inventoryParamsSchema,
      response: {
        200: inventoryEntryResponseSchema,
        404: z.object({
          success: z.literal(false),
          error: z.object({
            message: z.string(),
            code: z.string(),
          }),
        }),
      },
    },
    handler: async (request: any) => {
      const { id } = request.params;

      const approved = await inventoryService.approveInventoryEntry(id, request.user?.id || 'admin');

      return approved;
    },
  });

  // Reject inventory entry (Admin and Manager - Manager can only reject their own)
  server.post('/inventory/:id(' + UUID_REGEX + ')/reject', {
    preHandler: requireRole('ADMIN', 'MANAGER'),
    schema: {
      params: inventoryParamsSchema,
      body: z.object({
        reason: z.string().min(1, 'Причина отклонения обязательна'),
      }),
      response: {
        200: z.object({
          success: z.literal(true),
          message: z.string(),
        }),
        404: z.object({
          success: z.literal(false),
          error: z.object({
            message: z.string(),
            code: z.string(),
          }),
        }),
      },
    },
    handler: async (request: any) => {
      const { id } = request.params;
      const { reason } = request.body;

      await inventoryService.rejectInventoryEntry(id, reason, request.user?.id || 'unknown', request.user?.role === 'ADMIN');

      return {
        success: true as const,
        message: 'Inventory entry rejected',
      };
    },
  });
};

export default inventoryRoutes;
