import PDFDocument from "pdfkit";
import type { Response } from "express";
import { PdfHeader } from "./components/PdfHeader.js";
import type { AttendanceExportDataPayload } from "../excel/attendanceExportExcel.js";

const COLORS = {
  primary: "#0F5132",
  accent: "#198754",
  text: "#212529",
  muted: "#6C757D",
  border: "#DEE2E6",
  rowAlt: "#F8F9FA",
  present: "#15803d",
  absent: "#b91c1c",
  halfDay: "#d97706",
};

const PAGE_MARGIN = 36;

export class AttendanceExportPdf {
  static async generate(payload: AttendanceExportDataPayload, res: Response, filename: string) {
    const isLandScape = payload.reportType === "REGISTER";
    const doc = new PDFDocument({
      size: "A4",
      layout: isLandScape ? "landscape" : "portrait",
      margin: PAGE_MARGIN,
      bufferPages: true,
    });

    res.setHeader("Content-Type", "application/pdf");
    res.setHeader("Content-Disposition", `attachment; filename="${filename}"`);
    res.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
    doc.pipe(res);

    const pageWidth = doc.page.width - PAGE_MARGIN * 2;

    // Header
    await PdfHeader.draw(doc, pageWidth, PAGE_MARGIN, payload.title.toUpperCase());

    if (payload.subtitle) {
      doc
        .font("Helvetica-Oblique")
        .fontSize(9)
        .fillColor(COLORS.muted)
        .text(payload.subtitle, PAGE_MARGIN, doc.y, { width: pageWidth, align: "right" });
      doc.y += 10;
    }

    if (payload.reportType === "REGISTER") {
      this.drawRegisterTable(doc, payload, pageWidth);
    } else if (payload.reportType === "MONTHLY_SUMMARY" || payload.reportType === "ATTENDANCE_SUMMARY") {
      this.drawMonthlySummaryTable(doc, payload, pageWidth);
    } else if (payload.reportType === "EMPLOYEE") {
      this.drawEmployeeTable(doc, payload, pageWidth);
    } else {
      this.drawStandardTable(doc, payload, pageWidth);
    }

    this.drawFooter(doc, pageWidth);
    doc.end();
  }

  private static drawRegisterTable(doc: PDFKit.PDFDocument, payload: AttendanceExportDataPayload, pageWidth: number) {
    const days = payload.daysInMonth || 31;
    const nameWidth = 140;
    const dayWidth = (pageWidth - nameWidth) / days;

    const rowHeight = 20;

    const drawHeader = () => {
      const y = doc.y;
      doc.font("Helvetica-Bold").fontSize(7.5).fillColor(COLORS.primary);
      doc.text("EMPLOYEE", PAGE_MARGIN, y + 5, { width: nameWidth });

      for (let d = 1; d <= days; d++) {
        const x = PAGE_MARGIN + nameWidth + (d - 1) * dayWidth;
        doc.text(`${d}`, x, y + 5, { width: dayWidth, align: "center" });
      }

      doc.y = y + rowHeight;
      doc.moveTo(PAGE_MARGIN, doc.y).lineTo(PAGE_MARGIN + pageWidth, doc.y).strokeColor(COLORS.primary).stroke();
      doc.y += 2;
    };

    drawHeader();

    payload.records.forEach((emp, idx) => {
      if (doc.y + rowHeight > doc.page.height - PAGE_MARGIN - 40) {
        doc.addPage();
        doc.y = PAGE_MARGIN;
        drawHeader();
      }

      const y = doc.y;
      if (idx % 2 === 1) {
        doc.rect(PAGE_MARGIN, y, pageWidth, rowHeight).fill(COLORS.rowAlt);
      }

      doc.font("Helvetica-Bold").fontSize(7.5).fillColor(COLORS.text);
      doc.text(emp.name, PAGE_MARGIN + 2, y + 5, { width: nameWidth - 4, ellipsis: true });

      for (let d = 1; d <= days; d++) {
        const st = emp.daily?.[d]?.status;
        let txt = "-";
        let color = COLORS.muted;

        if (st === "PRESENT") {
          txt = "P";
          color = COLORS.present;
        } else if (st === "ABSENT") {
          txt = "A";
          color = COLORS.absent;
        } else if (st === "HALF_DAY") {
          txt = "HD";
          color = COLORS.halfDay;
        }

        const x = PAGE_MARGIN + nameWidth + (d - 1) * dayWidth;
        doc.font("Helvetica-Bold").fontSize(7).fillColor(color);
        doc.text(txt, x, y + 5, { width: dayWidth, align: "center" });
      }

      doc.y = y + rowHeight;
    });

    doc.y += 10;
    doc.font("Helvetica").fontSize(8).fillColor(COLORS.muted);
    doc.text("Legend: P = Present (Green)  |  A = Absent (Red)  |  HD = Half Day (Orange)", PAGE_MARGIN, doc.y, {
      width: pageWidth,
      align: "center",
    });
  }

  private static drawMonthlySummaryTable(doc: PDFKit.PDFDocument, payload: AttendanceExportDataPayload, pageWidth: number) {
    const cols = {
      no: { x: PAGE_MARGIN, width: pageWidth * 0.06 },
      code: { x: PAGE_MARGIN + pageWidth * 0.06, width: pageWidth * 0.14 },
      name: { x: PAGE_MARGIN + pageWidth * 0.2, width: pageWidth * 0.44 },
      p: { x: PAGE_MARGIN + pageWidth * 0.64, width: pageWidth * 0.09 },
      a: { x: PAGE_MARGIN + pageWidth * 0.73, width: pageWidth * 0.09 },
      hd: { x: PAGE_MARGIN + pageWidth * 0.82, width: pageWidth * 0.09 },
      rate: { x: PAGE_MARGIN + pageWidth * 0.91, width: pageWidth * 0.09 },
    };

    const rowHeight = 22;

    const drawHeader = () => {
      const y = doc.y;
      doc.font("Helvetica-Bold").fontSize(8.5).fillColor(COLORS.primary);
      doc.text("#", cols.no.x, y + 5, { width: cols.no.width, align: "center" });
      doc.text("CODE", cols.code.x, y + 5, { width: cols.code.width });
      doc.text("EMPLOYEE NAME", cols.name.x, y + 5, { width: cols.name.width });
      doc.text("PRESENT", cols.p.x, y + 5, { width: cols.p.width, align: "center" });
      doc.text("ABSENT", cols.a.x, y + 5, { width: cols.a.width, align: "center" });
      doc.text("HALF DAY", cols.hd.x, y + 5, { width: cols.hd.width, align: "center" });
      doc.text("RATE %", cols.rate.x, y + 5, { width: cols.rate.width, align: "center" });

      doc.y = y + rowHeight;
      doc.moveTo(PAGE_MARGIN, doc.y).lineTo(PAGE_MARGIN + pageWidth, doc.y).strokeColor(COLORS.primary).stroke();
      doc.y += 2;
    };

    drawHeader();

    payload.records.forEach((emp, i) => {
      if (doc.y + rowHeight > doc.page.height - PAGE_MARGIN - 40) {
        doc.addPage();
        doc.y = PAGE_MARGIN;
        drawHeader();
      }

      const y = doc.y;
      if (i % 2 === 1) doc.rect(PAGE_MARGIN, y, pageWidth, rowHeight).fill(COLORS.rowAlt);

      const stats = emp.stats || {};
      doc.font("Helvetica").fontSize(8.5).fillColor(COLORS.text);
      doc.text(`${i + 1}`, cols.no.x, y + 5, { width: cols.no.width, align: "center" });
      doc.text(emp.employeeCode || "-", cols.code.x, y + 5, { width: cols.code.width });
      doc.text(emp.name || emp.employeeName || "-", cols.name.x, y + 5, { width: cols.name.width - 4, ellipsis: true });

      doc.font("Helvetica-Bold").fillColor(COLORS.present);
      doc.text(`${stats.presentDays ?? 0}`, cols.p.x, y + 5, { width: cols.p.width, align: "center" });
      doc.fillColor(COLORS.absent);
      doc.text(`${stats.absentDays ?? 0}`, cols.a.x, y + 5, { width: cols.a.width, align: "center" });
      doc.fillColor(COLORS.halfDay);
      doc.text(`${stats.halfDays ?? 0}`, cols.hd.x, y + 5, { width: cols.hd.width, align: "center" });
      doc.fillColor(COLORS.primary);
      doc.text(`${stats.attendanceRate ?? stats.attendancePercentage ?? 0}%`, cols.rate.x, y + 5, {
        width: cols.rate.width,
        align: "center",
      });

      doc.y = y + rowHeight;
    });
  }

  private static drawEmployeeTable(doc: PDFKit.PDFDocument, payload: AttendanceExportDataPayload, pageWidth: number) {
    const cols = {
      no: { x: PAGE_MARGIN, width: pageWidth * 0.1 },
      date: { x: PAGE_MARGIN + pageWidth * 0.1, width: pageWidth * 0.25 },
      status: { x: PAGE_MARGIN + pageWidth * 0.35, width: pageWidth * 0.25 },
      remarks: { x: PAGE_MARGIN + pageWidth * 0.6, width: pageWidth * 0.4 },
    };

    const rowHeight = 22;

    const drawHeader = () => {
      const y = doc.y;
      doc.font("Helvetica-Bold").fontSize(8.5).fillColor(COLORS.primary);
      doc.text("#", cols.no.x, y + 5, { width: cols.no.width, align: "center" });
      doc.text("DATE", cols.date.x, y + 5, { width: cols.date.width });
      doc.text("STATUS", cols.status.x, y + 5, { width: cols.status.width });
      doc.text("REMARKS", cols.remarks.x, y + 5, { width: cols.remarks.width });

      doc.y = y + rowHeight;
      doc.moveTo(PAGE_MARGIN, doc.y).lineTo(PAGE_MARGIN + pageWidth, doc.y).strokeColor(COLORS.primary).stroke();
      doc.y += 2;
    };

    drawHeader();

    payload.records.forEach((rec, i) => {
      if (doc.y + rowHeight > doc.page.height - PAGE_MARGIN - 40) {
        doc.addPage();
        doc.y = PAGE_MARGIN;
        drawHeader();
      }

      const y = doc.y;
      if (i % 2 === 1) doc.rect(PAGE_MARGIN, y, pageWidth, rowHeight).fill(COLORS.rowAlt);

      doc.font("Helvetica").fontSize(8.5).fillColor(COLORS.text);
      doc.text(`${i + 1}`, cols.no.x, y + 5, { width: cols.no.width, align: "center" });
      doc.text(rec.date, cols.date.x, y + 5, { width: cols.date.width });

      let statusColor = COLORS.text;
      if (rec.status === "PRESENT") statusColor = COLORS.present;
      else if (rec.status === "ABSENT") statusColor = COLORS.absent;
      else if (rec.status === "HALF_DAY") statusColor = COLORS.halfDay;

      doc.font("Helvetica-Bold").fillColor(statusColor);
      doc.text(rec.status, cols.status.x, y + 5, { width: cols.status.width });

      doc.font("Helvetica").fillColor(COLORS.text);
      doc.text(rec.remarks || "-", cols.remarks.x, y + 5, { width: cols.remarks.width, ellipsis: true });

      doc.y = y + rowHeight;
    });

    if (payload.summary) {
      doc.y += 12;
      doc.font("Helvetica-Bold").fontSize(9).fillColor(COLORS.primary);
      const sumText = `Total Working Days: ${payload.summary.totalDays}   |   Present: ${payload.summary.presentDays}   |   Absent: ${payload.summary.absentDays}   |   Half Day: ${payload.summary.halfDays}   |   Attendance Rate: ${payload.summary.attendancePercentage}%`;
      doc.text(sumText, PAGE_MARGIN, doc.y, { width: pageWidth, align: "center" });
    }
  }

  private static drawStandardTable(doc: PDFKit.PDFDocument, payload: AttendanceExportDataPayload, pageWidth: number) {
    const cols = {
      no: { x: PAGE_MARGIN, width: pageWidth * 0.06 },
      date: { x: PAGE_MARGIN + pageWidth * 0.06, width: pageWidth * 0.14 },
      code: { x: PAGE_MARGIN + pageWidth * 0.2, width: pageWidth * 0.12 },
      name: { x: PAGE_MARGIN + pageWidth * 0.32, width: pageWidth * 0.24 },
      status: { x: PAGE_MARGIN + pageWidth * 0.56, width: pageWidth * 0.16 },
      remarks: { x: PAGE_MARGIN + pageWidth * 0.72, width: pageWidth * 0.28 },
    };

    const rowHeight = 22;

    const drawHeader = () => {
      const y = doc.y;
      doc.font("Helvetica-Bold").fontSize(8.5).fillColor(COLORS.primary);
      doc.text("#", cols.no.x, y + 5, { width: cols.no.width, align: "center" });
      doc.text("DATE", cols.date.x, y + 5, { width: cols.date.width });
      doc.text("CODE", cols.code.x, y + 5, { width: cols.code.width });
      doc.text("EMPLOYEE", cols.name.x, y + 5, { width: cols.name.width });
      doc.text("STATUS", cols.status.x, y + 5, { width: cols.status.width });
      doc.text("REMARKS", cols.remarks.x, y + 5, { width: cols.remarks.width });

      doc.y = y + rowHeight;
      doc.moveTo(PAGE_MARGIN, doc.y).lineTo(PAGE_MARGIN + pageWidth, doc.y).strokeColor(COLORS.primary).stroke();
      doc.y += 2;
    };

    drawHeader();

    payload.records.forEach((rec, i) => {
      if (doc.y + rowHeight > doc.page.height - PAGE_MARGIN - 40) {
        doc.addPage();
        doc.y = PAGE_MARGIN;
        drawHeader();
      }

      const y = doc.y;
      if (i % 2 === 1) doc.rect(PAGE_MARGIN, y, pageWidth, rowHeight).fill(COLORS.rowAlt);

      doc.font("Helvetica").fontSize(8.5).fillColor(COLORS.text);
      doc.text(`${i + 1}`, cols.no.x, y + 5, { width: cols.no.width, align: "center" });
      doc.text(rec.date || "-", cols.date.x, y + 5, { width: cols.date.width });
      doc.text(rec.employeeCode || "-", cols.code.x, y + 5, { width: cols.code.width });
      doc.text(rec.employeeName || rec.name || "-", cols.name.x, y + 5, { width: cols.name.width - 4, ellipsis: true });

      let statusColor = COLORS.text;
      if (rec.status === "PRESENT") statusColor = COLORS.present;
      else if (rec.status === "ABSENT") statusColor = COLORS.absent;
      else if (rec.status === "HALF_DAY") statusColor = COLORS.halfDay;

      doc.font("Helvetica-Bold").fillColor(statusColor);
      doc.text(rec.status || "-", cols.status.x, y + 5, { width: cols.status.width });

      doc.font("Helvetica").fillColor(COLORS.text);
      doc.text(rec.remarks || "-", cols.remarks.x, y + 5, { width: cols.remarks.width - 4, ellipsis: true });

      doc.y = y + rowHeight;
    });
  }

  private static drawFooter(doc: PDFKit.PDFDocument, pageWidth: number) {
    const y = doc.page.height - PAGE_MARGIN - 20;
    doc
      .font("Helvetica-Oblique")
      .fontSize(8)
      .fillColor(COLORS.muted)
      .text("This is a computer-generated attendance report.", PAGE_MARGIN, y, {
        width: pageWidth,
        align: "center",
      });
  }
}
