import fs from "fs";
import axios from "axios";
/*
|--------------------------------------------------------------------------
| Routes
|--------------------------------------------------------------------------
|
| This file is dedicated for defining HTTP routes. A single file is enough
| for majority of projects, however you can define routes in different
| files and just make sure to import them inside this file. For example
|
| Define routes in following two files
| ├── start/routes/cart.ts
| ├── start/routes/customer.ts
|
| and then import them inside `start/routes.ts` as follows
|
| import './routes/cart'
| import './routes/customer'
|
*/

import Route from "@ioc:Adonis/Core/Route";
import { runtimeCheckLogs } from "App/utils/runtimeCheckLogs";
import Env from "@ioc:Adonis/Core/Env";
import { sendMessToZulip } from "App/utils/sendMessToZulip";
import moment from "moment";
import Product from "App/Models/Product";
import { sendDeviceInfora } from "App/utils/sendDeviceInfor";
import InfoDevice from "App/Models/InfoDevice";
import LogReport from "App/Models/LogReport";
import Cache from "@ioc:Kaperskyguru/Adonis-Cache";
import { checkDateWiki } from "App/utils/helper";
const util = require("util");
const exec = util.promisify(require("child_process").exec);
const { DocumentProcessorServiceClient } =
  require("@google-cloud/documentai").v1;
const fs = require("fs");
const path = require("path");

runtimeCheckLogs(Env.get("FOLDER_LOGS"));

Route.post("/api/getIndexSerialNumber", "ErpsController.getIndexSerialNumber")
  .middleware("checkToken")
  .middleware("writeLog");
// .middleware("writeLog");

Route.post("/api/getParagraph", "ErpsController.getParagraph")
  .middleware("checkToken")
  .middleware("writeLog");

//Users
Route.post("/api/account/createUser", "UsersController.create").middleware(
  "writeLog"
);

Route.post("/api/account/checkLogin", "UsersController.checkLogin").middleware(
  "writeLog"
);

//Log
Route.get("/api/log/showLog/:name?", "LogsController.showLog").middleware(
  "writeLog"
);

Route.get("/api/getAllLogDetect", "LogsController.getAllLogDetect");

//Key-Value
Route.post("/api/getKeyValue", "ValuesController.getKeyValue");

Route.post("/api/deleteValue", "ValuesController.destroy").middleware(
  "writeLog"
);

Route.post("/api/editValue", "ValuesController.edit").middleware("writeLog");

Route.post("/api/addValue", "ValuesController.create").middleware("writeLog");

Route.post("/api/backupProduct", async ({ request, response }) => {
  try {
    const from = request.all().from || moment(Date.now()).format("YYYYMMDD");
    const to = request.all().to || moment(Date.now()).format("YYYYMMDD");
    const res = await axios.post(
      "https://logs.danielvu.com/api/getIndexSerialNumber",
      { from: from, to: to },
      {
        headers: {
          Authorization: request.headers().authorization?.replace(/"/g, ""),
        },
      }
    );

    res.data.map((obj, index) => {
      res.data[index] = {
        PID: res.data[index].PID,
        SN: res.data[index].SN,
        VID: res.data[index].VID,
        line: res.data[index].line.join(","),
        file: res.data[index].fileName,
        warehouse: res.data[index].warehouse,
      };
    });
    await Product.createMany(res.data);
    // console.log(addProduct)
    response.status(200).send("Add " + res.data.length + " success!");
    await sendMessToZulip(
      "stream",
      "networkToolBot",
      "Log service",
      "Backup product " +
      from +
      " to " +
      to +
      " success with " +
      res.data.length +
      " products"
    );
  } catch (error) {
    response.status(500).send(error);
    await sendMessToZulip(
      "stream",
      "networkToolBot",
      "Log service",
      "Backup product fail. Please check!"
    );
  }
}).middleware("writeLog");

Route.post("/api/sendMailInforDevice", async () => {
  try {
    sendDeviceInfora();
  } catch (error) {
    console.log(error);
  }
})
  .middleware("checkToken")
  .middleware("writeLog");

Route.post(
  "/api/private-log/getFileOnFolder",
  async ({ request, response }) => {
    try {
      let result = [];
      let path = request.all().folerPath;
      return new Promise((resolve, reject) => {
        fs.readdir(path, (err, entries) => {
          if (err) {
            reject(err);
            return;
          }

          entries.forEach((entry) => {
            const entryPath = path + "/" + entry;

            fs.stat(entryPath, (statErr, stats) => {
              if (statErr) {
                reject(statErr);
                return;
              }

              const type = stats.isFile() ? "file" : "directory";
              result.push({ name: entryPath, type: type });

              if (result.length === entries.length) {
                resolve(result);
              }
            });
          });
        });
      });
    } catch (error) {
      console.log(error);
    }
  }
);

Route.post("/api/private-log/readFile", async ({ request, response }) => {
  try {
    let result = [];
    let path = request.all().filePath;
    return await fs.readFileSync(path, "utf8");
  } catch (error) {
    console.log(error);
  }
});

Route.post("/api/extension/addressDetect", async ({ request, response }) => {
  // TODO(developer): Uncomment these variables before running the sample.
  const projectId = "532287737140";
  const location = "us"; // Format is 'us' or 'eu'
  const processorId = "64ad0cc100561909"; // Create processor before running sample
  // const filePath = "https://int.ipsupply.com.au/upload/temp/packagepurchaseorder_17162360547876.jpeg";
  const mimeType = "image/jpeg"; // Refer to https://cloud.google.com/document-ai/docs/file-types for supported file types
  const fieldMask = ["entities"]; // Optional. The fields to return in the Document object.
  const processorVersionId = "8aa31873669ac16f"; // Optional. Processor version to use
  const bucketName = "get-address"; // Replace with your GCS bucket name

  // Set up authentication
  process.env.GOOGLE_APPLICATION_CREDENTIALS =
    "strategic-block-424302-v3-54b10fc7e085.json";

  async function downloadFile(url, outputLocationPath) {
    const writer = fs.createWriteStream(outputLocationPath);
    const response = await axios({
      url,
      method: "GET",
      responseType: "stream",
    });
    response.data.pipe(writer);
    return new Promise((resolve, reject) => {
      writer.on("finish", resolve);
      writer.on("error", reject);
    });
  }

  async function processDocument(filePath) {
    const client = new DocumentProcessorServiceClient();

    let name;
    if (processorVersionId) {
      // The full resource name of the processor version, e.g.:
      // `projects/${projectId}/locations/${location}/processors/${processorId}/processorVersions/${processorVersionId}`
      name = client.processorVersionPath(
        projectId,
        location,
        processorId,
        processorVersionId
      );
    } else {
      // The full resource name of the processor, e.g.:
      // `projects/${projectId}/locations/${location}/processors/${processorId}`
      name = client.processorPath(projectId, location, processorId);
    }

    // Download the file from URL
    let imageContent;
    const tempFilePath = path.join(__dirname, "images/temp.jpeg");
    if (filePath.includes("http")) {
      console.log("Download file");
      await downloadFile(filePath, tempFilePath);
      imageContent = fs.readFileSync(tempFilePath);
    } else {
      imageContent = fs.readFileSync(filePath);
    }
    // Read the file into memory
    // imageContent = fs.readFileSync(filePath);

    // Load binary data
    const rawDocument = {
      content: imageContent,
      mimeType: mimeType,
    };

    // Optional: Additional configurations for processing.
    const processOptions = {
      individualPageSelector: {
        pages: [1],
      },
    };

    // Configure the process request
    const request = {
      name: name,
      rawDocument: rawDocument,
      fieldMask: fieldMask, // Join fieldMask array into a comma-separated string
      processOptions: processOptions,
    };

    const [result] = await client.processDocument(request);

    // For a full list of `Document` object attributes, reference this page:
    // https://cloud.google.com/document-ai/docs/reference/rest/v1/Document
    const document = result.document;

    // Read the text recognition output from the processor
    console.log("The document contains the following text:");
    return extractAndPrintData(document.entities);
  }

  // Function to extract and print data
  function extractAndPrintData(response) {
    let result = "";
    response.forEach((item) => {
      const type = item.type;
      const mentionText = item.mentionText;
      result += `${type} : ${mentionText}\n\n`;
    });
    return result;
  }
  const { filePath } = request.all();;
  console.log(filePath)
  try {
    await processDocument(filePath).then((result) => {
      console.log(result)
      response.status(200).send(JSON.stringify(result));
    }).catch((e) => console.log(e));
  } catch (error) {
    response.status(500).send(`Error: ${error.message}`);
  }
});

Route.post("/api/find-value", async ({ request, response }) => {
  try {
    const { value } = request.all();

    console.log(value);
    const { stdout, stderr } = await exec(`grep -nrE "${value}" /home/logs`, {
      maxBuffer: 1024 * 500,
    });

    // response.status(200).send("sdjkghs");
    response.status(200).send(JSON.stringify(stdout));
  } catch (error) {
    console.error(error);
    response.status(500).send(`Error: ${error.message}`);
  }
});

Route.post("/api/test", async () => {
  try {
    const logs = await Cache.get("logs");

    if (logs) {
      return { type: "cache", data: logs };
    } else {
      let data = await LogReport.all();
      Cache.set("logs", data, 120);
      return { type: "no cache", data: data };
    }
  } catch (error) {
    console.log(error);
  }
});


Route.post('/api/wiki/page/insert', async ({ request, response }) => {
  try {
    const { title, data: dataPayload, pid, vid, sn, lineNumber, license } = request.all()
    if (!title || !dataPayload) {
      return response.status(422).send({ error: `'title' & 'text' is required` })
    }

    let text = ""
    if (typeof dataPayload === "string")
      text = dataPayload.replace(/\\n/g, '\n')
    else if (Array.isArray(dataPayload)) {
      const dataPlatform = dataPayload?.find(el => el.command?.trim() === "show platform")
      const DPELP = dataPlatform && !dataPlatform?.output?.includes("Incomplete") ? true : false
      text = `<pre>
Line ${lineNumber ?? ""}:
PID: ${pid ?? ""}
VID: ${vid ?? ""}
SN:  ${sn ?? ""}
Tested mode: ${DPELP ? "DPELP" : "DPEL"}
License:  ${license ?? ""}
</pre>
`
    }

    // ============ LOGIN LẤY COOKIE ============
    const loginTokenRes = await fetch(
      'https://jv.ipsupply.com.au/wiki/api.php?action=query&meta=tokens&type=login&format=json'
    )
    const loginToken = (await loginTokenRes.json())?.query?.tokens?.logintoken
    if (!loginToken) return response.status(500).send('Không lấy được loginToken')

    // gửi login
    const bodyLogin = new URLSearchParams()
    bodyLogin.append('username', 'Ips')
    bodyLogin.append('password', 'Work1234%')
    bodyLogin.append('logintoken', loginToken)
    bodyLogin.append('format', 'json')
    bodyLogin.append("loginreturnurl", "https://jv.ipsupply.com.au/wiki")

    const loginRes = await fetch(
      'https://jv.ipsupply.com.au/wiki/api.php?action=clientlogin',
      {
        method: 'POST',
        headers: { 'Content-Type': 'application/x-www-form-urlencoded', cookie: loginTokenRes.headers.get('set-cookie') ?? '' },
        body: bodyLogin,
      }
    )
    const loginCookies = loginRes.headers.raw()['set-cookie']?.join('; ') ?? ''
    const loginData = await loginRes.json()
    if (loginData?.clientlogin?.status !== 'PASS') {
      return response.status(500).send(loginData)
    }

    // ============ LẤY CSRF TOKEN ============
    const csrfRes = await fetch(
      'https://jv.ipsupply.com.au/wiki/api.php?action=query&meta=tokens&type=csrf&format=json',
      {
        headers: { cookie: loginCookies },
      }
    )
    const csrfToken = (await csrfRes.json())?.query?.tokens?.csrftoken
    if (!csrfToken) return response.status(500).send('Không lấy được CSRF token')

    // ============ LẤY PAGE CŨ ============
    const pageRes = await fetch(
      `https://jv.ipsupply.com.au/wiki/api.php?action=query&prop=revisions&rvprop=content&format=json&titles=${encodeURIComponent(title)}`,
      {
        headers: { cookie: loginCookies },
      }
    )
    const pageJson = await pageRes.json()
    const pageId = Object.keys(pageJson.query.pages)[0]
    const oldContent = pageJson.query.pages[pageId]?.revisions?.[0]?.['*'] ?? ''

    // nối nội dung mới vào
    const now = new Date();
    const lineDate = `${String(now.getDate()).padStart(2, "0")}/${String(now.getMonth() + 1).padStart(2, "0")}/${now.getFullYear()}`;
    const scopeDate = `-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*<br/>ngay ${lineDate}<br/>-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*<br/><br/>`
    const newText = `${scopeDate}${text}\n\n${checkDateWiki(oldContent) ? oldContent.replace(scopeDate, "") : oldContent}`

    // ============ EDIT PAGE ============
    const formData = new FormData()
    formData.append('text', newText)
    formData.append('token', csrfToken)

    const editRes = await fetch(
      `https://jv.ipsupply.com.au/wiki/api.php?action=edit&format=json&title=${encodeURIComponent(title)}`,
      {
        method: 'POST',
        headers: { cookie: loginCookies },
        body: formData,
      }
    )
    const editResult = await editRes.json()
    return response.status(200).send(editResult)
  } catch (err) {
    console.error(err)
    return response.status(500).send(err)
  }
})

Route.post("/api/po-email/packing-slip", async ({ request, response }) => {
  try {
    const { data } = request.all()
    const PDFDocument = require('pdfkit')
    const getStream = require('stream-buffers')

    function generatePackingSlip(inputData) {

      function loadFont(name) {
        return path.join(__dirname, 'fonts', name + ".ttf")
      }

      const doc = new PDFDocument({
        size: 'A4',
        margins: { top: 50, bottom: 50, left: 50, right: 50 }
      })
      const stream = new getStream.WritableStreamBuffer()

      // Layout parameters
      const leftMargin = 50
      const pageWidth = 500
      const rightColumnX = 420
      let y = doc.y

      doc.pipe(stream)

      // ===== LOGO (LEFT COLUMN) =====
      const logoPath = '/home/Log_service/start/images/IP-Supply-Logo.png'
      try {
        doc.image(logoPath, leftMargin, y, { width: 180 })
      } catch (err) {
        console.warn('⚠️ Logo not found:', logoPath)
      }

      // ===== HEADER (RIGHT COLUMN) =====
      doc.font(loadFont('calibri-bold')).fontSize(18).fillColor('#396190')
        .text('IP Supply Pty Ltd', rightColumnX, y, { width: 195, align: 'left' })

      doc.fillColor('black').font(loadFont('calibri-regular')).fontSize(10)
      doc.text('Unit 8, 4A Bachell Ave', rightColumnX, doc.y, { width: 195, align: 'left' })
      doc.text('Lidcombe NSW 2141', rightColumnX, doc.y, { width: 195, align: 'left' })
      doc.text('Australia', rightColumnX, doc.y, { width: 195, align: 'left' })

      doc.moveDown(1.5)

      // ===== CONTACT INFO (TWO COLUMNS) =====
      const contactY = doc.y

      // Left column - ABN, ACN
      doc.font(loadFont('calibri-bold')).fontSize(10)
      doc.text('ABN: ', leftMargin, contactY, { continued: true })
      doc.font(loadFont('calibri-regular')).text('66 145 174 358')

      doc.font(loadFont('calibri-bold'))
      doc.text('ACN: ', leftMargin, doc.y, { continued: true })
      doc.font(loadFont('calibri-regular')).text('145 174 358')

      // Right column - Phone, Mobile, Email
      doc.font(loadFont('calibri-bold'))
      doc.text('Ph: ', rightColumnX, contactY, { continued: true })
      doc.font(loadFont('calibri-regular')).text('02 8061 6886')

      doc.font(loadFont('calibri-bold'))
      doc.text('M: ', rightColumnX, doc.y, { continued: true })
      doc.font(loadFont('calibri-regular')).text('04 8881 6886')

      doc.font(loadFont('calibri-bold'))
      doc.text('E: ', rightColumnX, doc.y, { continued: true })
      doc.font(loadFont('calibri-regular')).text('sales@ipsupply.com.au')

      doc.moveDown(2)

      // ===== "NOT CONFIRM TO" RIBBON (if needed) =====
      // if (inputData.confirmStatus === "NOT CONFIRM TO") {
      //   doc.save()
      //   doc.fontSize(10).fillColor('white').font(loadFont('calibri-bold')
      //   const ribbonText = 'NOT CONFIRM TO'
      //   const ribbonWidth = doc.widthOfString(ribbonText) + 20
      //   doc.rotate(45, { origin: [pageWidth + leftMargin - 60, 60] })
      //   doc.rect(pageWidth + leftMargin - 80, 50, ribbonWidth, 20)
      //     .fillAndStroke('#d80000', '#a00000')
      //   doc.fillColor('white')
      //     .text(ribbonText, pageWidth + leftMargin - 70, 55)
      //   doc.restore()
      // }

      // ===== TITLE =====
      doc.fontSize(25).font(loadFont('calibri-bold')).fillColor('#396190')
        .text('PACKING SLIP', leftMargin, doc.y, { width: pageWidth, align: 'center' })
      doc.fillColor('black')
      doc.moveDown(0.5)

      // ===== SHIP TO & PO (TWO COLUMNS) =====
      const detailsY = doc.y

      // Left column - Ship To
      doc.fontSize(13).font(loadFont('calibri-bold'))
        .text('Ship To', leftMargin, detailsY)

      doc.fontSize(11).font(loadFont('calibri-regular'))
      if (inputData.shipTo.name) {
        doc.text(inputData.shipTo.name, leftMargin, doc.y, { width: 280 })
      }
      if (inputData.shipTo.address) {
        doc.text(inputData.shipTo.address, leftMargin, doc.y, { width: 280 })
      }

      if (inputData.shipTo.attn) {
        doc.text(`Attn: ${inputData.shipTo.attn}`, leftMargin, doc.y, { width: 280 })
      }

      if (inputData.shipTo.phone) {
        doc.text(`Phone: ${inputData.shipTo.phone}`, leftMargin, doc.y, { width: 280 })
      }

      // Right column - PO
      doc.font(loadFont('calibri-bold')).fontSize(11)
        .text('PO: ', rightColumnX, detailsY, { continued: true })
      doc.font(loadFont('calibri-regular'))
        .text(inputData.po || '', { width: 195 })


      // Nối tất cả value thành một chuỗi, ngăn cách bằng xuống dòng
      const joined = Object.values(inputData.shipTo).join('\n');

      // Tách theo \n và đếm số dòng (bỏ qua dòng rỗng)
      const lines = joined.split('\n').filter(line => line.trim() !== '');
      const lineCount = lines.length;

      doc.moveDown(lineCount + 1)

      // ===== TABLE HEADER =====
      const tableY = doc.y
      const qtyColX = leftMargin
      const descColX = leftMargin + 50

      // Header background
      doc.rect(leftMargin, tableY, pageWidth, 20)
        .fillAndStroke('#396290', '#396290')

      // Header text
      doc.fillColor('white').font(loadFont('calibri-bold')).fontSize(11)
      doc.text('Qty', qtyColX + 10, tableY + 5, { width: 40, align: 'center' })
      doc.text('Description', descColX + 5, tableY + 5, { width: pageWidth - 60 })

      doc.fillColor('black')
      // doc.moveDown(0.5)

      // ===== TABLE ROWS =====
      inputData.items.forEach((item) => {
        const rowStartY = doc.y

        // Calculate description height
        let descText = ''
        // if (item.name) descText += item.name + ' '
        if (item.sku) descText += item.sku
        if (item.SN && item.SN.join(', ') !== "") {
          descText += `\nSN: ${item.SN.join(', ')}`
        }

        // Measure text height
        const textHeight = doc.heightOfString(descText.trim(), {
          width: pageWidth - 60,
          lineBreak: true
        })

        const rowHeight = Math.max(25, textHeight + 10)

        // Draw cell borders
        doc.strokeColor('#396290').lineWidth(0.5)

        // Qty cell
        doc.rect(qtyColX, rowStartY, 50, rowHeight).stroke()
        doc.fontSize(11).font(loadFont('calibri-regular'))
          .text(item.qty.toString(), qtyColX, rowStartY + 8, { width: 50, align: 'center' })

        // Description cell
        doc.rect(descColX, rowStartY, pageWidth - 50, rowHeight).stroke()

        doc.text(descText.trim(), descColX + 5, rowStartY + 5, {
          width: pageWidth - 60,
          lineBreak: true
        })

        doc.y = rowStartY + rowHeight
      })

      // ===== FOOTER =====
      doc.moveDown(1)
      doc.fontSize(10).font(loadFont('calibri-bold'))
        .text('Thank you for your purchase.', leftMargin, doc.y, { width: pageWidth })

      doc.end()
      return stream
    }

    const pdfStream = generatePackingSlip(data)

    await new Promise(resolve => pdfStream.on('finish', resolve))
    const buffer = pdfStream.getContents()

    const fileName = `${data.po || 'PackingSlip'}_PackingSlip.pdf`
    const filePath = `/tmp/${fileName}`
    fs.writeFileSync(filePath, buffer)

    response.header('Content-Type', 'application/pdf')
    response.header('Content-Disposition', `attachment; filename="${fileName}"`)
    return response.download(filePath)

  } catch (err) {
    console.error(err)
    return response.status(500).json({
      status: 'error',
      message: err.message,
    })
  }
})