
import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { prisma } from '@/lib/db';
import { uploadFile } from '@/lib/s3';

export async function POST(request: NextRequest) {
  try {
    const session = await getServerSession(authOptions);
    if (!session?.user?.email) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const user = await prisma.user.findUnique({
      where: { email: session.user.email }
    });

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

    const formData = await request.formData();
    const file = formData.get('file') as File;
    const uploadTypeString = formData.get('uploadType') as string;
    const latitude = formData.get('latitude') as string;
    const longitude = formData.get('longitude') as string;
    const accuracy = formData.get('accuracy') as string;
    const altitude = formData.get('altitude') as string;
    const gpsTimestamp = formData.get('gpsTimestamp') as string;
    const leadId = formData.get('leadId') as string;
    const contractId = formData.get('contractId') as string;
    const quoteId = formData.get('quoteId') as string;
    const expectedLatitude = formData.get('expectedLatitude') as string;
    const expectedLongitude = formData.get('expectedLongitude') as string;

    if (!file) {
      return NextResponse.json({ error: 'No file provided' }, { status: 400 });
    }

    if (!uploadTypeString) {
      return NextResponse.json({ error: 'Upload type is required' }, { status: 400 });
    }

    // Validate upload type
    const validUploadTypes = [
      'CUSTOMER_PLAN',
      'CUSTOMER_PHOTO',
      'CONTRACTOR_PROGRESS',
      'CONTRACTOR_COMPLETION',
      'INSPECTION_PHOTO',
      'QUOTE_ATTACHMENT',
      'CONTRACT_ATTACHMENT',
      'OTHER'
    ];

    if (!validUploadTypes.includes(uploadTypeString)) {
      return NextResponse.json({ error: 'Invalid upload type' }, { status: 400 });
    }

    // Validate GPS data for contractor uploads
    if (
      uploadTypeString === 'CONTRACTOR_PROGRESS' ||
      uploadTypeString === 'CONTRACTOR_COMPLETION'
    ) {
      if (!latitude || !longitude) {
        return NextResponse.json(
          { error: 'GPS location is required for contractor uploads' },
          { status: 400 }
        );
      }
    }

    // Upload file to S3
    const buffer = Buffer.from(await file.arrayBuffer());
    const cloudStoragePath = await uploadFile(buffer, file.name);

    // Calculate distance from expected location if provided
    let locationDistance = null;
    let locationVerified = false;

    if (expectedLatitude && expectedLongitude && latitude && longitude) {
      locationDistance = calculateDistance(
        parseFloat(latitude),
        parseFloat(longitude),
        parseFloat(expectedLatitude),
        parseFloat(expectedLongitude)
      );
      // Verify if within 100 meters
      locationVerified = locationDistance <= 100;
    }

    // Save file upload record with GPS data
    const upload = await prisma.fileUpload.create({
      data: {
        fileName: file.name,
        fileSize: file.size,
        fileType: file.type,
        cloudStoragePath,
        uploadType: uploadTypeString as any,
        userId: user.id,
        leadId: leadId || null,
        contractId: contractId || null,
        quoteId: quoteId || null,
        latitude: latitude ? parseFloat(latitude) : null,
        longitude: longitude ? parseFloat(longitude) : null,
        accuracy: accuracy ? parseFloat(accuracy) : null,
        altitude: altitude ? parseFloat(altitude) : null,
        gpsTimestamp: gpsTimestamp ? new Date(gpsTimestamp) : null,
        expectedLatitude: expectedLatitude ? parseFloat(expectedLatitude) : null,
        expectedLongitude: expectedLongitude
          ? parseFloat(expectedLongitude)
          : null,
        locationVerified,
        locationDistance,
        ipAddress: request.headers.get('x-forwarded-for') || 'unknown',
        userAgent: request.headers.get('user-agent') || 'unknown',
        deviceInfo: {
          platform: request.headers.get('sec-ch-ua-platform'),
          mobile: request.headers.get('sec-ch-ua-mobile')
        }
      }
    });

    return NextResponse.json({ upload });
  } catch (error) {
    console.error('Error uploading file:', error);
    return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
  }
}

export async function GET(request: NextRequest) {
  try {
    const session = await getServerSession(authOptions);
    if (!session?.user?.email) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }

    const user = await prisma.user.findUnique({
      where: { email: session.user.email }
    });

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

    const { searchParams } = new URL(request.url);
    const leadId = searchParams.get('leadId');
    const contractId = searchParams.get('contractId');
    const uploadType = searchParams.get('uploadType');

    const where: any = {};

    // Admins can see all uploads, others only their own
    if (user.role !== 'ADMIN') {
      where.userId = user.id;
    }

    if (leadId) where.leadId = leadId;
    if (contractId) where.contractId = contractId;
    if (uploadType) where.uploadType = uploadType;

    const uploads = await prisma.fileUpload.findMany({
      where,
      orderBy: { createdAt: 'desc' },
      include: {
        user: {
          select: {
            id: true,
            name: true,
            email: true,
            role: true
          }
        }
      }
    });

    return NextResponse.json({ uploads });
  } catch (error) {
    console.error('Error fetching uploads:', error);
    return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
  }
}

// Haversine formula to calculate distance between two GPS coordinates
function calculateDistance(
  lat1: number,
  lon1: number,
  lat2: number,
  lon2: number
): number {
  const R = 6371e3; // Earth's radius in meters
  const φ1 = (lat1 * Math.PI) / 180;
  const φ2 = (lat2 * Math.PI) / 180;
  const Δφ = ((lat2 - lat1) * Math.PI) / 180;
  const Δλ = ((lon2 - lon1) * Math.PI) / 180;

  const a =
    Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
    Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

  return R * c; // Distance in meters
}
