// src/server/features/reference_books/contractors.routes.ts
// HTTP handlers for contractors routes with RBAC and approval workflow

import { FastifyPluginAsync } from 'fastify';
import { ZodTypeProvider } from 'fastify-type-provider-zod';
import { z } from 'zod';
import { requireRole, isAdmin } from '../../shared/lib/auth';
import { AppError } from '../../shared/lib/errors';
import { contractorCreateSchema, contractorUpdateSchema, contractorEntrySchema, contractorPendingEntrySchema } from './contractors.schema';
import * as contractorsService from './contractors.service';
import { approveContractorEntry, rejectContractorEntry, getContractorPendingEntryById } from './lib/contractors.workflow';

/**
 * Register contractors routes
 */
const contractorsRoutes: FastifyPluginAsync = async (fastify, opts) => {
  const server = fastify.withTypeProvider<ZodTypeProvider>();

  // POST /contractors - Create new contractor entry
  server.post('/contractors', {
    preHandler: [requireRole('ADMIN', 'MANAGER')],
    schema: {
      body: contractorCreateSchema,
      response: {
        201: contractorEntrySchema,
      },
    },
  }, async (request: any) => {
    const data = request.body;
    const userId = request.user?.id || 'unknown';
    const isAdminFlag = isAdmin(request.user);

    const entry = await contractorsService.createContractorEntry({
      ...data,
      createdBy: userId,
      isAdmin: isAdminFlag,
    });
    return entry;
  });

  // GET /contractors - Get all contractor entries
  server.get('/contractors', {
    preHandler: [requireRole('ADMIN', 'MANAGER')],
    schema: {
      querystring: z.object({
        archived: z.coerce.boolean().optional(),
        status: z.enum(['all', 'pending', 'approved']).optional().default('all'),
      }),
      response: {
        200: z.array(contractorEntrySchema),
      },
    },
  }, async (request: any) => {
    const { archived, status } = request.query;
    const entries = await contractorsService.getAllContractorsEntries(archived, status);
    return entries;
  });

  // GET /contractors/pending - Get pending contractor entries (for admin approval)
  server.get('/contractors/pending', {
    preHandler: [requireRole('ADMIN', 'MANAGER')],
    schema: {
      response: {
        200: z.array(contractorPendingEntrySchema),
      },
    },
  }, async () => {
    const entries = await contractorsService.getContractorsPendingEntries();
    return entries;
  });

  // POST /contractors/approve/:id - Approve single pending contractor entry (ADMIN only)
  server.post('/contractors/approve/:id', {
    preHandler: [requireRole('ADMIN')],
    schema: {
      params: z.object({
        id: z.string().uuid(),
      }),
      response: {
        200: z.object({
          success: z.boolean(),
        }),
      },
    },
  }, async (request: any) => {
    const { id } = request.params;
    await approveContractorEntry(id);
    return { success: true };
  });

  // POST /contractors/reject/:id - Reject single pending contractor entry (ADMIN and MANAGER)
  server.post('/contractors/reject/:id', {
    preHandler: [requireRole('ADMIN', 'MANAGER')],
    schema: {
      params: z.object({
        id: z.string().uuid(),
      }),
      response: {
        200: z.object({
          success: z.boolean(),
        }),
      },
    },
  }, async (request: any) => {
    const { id } = request.params;
    const userId = request.user?.id || 'unknown';
    const userRole = request.user?.role || 'GUEST';

    // MANAGER can only reject their own requests
    if (userRole === 'MANAGER') {
      const entry = await getContractorPendingEntryById(id);
      if (!entry) {
        throw new AppError('Запись на согласование не найдена', 404, 'NOT_FOUND');
      }
      if (entry.createdBy !== userId) {
        throw new AppError('Вы можете отклонить только свои запросы', 403, 'FORBIDDEN');
      }
    }

    await rejectContractorEntry(id);
    return { success: true };
  });

  // GET /contractors/:id - Get contractor entry by ID (must be AFTER static routes)
  server.get('/contractors/:id', {
    preHandler: [requireRole('ADMIN', 'MANAGER')],
    schema: {
      params: z.object({
        id: z.string().uuid(),
      }),
      response: {
        200: contractorEntrySchema,
      },
    },
  }, async (request: any) => {
    const { id } = request.params;
    const entry = await contractorsService.getContractorEntryById(id);

    if (!entry) {
      throw new AppError('Запись не найдена', 404, 'NOT_FOUND');
    }

    return entry;
  });

  // PUT /contractors/:id - Update contractor entry (must be AFTER static routes)
  server.put('/contractors/:id', {
    preHandler: [requireRole('ADMIN', 'MANAGER')],
    schema: {
      params: z.object({
        id: z.string().uuid(),
      }),
      body: contractorUpdateSchema,
      response: {
        200: contractorEntrySchema,
      },
    },
  }, async (request: any) => {
    const { id } = request.params;
    const data = request.body;
    const userId = request.user?.id || 'unknown';
    const isAdminFlag = isAdmin(request.user);

    const entry = await contractorsService.updateContractorEntry(
      id,
      {
        ...data,
        updatedBy: userId,
        isAdmin: isAdminFlag,
      }
    );
    return entry;
  });

  // DELETE /contractors/:id - Delete contractor entry (soft delete) (must be AFTER static routes)
  server.delete('/contractors/:id', {
    preHandler: [requireRole('ADMIN', 'MANAGER')],
    schema: {
      params: z.object({
        id: z.string().uuid(),
      }),
    },
  }, async (request: any) => {
    const { id } = request.params;
    const userId = request.user?.id || 'unknown';
    const isAdminFlag = isAdmin(request.user);

    await contractorsService.deleteContractorEntry(id, userId, isAdminFlag);
  });
};

export default contractorsRoutes;
