import { FastifyInstance } from 'fastify';
import { prisma } from '../../../config/database';
import { optionalAuth } from '../middleware/auth';
import { createHash } from 'crypto';
import { logger } from '../../../utils/logger';
import { geoipService } from '../../../services/geoip.service';

/**
 * Photo engagement routes — upvotes, comments, reactions, views (prefix: /api)
 */

interface UpvoteParams {
  id: string;
}

interface CommentBody {
  content: string;
  sessionId: string;
}

interface ReactionBody {
  sessionId: string;
  reactionType: string;
}

interface ViewBody {
  photoId: number;
  sessionId?: string;
}

const VALID_REACTIONS = ['like', 'love', 'laugh', 'wow', 'sad', 'angry'];

export async function photoEngagementRoutes(fastify: FastifyInstance) {
  // POST /api/photos/:id/upvote - Toggle upvote on
  fastify.post<{ Params: UpvoteParams; Body: { sessionId: string } }>(
    '/photos/:id/upvote',
    { preHandler: optionalAuth },
    async (request, reply) => {
      const photoId = parseInt(request.params.id as string);
      const { sessionId } = request.body;

      if (!sessionId) {
        return reply.code(400).send({ message: 'sessionId is required' });
      }

      // Ensure session exists
      await prisma.session.upsert({
        where: { id: sessionId },
        create: { id: sessionId, userId: request.user?.id || null },
        update: { lastSeenAt: new Date() },
      });

      // Check existing
      const existing = await prisma.photoUpvote.findFirst({
        where: { photoId, sessionId },
      });

      if (existing) {
        return reply.code(409).send({ message: 'Already upvoted' });
      }

      await prisma.photoUpvote.create({
        data: { photoId, sessionId },
      });

      // Increment counter
      await prisma.photo.update({
        where: { id: photoId },
        data: { upvoteCount: { increment: 1 } },
      });

      return { message: 'Upvoted', upvoted: true };
    }
  );

  // DELETE /api/photos/:id/upvote - Remove upvote
  fastify.delete<{ Params: UpvoteParams; Body: { sessionId: string } }>(
    '/photos/:id/upvote',
    { preHandler: optionalAuth },
    async (request, reply) => {
      const photoId = parseInt(request.params.id as string);
      const sessionId = (request.body as any)?.sessionId || (request.query as any)?.sessionId;

      if (!sessionId) {
        return reply.code(400).send({ message: 'sessionId is required' });
      }

      const existing = await prisma.photoUpvote.findFirst({
        where: { photoId, sessionId },
      });

      if (!existing) {
        return reply.code(404).send({ message: 'No upvote found' });
      }

      await prisma.photoUpvote.delete({ where: { id: existing.id } });

      await prisma.photo.update({
        where: { id: photoId },
        data: { upvoteCount: { decrement: 1 } },
      });

      return { message: 'Upvote removed', upvoted: false };
    }
  );

  // GET /api/photos/:id/comments - Get comments
  fastify.get<{ Params: { id: string }; Querystring: { limit?: string; offset?: string } }>(
    '/photos/:id/comments',
    { preHandler: optionalAuth },
    async (request) => {
      const photoId = parseInt(request.params.id as string);
      const limit = Math.min(parseInt(request.query.limit || '50'), 200);
      const offset = parseInt(request.query.offset || '0');

      const [comments, total] = await Promise.all([
        prisma.photoComment.findMany({
          where: { photoId, isHidden: false, safetyStatus: 'approved' },
          orderBy: { createdAt: 'desc' },
          take: limit,
          skip: offset,
          select: {
            id: true,
            content: true,
            createdAt: true,
            user: {
              select: { id: true, name: true },
            },
          },
        }),
        prisma.photoComment.count({
          where: { photoId, isHidden: false, safetyStatus: 'approved' },
        }),
      ]);

      return { comments, total, limit, offset };
    }
  );

  // POST /api/photos/:id/comments - Add comment
  fastify.post<{ Params: { id: string }; Body: CommentBody }>(
    '/photos/:id/comments',
    { preHandler: optionalAuth },
    async (request, reply) => {
      const photoId = parseInt(request.params.id as string);
      const { content, sessionId } = request.body;

      if (!content?.trim()) {
        return reply.code(400).send({ message: 'Content is required' });
      }
      if (!sessionId) {
        return reply.code(400).send({ message: 'sessionId is required' });
      }

      // Ensure session exists
      await prisma.session.upsert({
        where: { id: sessionId },
        create: { id: sessionId, userId: request.user?.id || null },
        update: { lastSeenAt: new Date() },
      });

      const comment = await prisma.photoComment.create({
        data: {
          photoId,
          sessionId,
          userId: request.user?.id || null,
          content: content.trim().slice(0, 2000), // Max 2000 chars
        },
      });

      // Increment counter
      await prisma.photo.update({
        where: { id: photoId },
        data: { commentCount: { increment: 1 } },
      });

      return reply.code(201).send({ comment });
    }
  );

  // POST /api/photos/:id/reactions - Add reaction
  fastify.post<{ Params: { id: string }; Body: ReactionBody }>(
    '/photos/:id/reactions',
    { preHandler: optionalAuth },
    async (request, reply) => {
      const photoId = parseInt(request.params.id as string);
      const { sessionId, reactionType } = request.body;

      if (!sessionId) {
        return reply.code(400).send({ message: 'sessionId is required' });
      }
      if (!VALID_REACTIONS.includes(reactionType)) {
        return reply.code(400).send({ message: `Invalid reaction. Must be: ${VALID_REACTIONS.join(', ')}` });
      }

      // Ensure session exists
      await prisma.session.upsert({
        where: { id: sessionId },
        create: { id: sessionId, userId: request.user?.id || null },
        update: { lastSeenAt: new Date() },
      });

      // Upsert reaction (one per session per type)
      await prisma.photoReaction.upsert({
        where: {
          photoId_sessionId_reactionType: {
            photoId,
            sessionId,
            reactionType,
          },
        },
        create: { photoId, sessionId, reactionType },
        update: {},
      });

      return { message: 'Reaction added' };
    }
  );

  // POST /api/track/photo-view - Record photo view
  fastify.post<{ Body: ViewBody }>(
    '/track/photo-view',
    { preHandler: optionalAuth },
    async (request, reply) => {
      const { photoId, sessionId } = request.body;

      if (!photoId) {
        return reply.code(400).send({ message: 'photoId is required' });
      }

      // Resolve geo before hashing IP (IP is discarded after this block)
      const ipRaw = request.ip || request.headers['x-forwarded-for'] || '';
      const ipStr = Array.isArray(ipRaw) ? ipRaw[0] : ipRaw;
      const geo = ipStr ? await geoipService.lookup(ipStr) : null;
      const ipHash = createHash('sha256').update(ipStr).digest('hex').slice(0, 16);

      await prisma.photoView.create({
        data: {
          photoId,
          sessionId: sessionId || null,
          userId: request.user?.id || null,
          ipAddressHash: ipHash,
          country: geo?.country ?? null,
          region: geo?.region ?? null,
          city: geo?.city ?? null,
          latitude: geo?.latitude ?? null,
          longitude: geo?.longitude ?? null,
        },
      });

      // Increment counter
      await prisma.photo.update({
        where: { id: photoId },
        data: { viewCount: { increment: 1 } },
      });

      return { message: 'View recorded' };
    }
  );
}
