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

import { ZodTypeProvider } from 'fastify-type-provider-zod';
import { FastifyInstance } from 'fastify';
import { z } from 'zod';
import * as scheduleService from './schedule.service';
import {
  getShiftsGridSchema,
  bulkUpdateShiftsSchema,
  approveShiftsSchema,
  rejectShiftsSchema,
  shiftsGridResponseSchema,
  successResponseSchema,
  errorResponseSchema,
  pendingCountResponseSchema,
} from './schedule.schema';
import { logger } from '../../shared/lib/logger';
import { requireRole, UserInfo } from '../../shared/lib/auth';
import { USER_ROLES } from '@shared/constants/roles';

export const scheduleRoutes = async (fastify: FastifyInstance) => {
  const server = fastify.withTypeProvider<ZodTypeProvider>();

  // Get shifts grid for a month
  server.get('/shifts/grid', {
    schema: {
      querystring: getShiftsGridSchema,
      response: {
        200: shiftsGridResponseSchema,
      },
    },
  }, async (request: any) => {
    const { month, year } = request.query;
    logger.info(`[Schedule] GET /shifts/grid - month: ${month}, year: ${year}`);
    const data = await scheduleService.getShiftsGrid(month, year);
    logger.info(`[Schedule] GET /shifts/grid - returning ${data.shifts.length} shifts, ${data.managers.length} managers, ${data.maids.length} maids`);
    return {
      success: true,
      data,
    };
  });

  // Update shifts (bulk)
  server.post('/shifts/update', {
    schema: {
      body: bulkUpdateShiftsSchema,
      response: {
        200: z.union([successResponseSchema, errorResponseSchema]),
        400: errorResponseSchema,
      },
    },
    preHandler: requireRole('ADMIN', 'MANAGER'),
  }, async (request: any, reply) => {
    try {
      const { shifts: shiftsUpdates } = request.body;
      const user = request.user as UserInfo;
      const userId = user?.id || 'system';
      const isAdmin = user?.role === USER_ROLES.ADMIN;

      await scheduleService.bulkUpdateShifts(
        shiftsUpdates.map((s: any) => ({
          ...s,
          date: new Date(s.date),
        })),
        userId,
        isAdmin
      );

      return {
        success: true,
        message: 'Shifts updated successfully',
      };
    } catch (error: any) {
      logger.error('[Schedule Routes] Error updating shifts:', error);
      return reply.code(400).send({
        success: false,
        error: {
          message: error.message || 'Failed to update shifts',
          code: 'SHIFT_UPDATE_ERROR',
        },
      });
    }
  });

  // Approve shifts for a month (Admin only)
  server.post('/shifts/approve', {
    schema: {
      body: approveShiftsSchema,
      response: {
        200: z.union([successResponseSchema, errorResponseSchema]),
        400: errorResponseSchema,
      },
    },
    preHandler: requireRole('ADMIN'),
  }, async (request: any, reply) => {
    try {
      const { month, year } = request.body;

      await scheduleService.approveShiftsForMonth(month, year);

      return {
        success: true,
        message: 'Shifts approved successfully',
      };
    } catch (error: any) {
      logger.error('[Schedule Routes] Error approving shifts:', error);
      return reply.code(400).send({
        success: false,
        error: {
          message: error.message || 'Failed to approve shifts',
          code: 'SHIFT_APPROVE_ERROR',
        },
      });
    }
  });

  // Get pending approval shifts for a month
  server.get('/shifts/pending', {
    schema: {
      querystring: getShiftsGridSchema,
      response: {
        200: z.object({
          success: z.boolean(),
          data: z.array(z.object({
            id: z.string(),
            date: z.string(),
            userId: z.string(),
            roleAtShift: z.enum(['Manager', 'Maid']),
            status: z.enum(['Blank', 'Work', 'Holiday', 'Unavailable']),
            isApproved: z.boolean(),
            createdBy: z.string(),
            createdAt: z.string(),
            updatedAt: z.string(),
          })),
        }),
      },
    },
  }, async (request: any) => {
    const { month, year } = request.query;
    const shifts = await scheduleService.getPendingApprovalShifts(month, year);
    return {
      success: true,
      data: shifts,
    };
  });

  // Reject shifts for a month (Admin only)
  server.post('/shifts/reject', {
    schema: {
      body: rejectShiftsSchema,
      response: {
        200: z.union([successResponseSchema, errorResponseSchema]),
        400: errorResponseSchema,
      },
    },
    preHandler: requireRole('ADMIN'),
  }, async (request: any, reply) => {
    try {
      const { month, year } = request.body;

      const count = await scheduleService.rejectShiftsForMonth(month, year);

      return {
        success: true,
        message: `Shifts rejected successfully (${count} shifts deleted)`,
      };
    } catch (error: any) {
      logger.error('[Schedule Routes] Error rejecting shifts:', error);
      return reply.code(400).send({
        success: false,
        error: {
          message: error.message || 'Failed to reject shifts',
          code: 'SHIFT_REJECT_ERROR',
        },
      });
    }
  });

  // Get total pending shifts count (for Red Dot indicator)
  server.get('/shifts/pending-count', {
    schema: {
      response: {
        200: pendingCountResponseSchema,
      },
    },
  }, async () => {
    const count = await scheduleService.getPendingCount();
    return {
      success: true,
      data: { count },
    };
  });

  // Export shifts to CSV
  server.get('/export', {
    schema: {
      querystring: getShiftsGridSchema,
    },
  }, async (request: any, reply) => {
    const { month, year } = request.query;
    logger.info(`[Schedule] GET /export - month: ${month}, year: ${year}`);
    
    const { csv, filename } = await scheduleService.exportShiftsToCSV(month, year);
    
    reply
      .type('text/csv; charset=utf-8')
      .header('Content-Disposition', `attachment; filename="${filename}"`)
      .send(csv);
  });
};
