import { Request, Response, NextFunction } from 'express';
import { prisma } from '../models';
import { NotificationService } from '../services/notification.service';
import { PitStatus } from '@prisma/client';

export class GPSLockMiddleware {
  static haversineDistance(lat1: number, lon1: number, lat2: number, lon2: number): number {
    const R = 6371;
    const dLat = ((lat2 - lat1) * Math.PI) / 180;
    const dLon = ((lon2 - lon1) * Math.PI) / 180;
    const a =
      Math.sin(dLat / 2) * Math.sin(dLat / 2) +
      Math.cos((lat1 * Math.PI) / 180) *
        Math.cos((lat2 * Math.PI) / 180) *
        Math.sin(dLon / 2) *
        Math.sin(dLon / 2);
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
    return R * c * 1000;
  }

  static async verifyReportLocation(req: Request, res: Response, next: NextFunction) {
    const { pit_id, current_latitude, current_longitude } = req.body as {
      pit_id?: string;
      current_latitude?: number;
      current_longitude?: number;
    };

    if (!pit_id || current_latitude == null || current_longitude == null) {
      res.status(400).json({ success: false, error: 'pit_id, current_latitude, current_longitude required' });
      return;
    }

    const pit = await prisma.pit.findFirst({
      where: { id: pit_id, deleted_at: null },
      include: { license: true },
    });

    if (!pit) {
      res.status(404).json({ success: false, error: 'Pit not found' });
      return;
    }

    if (pit.status !== PitStatus.ACTIVE || !pit.operational_access) {
      res.status(403).json({
        success: false,
        error: 'This pit is not active. License may be expired.',
      });
      return;
    }

    const distance = GPSLockMiddleware.haversineDistance(
      current_latitude,
      current_longitude,
      pit.gps_latitude,
      pit.gps_longitude
    );

    const allowDevMock = process.env.NODE_ENV !== 'production';
    const isFakeGPS =
      req.headers['x-fake-gps-detected'] === 'true' ||
      (allowDevMock && (req.body as { mock_gps?: boolean }).mock_gps === true);

    if (isFakeGPS) {
      if (req.user) {
        await prisma.user.update({
          where: { id: req.user.id },
          data: { is_suspended: true, suspension_reason: 'Fake GPS detected' },
        });
        await NotificationService.sendRedAlert(
          `Fake GPS detected. User ${req.user.id} suspended.`
        );
      }
      res.status(403).json({ success: false, error: 'Fake GPS detected. Account suspended.' });
      return;
    }

    if (distance > 50) {
      res.status(403).json({
        success: false,
        error: 'GEO-LOCK: Upo nje ya mita 50 za mdomo wa Duara. Sogeza karibu na shimo.',
        distance_meters: distance,
        max_allowed_meters: 50,
      });
      return;
    }

    (req.body as Record<string, unknown>).gps_verified_at = new Date();
    (req.body as Record<string, unknown>).gps_distance_meters = distance;
    next();
  }
}

export const pitOperationalGuard = async (req: Request, res: Response, next: NextFunction) => {
  const pitId = (req.params as { id?: string; pitId?: string }).id || (req.params as { pitId?: string }).pitId;
  if (!pitId) {
    next();
    return;
  }
  const pit = await prisma.pit.findFirst({
    where: { id: pitId, deleted_at: null },
    include: { license: true },
  });
  if (!pit) {
    res.status(404).json({ success: false, error: 'Pit not found' });
    return;
  }
  const lic = pit.license;
  if (lic.status === 'EXPIRED' || lic.status === 'SUSPENDED' || !pit.operational_access || pit.status !== 'ACTIVE') {
    res.status(403).json({
      success: false,
      error: 'Operational access denied (kill-switch or pit inactive)',
    });
    return;
  }
  next();
};
