import { NextRequest, NextResponse } from 'next/server';
import { prisma, prismaAuth } from '@/lib/db';
import { auth } from '@/app/api/auth/[...nextauth]/route';

// In-memory cache for report statuses
// Key: `${userId}:${photoId}`, Value: { data, expiresAt }
interface CacheEntry {
  data: {
    reported: boolean;
    status?: string;
    reportedAt?: Date;
  };
  expiresAt: number;
}

const reportStatusCache = new Map<string, CacheEntry>();
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
const MAX_COMMENT_LENGTH = 300;

// Helper function to get cache key
function getCacheKey(userId: number, photoId: number): string {
  return `${userId}:${photoId}`;
}

// Helper function to get cached report status
function getCachedStatus(userId: number, photoId: number): CacheEntry['data'] | null {
  const key = getCacheKey(userId, photoId);
  const entry = reportStatusCache.get(key);
  
  if (!entry) {
    return null;
  }
  
  // Check if cache entry has expired
  if (Date.now() > entry.expiresAt) {
    reportStatusCache.delete(key);
    return null;
  }
  
  return entry.data;
}

// Helper function to set cache
function setCachedStatus(
  userId: number,
  photoId: number,
  data: CacheEntry['data']
): void {
  const key = getCacheKey(userId, photoId);
  reportStatusCache.set(key, {
    data,
    expiresAt: Date.now() + CACHE_TTL,
  });
}

// Helper function to invalidate cache for a specific user/photo combination
function invalidateCache(userId: number, photoId: number): void {
  const key = getCacheKey(userId, photoId);
  reportStatusCache.delete(key);
}

// Helper function to fetch report status from database
async function fetchReportStatusFromDB(
  userId: number,
  photoId: number
): Promise<CacheEntry['data']> {
  const existingReport = await prismaAuth.inappropriatePhotoReport.findUnique({
    where: {
      uq_photo_user_report: {
        photoId,
        userId,
      },
    },
    select: {
      id: true,
      status: true,
      reportedAt: true,
    },
  });

  const result: CacheEntry['data'] = existingReport
    ? {
        reported: true,
        status: existingReport.status,
        reportedAt: existingReport.reportedAt,
      }
    : {
        reported: false,
      };

  // Cache the result
  setCachedStatus(userId, photoId, result);
  
  return result;
}

export async function POST(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    // Check authentication
    const session = await auth();
    if (!session?.user?.id) {
      return NextResponse.json(
        { error: 'Authentication required. Please sign in to report photos.' },
        { status: 401 }
      );
    }

    const { id } = await params;
    const photoId = parseInt(id, 10);
    
    if (isNaN(photoId)) {
      return NextResponse.json(
        { error: 'Invalid photo ID' },
        { status: 400 }
      );
    }

    // Verify photo exists
    const photo = await prisma.photo.findUnique({
      where: { id: photoId },
      select: { id: true, filename: true },
    });

    if (!photo) {
      return NextResponse.json(
        { error: 'Photo not found' },
        { status: 404 }
      );
    }

    const userId = parseInt(session.user.id, 10);
    if (isNaN(userId)) {
      return NextResponse.json(
        { error: 'Invalid user ID' },
        { status: 400 }
      );
    }

    // Verify user exists in auth database before proceeding
    const user = await prismaAuth.user.findUnique({
      where: { id: userId },
      select: { id: true },
    });

    if (!user) {
      console.error(`[REPORT] User ${userId} not found in auth database`);
      return NextResponse.json(
        { error: 'User account not found. Please sign in again.' },
        { status: 404 }
      );
    }

    // Parse optional comment payload
    let reportComment: string | null = null;
    try {
      const body = await request.json();
      if (body && typeof body === 'object' && !Array.isArray(body)) {
        if (body.comment !== undefined && typeof body.comment !== 'string' && body.comment !== null) {
          return NextResponse.json(
            { error: 'Comment must be a string' },
            { status: 400 }
          );
        }
        if (typeof body.comment === 'string') {
          const trimmed = body.comment.trim();
          if (trimmed.length > MAX_COMMENT_LENGTH) {
            return NextResponse.json(
              { error: `Comment must be ${MAX_COMMENT_LENGTH} characters or less` },
              { status: 400 }
            );
          }
          reportComment = trimmed.length > 0 ? trimmed : null;
        }
      }
    } catch (error: any) {
      // If the request body is empty or invalid JSON, treat as no comment
      if (error.type !== 'invalid-json') {
        console.warn('Invalid report payload received', error);
      }
    }

    // Check if user has already reported this photo (get all info in one query)
    const existingReport = await prismaAuth.inappropriatePhotoReport.findUnique({
      where: {
        uq_photo_user_report: {
          photoId,
          userId,
        },
      },
    });

    let report;
    
    if (existingReport) {
      // If report exists and is still pending, return error
      if (existingReport.status === 'pending') {
        return NextResponse.json(
          { error: 'You have already reported this photo' },
          { status: 409 }
        );
      }
      
      // If report was dismissed, cannot re-report
      if (existingReport.status === 'dismissed') {
        return NextResponse.json(
          { error: 'Cannot re-report a dismissed report' },
          { status: 403 }
        );
      }
      
      // If report was reviewed, update it back to pending (re-report)
      // Keep reviewNotes but clear reviewedAt and reviewedBy
      if (existingReport.status === 'reviewed') {
        report = await prismaAuth.inappropriatePhotoReport.update({
          where: {
            id: existingReport.id,
          },
          data: {
            status: 'pending',
            reviewedAt: null,
            reviewedBy: null,
            reportComment,
            // Keep reviewNotes - don't clear them
          },
        });
        // Invalidate cache after update
        invalidateCache(userId, photoId);
      }
    } else {
      // Create new report
      report = await prismaAuth.inappropriatePhotoReport.create({
        data: {
          photoId,
          userId,
          status: 'pending',
          reportComment,
        },
      });
      // Invalidate cache after creation
      invalidateCache(userId, photoId);
    }

    if (!report) {
      return NextResponse.json(
        { error: 'Failed to create report' },
        { status: 500 }
      );
    }

    return NextResponse.json(
      { 
        message: 'Photo reported successfully',
        report: {
          id: report.id,
          photoId: report.photoId,
          status: report.status,
          reportedAt: report.reportedAt,
          reportComment: report.reportComment,
        },
      },
      { status: 201 }
    );
  } catch (error: any) {
    console.error('Error reporting photo:', error);
    
    // Handle unique constraint violation
    if (error.code === 'P2002') {
      return NextResponse.json(
        { error: 'You have already reported this photo' },
        { status: 409 }
      );
    }
    
    // Handle foreign key constraint violation
    if (error.code === 'P2003') {
      console.error('[REPORT] Foreign key constraint violation:', error.meta);
      return NextResponse.json(
        { error: 'User account not found. Please sign in again.' },
        { status: 404 }
      );
    }
    
    return NextResponse.json(
      { error: 'Failed to report photo', details: error.message },
      { status: 500 }
    );
  }
}

export async function GET(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    // Check authentication
    const session = await auth();
    if (!session?.user?.id) {
      return NextResponse.json(
        { error: 'Authentication required' },
        { status: 401 }
      );
    }

    const { id } = await params;
    const photoId = parseInt(id, 10);
    
    if (isNaN(photoId)) {
      return NextResponse.json(
        { error: 'Invalid photo ID' },
        { status: 400 }
      );
    }

    const userId = parseInt(session.user.id, 10);
    if (isNaN(userId)) {
      return NextResponse.json(
        { error: 'Invalid user ID' },
        { status: 400 }
      );
    }

    // Check cache first
    const cachedStatus = getCachedStatus(userId, photoId);
    if (cachedStatus !== null) {
      return NextResponse.json(cachedStatus);
    }

    // Cache miss - fetch from database (this will also cache the result)
    const reportStatus = await fetchReportStatusFromDB(userId, photoId);
    
    return NextResponse.json(reportStatus);
  } catch (error: any) {
    console.error('Error checking report status:', error);
    return NextResponse.json(
      { error: 'Failed to check report status', details: error.message },
      { status: 500 }
    );
  }
}

export async function DELETE(
  request: NextRequest,
  { params }: { params: Promise<{ id: string }> }
) {
  try {
    // Check authentication
    const session = await auth();
    if (!session?.user?.id) {
      return NextResponse.json(
        { error: 'Authentication required. Please sign in to undo reports.' },
        { status: 401 }
      );
    }

    const { id } = await params;
    const photoId = parseInt(id, 10);
    
    if (isNaN(photoId)) {
      return NextResponse.json(
        { error: 'Invalid photo ID' },
        { status: 400 }
      );
    }

    const userId = parseInt(session.user.id, 10);
    if (isNaN(userId)) {
      return NextResponse.json(
        { error: 'Invalid user ID' },
        { status: 400 }
      );
    }

    // Find the report
    const existingReport = await prismaAuth.inappropriatePhotoReport.findUnique({
      where: {
        uq_photo_user_report: {
          photoId,
          userId,
        },
      },
    });

    if (!existingReport) {
      return NextResponse.json(
        { error: 'Report not found' },
        { status: 404 }
      );
    }

    // Only allow undo if status is still pending
    if (existingReport.status !== 'pending') {
      return NextResponse.json(
        { error: 'Cannot undo report that has already been reviewed' },
        { status: 403 }
      );
    }

    // Delete the report
    await prismaAuth.inappropriatePhotoReport.delete({
      where: {
        id: existingReport.id,
      },
    });

    // Invalidate cache after deletion
    invalidateCache(userId, photoId);

    return NextResponse.json(
      { 
        message: 'Report undone successfully',
      },
      { status: 200 }
    );
  } catch (error: any) {
    console.error('Error undoing report:', error);
    
    return NextResponse.json(
      { error: 'Failed to undo report', details: error.message },
      { status: 500 }
    );
  }
}

