// src/server/features/paymaster/paymaster.routes.ts
// HTTP handlers for paymaster (cash register) routes

import { ZodTypeProvider } from 'fastify-type-provider-zod';
import { z } from 'zod';
import type { FastifyInstance, FastifyRequest } from 'fastify';
import {
  getActivePaymasterRows,
  getArchivedPaymasterRows,
  getPaymasterRowsByDate,
  getPaymasterRowById,
  createPaymasterRow,
  updatePaymasterRow,
  deletePaymasterRow,
  archiveAllPaymasterRows,
  calculateTotalsByDate,
  getOperationalDayString,
  getPaymasterSuggestions,
  getDateBoundaries,
  getPeriodReport,
} from './paymaster.service';
import {
  createPaymasterRowSchema,
  updatePaymasterRowSchema,
  paymasterRowResponseSchema,
  paymasterTotalsSchema,
  paymasterListResponseSchema,
  dateBoundariesSchema,
  paymasterPeriodReportSchema,
} from './paymaster.schema';

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

  // Get all active paymaster rows (current operational day)
  server.get('/rows', {
    schema: {
      response: {
        200: z.object({
          success: z.boolean(),
          data: paymasterListResponseSchema,
        }),
      },
    },
  }, async () => {
    const rows = await getActivePaymasterRows();
    return { success: true, data: rows };
  });

  // Get paymaster rows by date
  server.get('/rows/date/:date', {
    schema: {
      params: z.object({
        date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Неверный формат даты. Используйте YYYY-MM-DD'),
      }),
      response: {
        200: z.object({
          success: z.boolean(),
          data: paymasterListResponseSchema,
        }),
      },
    },
  }, async (request: FastifyRequest) => {
    const { date } = request.params as { date: string };
    const rows = await getPaymasterRowsByDate(date);
    return { success: true, data: rows };
  });

  // Get archived paymaster rows (legacy endpoint)
  server.get('/rows/archived', {
    schema: {
      querystring: z.object({
        date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Неверный формат даты. Используйте YYYY-MM-DD').optional(),
      }),
      response: {
        200: z.object({
          success: z.boolean(),
          data: paymasterListResponseSchema,
        }),
      },
    },
  }, async (request: FastifyRequest) => {
    const { date } = request.query as { date?: string };
    // Если дата не указана, возвращаем пустой массив (legacy)
    if (!date) {
      return { success: true, data: [] };
    }
    const rows = await getPaymasterRowsByDate(date);
    return { success: true, data: rows };
  });

  // Get paymaster row by ID
  server.get('/rows/:id', {
    schema: {
      params: z.object({
        id: z.string().uuid(),
      }),
      response: {
        200: z.object({
          success: z.boolean(),
          data: paymasterRowResponseSchema,
        }),
      },
    },
  }, async (request: FastifyRequest) => {
    const { id } = request.params as { id: string };
    const row = await getPaymasterRowById(id);
    if (!row) {
      throw new Error('Paymaster row not found');
    }
    return { success: true, data: row };
  });

  // Create paymaster row
  server.post('/rows', {
    schema: {
      body: createPaymasterRowSchema,
      response: {
        200: z.object({
          success: z.boolean(),
          data: z.object({ id: z.string() }),
        }),
      },
    },
    preHandler: async (request) => {
      // Проверяем права для создания записей на прошлые даты
      const data = request.body as any;
      if (data.operationalDay && data.operationalDay !== getOperationalDayString()) {
        const user = request.user as any;
        if (user.role !== 'ADMIN') {
          throw new Error('Доступ запрещен: только администратор может создавать записи на прошлые даты');
        }
      }
    },
  }, async (request: FastifyRequest) => {
    const data = request.body as any;
    const user = request.user as any;
    const id = await createPaymasterRow(data, user.role);
    return { success: true, data: { id } };
  });

  // Update paymaster row
  server.put('/rows/:id', {
    schema: {
      params: z.object({
        id: z.string().uuid(),
      }),
      body: updatePaymasterRowSchema,
      response: {
        200: z.object({
          success: z.boolean(),
          data: paymasterRowResponseSchema,
        }),
      },
    },
  }, async (request: FastifyRequest) => {
    const { id } = request.params as { id: string };
    const data = request.body as any;
    const user = request.user as any;
    const row = await updatePaymasterRow(id, data, user.role);
    return { success: true, data: row };
  });

  // Delete paymaster row
  server.delete('/rows/:id', {
    schema: {
      params: z.object({
        id: z.string().uuid(),
      }),
      response: {
        200: z.object({
          success: z.boolean(),
        }),
      },
    },
  }, async (request: FastifyRequest) => {
    const { id } = request.params as { id: string };
    const user = request.user as any;
    await deletePaymasterRow(id, user.role);
    return { success: true };
  });

  // Archive all paymaster rows (Cron job)
  server.post('/rows/archive', {
    schema: {
      response: {
        200: z.object({
          success: z.boolean(),
        }),
      },
    },
  }, async () => {
    await archiveAllPaymasterRows();
    return { success: true };
  });

  // Get totals for current operational day
  server.get('/totals', {
    schema: {
      response: {
        200: z.object({
          success: z.boolean(),
          data: paymasterTotalsSchema,
        }),
      },
    },
  }, async () => {
    const totals = await calculateTotalsByDate(getOperationalDayString());
    return { success: true, data: totals };
  });

  // Legacy endpoint - calculate totals (deprecated, use calculateTotalsByDate)
  server.get('/totals/current', {
    schema: {
      response: {
        200: z.object({
          success: z.boolean(),
          data: paymasterTotalsSchema,
        }),
      },
    },
  }, async () => {
    const totals = await calculateTotalsByDate(getOperationalDayString());
    return { success: true, data: totals };
  });

  // Get totals by date
  server.get('/totals/:date', {
    schema: {
      params: z.object({
        date: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Неверный формат даты. Используйте YYYY-MM-DD'),
      }),
      response: {
        200: z.object({
          success: z.boolean(),
          data: paymasterTotalsSchema,
        }),
      },
    },
  }, async (request: FastifyRequest) => {
    const { date } = request.params as { date: string };
    const totals = await calculateTotalsByDate(date);
    return { success: true, data: totals };
  });

  // Get suggestions for autocomplete (all time unique values)
  server.get('/suggestions', {
    schema: {
      response: {
        200: z.object({
          success: z.boolean(),
          data: z.object({
            rooms: z.array(z.string()),
            contractors: z.array(z.string()),
            types: z.array(z.string()),
          }),
        }),
      },
    },
  }, async () => {
    const suggestions = await getPaymasterSuggestions();
    return { success: true, data: suggestions };
  });

  // Get date boundaries for navigation
  server.get('/date-boundaries', {
    schema: {
      response: {
        200: z.object({
          success: z.boolean(),
          data: dateBoundariesSchema,
        }),
      },
    },
  }, async () => {
    const boundaries = await getDateBoundaries();
    return { success: true, data: boundaries };
  });

  // Get period report (aggregated report for operational days range)
  server.get('/period-report', {
    schema: {
      querystring: z.object({
        startDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Неверный формат даты. Используйте YYYY-MM-DD'),
        endDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'Неверный формат даты. Используйте YYYY-MM-DD'),
      }),
      response: {
        200: z.object({
          success: z.boolean(),
          data: paymasterPeriodReportSchema,
        }),
      },
    },
  }, async (request: FastifyRequest) => {
    const { startDate, endDate } = request.query as { startDate: string; endDate: string };
    const report = await getPeriodReport(startDate, endDate);
    return { success: true, data: report };
  });
};
