import { Router, Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { reactionRepo } from '../services/db/index.db';
import { validateRequest } from '../middleware/validation.middleware';
import passport from '../config/passport';
import { requiredString } from '../utils/zodUtils';
import { UserProfile } from '../types';
import { publicReadLimiter, reactionToggleLimiter } from '../config/rateLimiters';
import { sendSuccess } from '../utils/apiResponse';

const router = Router();

// --- Zod Schemas for Reaction Routes ---

const getReactionsSchema = z.object({
  query: z.object({
    userId: z.string().uuid().optional(),
    entityType: z.string().optional(),
    entityId: z.string().optional(),
  }),
});

const toggleReactionSchema = z.object({
  body: z.object({
    entity_type: requiredString('entity_type is required.'),
    entity_id: requiredString('entity_id is required.'),
    reaction_type: requiredString('reaction_type is required.'),
  }),
});

const getReactionSummarySchema = z.object({
  query: z.object({
    entityType: requiredString('entityType is required.'),
    entityId: requiredString('entityId is required.'),
  }),
});

// --- Routes ---

/**
 * @openapi
 * /reactions:
 *   get:
 *     tags: [Reactions]
 *     summary: Get reactions
 *     description: Fetches user reactions based on query filters. Supports filtering by userId, entityType, and entityId.
 *     parameters:
 *       - in: query
 *         name: userId
 *         schema:
 *           type: string
 *           format: uuid
 *         description: Filter by user ID
 *       - in: query
 *         name: entityType
 *         schema:
 *           type: string
 *         description: Filter by entity type (e.g., recipe, comment)
 *       - in: query
 *         name: entityId
 *         schema:
 *           type: string
 *         description: Filter by entity ID
 *     responses:
 *       200:
 *         description: List of reactions matching filters
 *         content:
 *           application/json:
 *             schema:
 *               $ref: '#/components/schemas/SuccessResponse'
 */
router.get(
  '/',
  publicReadLimiter,
  validateRequest(getReactionsSchema),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const { query } = getReactionsSchema.parse({ query: req.query });
      const reactions = await reactionRepo.getReactions(query, req.log);
      sendSuccess(res, reactions);
    } catch (error) {
      req.log.error({ error }, 'Error fetching user reactions');
      next(error);
    }
  },
);

/**
 * @openapi
 * /reactions/summary:
 *   get:
 *     tags: [Reactions]
 *     summary: Get reaction summary
 *     description: Fetches a summary of reactions for a specific entity.
 *     parameters:
 *       - in: query
 *         name: entityType
 *         required: true
 *         schema:
 *           type: string
 *         description: Entity type (e.g., recipe, comment)
 *       - in: query
 *         name: entityId
 *         required: true
 *         schema:
 *           type: string
 *         description: Entity ID
 *     responses:
 *       200:
 *         description: Reaction summary with counts by type
 *         content:
 *           application/json:
 *             schema:
 *               $ref: '#/components/schemas/SuccessResponse'
 *       400:
 *         description: Missing required query parameters
 */
router.get(
  '/summary',
  publicReadLimiter,
  validateRequest(getReactionSummarySchema),
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const { query } = getReactionSummarySchema.parse({ query: req.query });
      const summary = await reactionRepo.getReactionSummary(
        query.entityType,
        query.entityId,
        req.log,
      );
      sendSuccess(res, summary);
    } catch (error) {
      req.log.error({ error }, 'Error fetching reaction summary');
      next(error);
    }
  },
);

/**
 * @openapi
 * /reactions/toggle:
 *   post:
 *     tags: [Reactions]
 *     summary: Toggle reaction
 *     description: Toggles a user's reaction to an entity. If the reaction exists, it's removed; otherwise, it's added.
 *     security:
 *       - bearerAuth: []
 *     requestBody:
 *       required: true
 *       content:
 *         application/json:
 *           schema:
 *             type: object
 *             required:
 *               - entity_type
 *               - entity_id
 *               - reaction_type
 *             properties:
 *               entity_type:
 *                 type: string
 *                 description: Entity type (e.g., recipe, comment)
 *               entity_id:
 *                 type: string
 *                 description: Entity ID
 *               reaction_type:
 *                 type: string
 *                 description: Type of reaction (e.g., like, love)
 *     responses:
 *       200:
 *         description: Reaction removed
 *       201:
 *         description: Reaction added
 *       401:
 *         description: Unauthorized - invalid or missing token
 */
router.post(
  '/toggle',
  reactionToggleLimiter,
  passport.authenticate('jwt', { session: false }),
  validateRequest(toggleReactionSchema),
  async (req: Request, res: Response, next: NextFunction) => {
    const userProfile = req.user as UserProfile;
    type ToggleReactionRequest = z.infer<typeof toggleReactionSchema>;
    const { body } = req as unknown as ToggleReactionRequest;

    try {
      const reactionData = {
        user_id: userProfile.user.user_id,
        ...body,
      };
      const result = await reactionRepo.toggleReaction(reactionData, req.log);
      if (result) {
        sendSuccess(res, { message: 'Reaction added.', reaction: result }, 201);
      } else {
        sendSuccess(res, { message: 'Reaction removed.' });
      }
    } catch (error) {
      req.log.error({ error, body }, 'Error toggling user reaction');
      next(error);
    }
  },
);

export default router;
