import { Request, Response } from 'express';
import { prisma } from '../models';
import { gradeBand, isWaste } from '../lib/module-b';

export const excavatorController = {
  async create(req: Request, res: Response) {
    const b = req.body as {
      excavator_name?: string;
      excavator_id?: string;
      license_id?: string;
      gps_device_id?: string;
      current_pit_id?: string;
    };
    if (!b.excavator_name || !b.excavator_id || !b.license_id || !b.gps_device_id) {
      res.status(400).json({ success: false, error: 'excavator_name, excavator_id, license_id, gps_device_id required' });
      return;
    }
    const lic = await prisma.license.findFirst({ where: { id: b.license_id, deleted_at: null } });
    if (!lic) {
      res.status(404).json({ success: false, error: 'License not found' });
      return;
    }
    try {
      const ex = await prisma.excavator.create({
        data: {
          excavator_name: b.excavator_name,
          excavator_id: b.excavator_id,
          license_id: b.license_id,
          gps_device_id: b.gps_device_id,
          current_pit_id: b.current_pit_id,
        },
      });
      res.json({ success: true, data: ex });
    } catch {
      res.status(400).json({ success: false, error: 'Could not create (duplicate excavator_id?)' });
    }
  },

  async list(req: Request, res: Response) {
    const license_id = req.query.license_id as string | undefined;
    const where = license_id ? { license_id } : {};
    const excavators = await prisma.excavator.findMany({
      where,
      orderBy: { excavator_name: 'asc' },
      include: { pit: true },
    });
    res.json({ success: true, data: { excavators } });
  },

  async telemetry(req: Request, res: Response) {
    const id = String(req.params.id);
    const ex = await prisma.excavator.findUnique({ where: { id } });
    if (!ex) {
      res.status(404).json({ success: false, error: 'Excavator not found' });
      return;
    }
    const latest = await prisma.excavatorTelemetry.findFirst({
      where: { excavator_id: id },
      orderBy: { recorded_at: 'desc' },
    });
    res.json({
      success: true,
      data: {
        excavator: ex,
        latest_telemetry: latest,
        immobilized: ex.immobilized,
      },
    });
  },

  async assignPit(req: Request, res: Response) {
    const id = String(req.params.id);
    const { pit_id } = req.body as { pit_id?: string };
    const ex = await prisma.excavator.findUnique({ where: { id } });
    if (!ex) {
      res.status(404).json({ success: false, error: 'Excavator not found' });
      return;
    }
    if (pit_id) {
      const pit = await prisma.pit.findFirst({
        where: { id: pit_id, license_id: ex.license_id, deleted_at: null },
      });
      if (!pit) {
        res.status(404).json({ success: false, error: 'Pit not found for license' });
        return;
      }
    }
    const updated = await prisma.excavator.update({
      where: { id },
      data: { current_pit_id: pit_id || null },
    });
    res.json({ success: true, data: updated });
  },

  async shutoff(req: Request, res: Response) {
    const id = String(req.params.id);
    const ex = await prisma.excavator.findUnique({ where: { id } });
    if (!ex) {
      res.status(404).json({ success: false, error: 'Excavator not found' });
      return;
    }
    const updated = await prisma.excavator.update({
      where: { id },
      data: { immobilized: true, status: 'MAINTENANCE' },
    });
    await prisma.excavatorIncident.create({
      data: {
        excavator_id: id,
        severity: 'RED',
        message: 'Remote immobilizer triggered by MD',
        outside_fence: false,
        low_ppm: false,
      },
    });
    res.json({ success: true, data: updated });
  },

  async route(req: Request, res: Response) {
    const id = String(req.params.id);
    const ex = await prisma.excavator.findUnique({ where: { id } });
    if (!ex) {
      res.status(404).json({ success: false, error: 'Excavator not found' });
      return;
    }
    const blocks = await prisma.blockModel.findMany({
      where: { license_id: ex.license_id, ppm_estimate: { gte: 0.5 } },
      orderBy: { ppm_estimate: 'desc' },
      take: 200,
      select: { block_x: true, block_y: true, block_z: true, ppm_estimate: true },
    });
    res.json({ success: true, data: { approved_cells: blocks } });
  },

  /** POST body: simulate telemetry (MVP IoT ingest) */
  async ingestTelemetry(req: Request, res: Response) {
    const id = String(req.params.id);
    const b = req.body as {
      lat?: number;
      lng?: number;
      altitude_m?: number;
      payload_tons?: number;
      ppm_reading?: number;
      fuel_percent?: number;
    };
    const ex = await prisma.excavator.findUnique({
      where: { id },
      include: { pit: true },
    });
    if (!ex) {
      res.status(404).json({ success: false, error: 'Excavator not found' });
      return;
    }
    if (b.lat == null || b.lng == null) {
      res.status(400).json({ success: false, error: 'lat and lng required' });
      return;
    }
    if (ex.immobilized) {
      res.status(423).json({ success: false, error: 'Excavator immobilized' });
      return;
    }

    let outside = false;
    if (ex.pit) {
      const d =
        Math.abs(b.lat - ex.pit.gps_latitude) + Math.abs(b.lng - ex.pit.gps_longitude);
      if (d > 0.02) outside = true;
    }

    const lowPpm = b.ppm_reading != null && isWaste(b.ppm_reading);

    const row = await prisma.excavatorTelemetry.create({
      data: {
        excavator_id: id,
        lat: b.lat,
        lng: b.lng,
        altitude_m: b.altitude_m,
        payload_tons: b.ppm_reading != null ? b.payload_tons : undefined,
        ppm_reading: b.ppm_reading,
        fuel_percent: b.fuel_percent,
        engine_hours_snapshot: ex.engine_hours,
      },
    });

    await prisma.excavator.update({
      where: { id },
      data: { last_lat: b.lat, last_lng: b.lng },
    });

    if (outside || lowPpm) {
      await prisma.excavator.update({
        where: { id },
        data: { immobilized: true, status: 'MAINTENANCE' },
      });
      await prisma.excavatorIncident.create({
        data: {
          excavator_id: id,
          severity: 'RED',
          message: outside
            ? 'Moved outside approved pit zone'
            : `Low grade ${b.ppm_reading} PPM — waste band`,
          outside_fence: outside,
          low_ppm: lowPpm,
        },
      });
    }

    res.json({
      success: true,
      data: {
        telemetry: row,
        alerts: { outside_fence: outside, low_ppm: lowPpm, grade_band: b.ppm_reading != null ? gradeBand(b.ppm_reading) : null },
      },
    });
  },
};
