// src/server/features/approval/approval.routes.ts
// HTTP handlers for approval routes

import { FastifyPluginAsync } from 'fastify';
import { ZodTypeProvider } from 'fastify-type-provider-zod';
import { z } from 'zod';
import * as approvalService from './approval.service';

const approvalRoutes: FastifyPluginAsync = async (fastify, opts) => {
  // Create approval request
  fastify.withTypeProvider<ZodTypeProvider>().route({
    method: 'POST',
    url: '/approval',
    schema: {
      body: z.object({
        entityType: z.enum(['shift', 'employee', 'blacklist']),
        targetId: z.string().nullable(),
        requesterId: z.string(),
        payload: z.record(z.string(), z.any()),
      }),
      response: {
        201: z.object({
          id: z.string(),
          entityType: z.enum(['shift', 'employee', 'blacklist']),
          targetId: z.string().nullable(),
          requesterId: z.string(),
          payload: z.record(z.string(), z.any()),
          status: z.enum(['pending', 'approved', 'rejected']),
          createdAt: z.string(),
          updatedAt: z.string(),
          archivedAt: z.string().nullable(),
        }),
      },
    },
    handler: async (request, reply) => {
      const { entityType, targetId, requesterId, payload } = request.body as {
        entityType: 'shift' | 'employee' | 'blacklist';
        targetId: string | null;
        requesterId: string;
        payload: Record<string, any>;
      };
      const requestId = await approvalService.createApprovalRequest({
        entityType,
        targetId,
        requesterId,
        payload,
      });
      return reply.status(201).send({
        id: requestId,
        entityType,
        targetId,
        requesterId,
        payload,
        status: 'pending',
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString(),
        archivedAt: null,
      });
    },
  });

  // Get all approval requests
  fastify.withTypeProvider<ZodTypeProvider>().route({
    method: 'GET',
    url: '/approval',
    schema: {
      response: {
        200: z.array(
          z.object({
            id: z.string(),
            entityType: z.enum(['shift', 'employee', 'blacklist']),
            targetId: z.string().nullable(),
            requesterId: z.string(),
            payload: z.record(z.string(), z.any()),
            status: z.enum(['pending', 'approved', 'rejected']),
            createdAt: z.string(),
            updatedAt: z.string(),
            archivedAt: z.string().nullable(),
          })
        ),
      },
    },
    handler: async (request, reply) => {
      const requests = await approvalService.getApprovalRequests();
      return reply.status(200).send(
        requests.map((r) => ({
          id: r.id,
          entityType: r.entityType as 'shift' | 'employee' | 'blacklist',
          targetId: r.targetId,
          requesterId: r.requesterId,
          payload: r.payload as Record<string, any>,
          status: r.status,
          createdAt: r.createdAt.toISOString(),
          updatedAt: r.updatedAt.toISOString(),
          archivedAt: r.archivedAt?.toISOString() || null,
        }))
      );
    },
  });

  // Get approval requests by status
  fastify.withTypeProvider<ZodTypeProvider>().route({
    method: 'GET',
    url: '/approval/status/:status',
    schema: {
      params: z.object({
        status: z.enum(['pending', 'approved', 'rejected']),
      }),
      response: {
        200: z.array(
          z.object({
            id: z.string(),
            entityType: z.enum(['shift', 'employee', 'blacklist']),
            targetId: z.string().nullable(),
            requesterId: z.string(),
            payload: z.record(z.string(), z.any()),
            status: z.enum(['pending', 'approved', 'rejected']),
            createdAt: z.string(),
            updatedAt: z.string(),
            archivedAt: z.string().nullable(),
          })
        ),
      },
    },
    handler: async (request, reply) => {
      const { status } = request.params as { status: 'pending' | 'approved' | 'rejected' };
      const requests = await approvalService.getApprovalRequestsByStatus(status);
      return reply.status(200).send(
        requests.map((r) => ({
          id: r.id,
          entityType: r.entityType as 'shift' | 'employee' | 'blacklist',
          targetId: r.targetId,
          requesterId: r.requesterId,
          payload: r.payload as Record<string, any>,
          status: r.status,
          createdAt: r.createdAt.toISOString(),
          updatedAt: r.updatedAt.toISOString(),
          archivedAt: r.archivedAt?.toISOString() || null,
        }))
      );
    },
  });

  // Get approval request by ID
  fastify.withTypeProvider<ZodTypeProvider>().route({
    method: 'GET',
    url: '/approval/:id',
    schema: {
      params: z.object({
        id: z.string(),
      }),
      response: {
        200: z.object({
          id: z.string(),
          entityType: z.enum(['shift', 'employee', 'blacklist']),
          targetId: z.string().nullable(),
          requesterId: z.string(),
          payload: z.record(z.string(), z.any()),
          status: z.enum(['pending', 'approved', 'rejected']),
          createdAt: z.string(),
          updatedAt: z.string(),
          archivedAt: z.string().nullable(),
        }),
        404: z.object({
          success: z.literal(false),
          error: z.object({
            message: z.string(),
            code: z.string(),
          }),
        }),
      },
    },
    handler: async (request, reply) => {
      const { id } = request.params as { id: string };
      const requestObj = await approvalService.getApprovalRequestById(id);
      if (!requestObj) {
        return reply.status(404).send({
          success: false,
          error: {
            message: 'Approval request not found',
            code: 'NOT_FOUND',
          },
        });
      }
      return reply.status(200).send({
        id: requestObj.id,
        entityType: requestObj.entityType as 'shift' | 'employee' | 'blacklist',
        targetId: requestObj.targetId,
        requesterId: requestObj.requesterId,
        payload: requestObj.payload as Record<string, any>,
        status: requestObj.status,
        createdAt: requestObj.createdAt.toISOString(),
        updatedAt: requestObj.updatedAt.toISOString(),
        archivedAt: requestObj.archivedAt?.toISOString() || null,
      });
    },
  });

  // Approve approval request
  fastify.withTypeProvider<ZodTypeProvider>().route({
    method: 'POST',
    url: '/approval/:id/approve',
    schema: {
      params: z.object({
        id: z.string(),
      }),
      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, reply) => {
      const { id } = request.params as { id: string };
      await approvalService.approveApprovalRequest(id);
      return reply.status(200).send({
        success: true,
        message: 'Approval request approved',
      });
    },
  });

  // Reject approval request
  fastify.withTypeProvider<ZodTypeProvider>().route({
    method: 'POST',
    url: '/approval/:id/reject',
    schema: {
      params: z.object({
        id: z.string(),
      }),
      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, reply) => {
      const { id } = request.params as { id: string };
      await approvalService.rejectApprovalRequest(id);
      return reply.status(200).send({
        success: true,
        message: 'Approval request rejected',
      });
    },
  });

  // Update approval request
  fastify.withTypeProvider<ZodTypeProvider>().route({
    method: 'PUT',
    url: '/approval/:id',
    schema: {
      params: z.object({
        id: z.string(),
      }),
      body: z.object({
        payload: z.record(z.string(), z.any()),
      }),
      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, reply) => {
      const { id } = request.params as { id: string };
      const { payload } = request.body as { payload: Record<string, any> };
      await approvalService.updateApprovalRequest(id, payload);
      return reply.status(200).send({
        success: true,
        message: 'Approval request updated',
      });
    },
  });

  // Archive approval request
  fastify.withTypeProvider<ZodTypeProvider>().route({
    method: 'DELETE',
    url: '/approval/:id',
    schema: {
      params: z.object({
        id: z.string(),
      }),
      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, reply) => {
      const { id } = request.params as { id: string };
      await approvalService.archiveApprovalRequest(id);
      return reply.status(200).send({
        success: true,
        message: 'Approval request archived',
      });
    },
  });
};

export default approvalRoutes;
