import { Request, Response } from 'express';
import PDFDocument from 'pdfkit';
import QRCode from 'qrcode';
import { prisma } from '../models';
import { calculateBlendTwo, calculateBlendThree } from '../lib/module-b';

function blendPdfBuffer(title: string, lines: string[], qrData: string): Promise<Buffer> {
  return new Promise((resolve, reject) => {
    const chunks: Buffer[] = [];
    const doc = new PDFDocument({ margin: 40 });
    doc.on('data', (c) => chunks.push(c as Buffer));
    doc.on('end', () => resolve(Buffer.concat(chunks)));
    doc.on('error', reject);
    doc.fontSize(16).text(title, { underline: true });
    doc.moveDown();
    lines.forEach((l) => {
      doc.fontSize(11).text(l);
      doc.moveDown(0.3);
    });
    QRCode.toDataURL(qrData)
      .then((dataUrl: string) => {
        const base64 = dataUrl.replace(/^data:image\/png;base64,/, '');
        const img = Buffer.from(base64, 'base64');
        doc.image(img, { width: 120 });
        doc.end();
      })
      .catch(reject);
  });
}

export const blendingController = {
  async calculate(req: Request, res: Response) {
    const b = req.body as {
      target_plant?: string;
      target_ppm?: number;
      target_tons?: number;
      source_1?: { pit_id: string; ppm: number };
      source_2?: { pit_id: string; ppm: number };
      source_3?: { pit_id: string; ppm: number; tons?: number };
      issued_by?: string;
    };
    if (
      !b.target_plant ||
      b.target_ppm == null ||
      b.target_tons == null ||
      !b.source_1 ||
      !b.source_2
    ) {
      res.status(400).json({
        success: false,
        error: 'target_plant, target_ppm, target_tons, source_1, source_2 required',
      });
      return;
    }
    try {
      let result;
      let s3tons = 0;
      if (b.source_3?.pit_id && b.source_3.tons && b.source_3.tons > 0) {
        s3tons = b.source_3.tons;
        result = calculateBlendThree(
          { tons: 0, ppm: b.source_1.ppm },
          { tons: 0, ppm: b.source_2.ppm },
          { tons: 0, ppm: b.source_3.ppm },
          b.target_tons,
          b.target_ppm,
          s3tons
        );
      } else {
        const r = calculateBlendTwo(
          { tons: 0, ppm: b.source_1.ppm },
          { tons: 0, ppm: b.source_2.ppm },
          b.target_tons,
          b.target_ppm
        );
        result = { ...r, source3_tons: 0 };
      }

      const rec = await prisma.blendingInstruction.create({
        data: {
          target_plant: b.target_plant,
          target_ppm: b.target_ppm,
          target_tons: b.target_tons,
          source_1_pit_id: b.source_1.pit_id,
          source_1_tons: result.source1_tons,
          source_1_ppm: b.source_1.ppm,
          source_2_pit_id: b.source_2.pit_id,
          source_2_tons: result.source2_tons,
          source_2_ppm: b.source_2.ppm,
          source_3_pit_id: b.source_3?.pit_id,
          source_3_tons: result.source3_tons || undefined,
          source_3_ppm: b.source_3?.ppm,
          result_ppm: result.result_ppm,
          issued_by: b.issued_by ?? (req.user?.email ?? 'unknown'),
          status: 'PENDING',
        },
      });
      res.json({ success: true, data: { instruction: rec } });
    } catch (e) {
      const msg = e instanceof Error ? e.message : 'blend error';
      res.status(400).json({ success: false, error: msg });
    }
  },

  async generateManifest(req: Request, res: Response) {
    const id = String(req.params.id);
    const rec = await prisma.blendingInstruction.findUnique({ where: { id } });
    if (!rec) {
      res.status(404).json({ success: false, error: 'Instruction not found' });
      return;
    }
    const lines = [
      `Plant: ${rec.target_plant}`,
      `Target ${rec.target_tons} t @ ${rec.target_ppm} PPM`,
      `Source 1 pit ${rec.source_1_pit_id}: ${rec.source_1_tons.toFixed(1)} t @ ${rec.source_1_ppm} PPM`,
      `Source 2 pit ${rec.source_2_pit_id}: ${(rec.source_2_tons ?? 0).toFixed(1)} t @ ${rec.source_2_ppm} PPM`,
      `Result PPM: ${rec.result_ppm.toFixed(3)}`,
      `Issued by: ${rec.issued_by}`,
    ];
    const qrPayload = JSON.stringify({ blend_id: rec.id, plant: rec.target_plant });
    const pdf = await blendPdfBuffer('Blend manifest', lines, qrPayload);
    const base64 = pdf.toString('base64');
    const dataUrl = `data:application/pdf;base64,${base64}`;
    await prisma.blendingInstruction.update({
      where: { id },
      data: { manifest_pdf_url: dataUrl },
    });
    res.json({ success: true, data: { manifest_pdf_base64: base64, manifest_pdf_url: dataUrl } });
  },

  async history(req: Request, res: Response) {
    const plant = String(req.params.plant);
    const rows = await prisma.blendingInstruction.findMany({
      where: { target_plant: plant },
      orderBy: { created_at: 'desc' },
      take: 100,
    });
    res.json({ success: true, data: { blends: rows } });
  },
};
