
import fs from "fs";
import path from "path";
import axios from "axios";
import qs from "qs";
import dotenv from "dotenv";
import PocketBase from "pocketbase";
import XLSX from "xlsx";

dotenv.config();

// -----------------------------
// CONFIG
// -----------------------------
const CONFIG = JSON.parse(fs.readFileSync("config.json", "utf8"));
const tenantId = CONFIG.tenantId;
const clientId = CONFIG.clientId;
const pbUrl = CONFIG.pbUrl;
const pbCollection = CONFIG.pbCollection;
const pbEmail = CONFIG.pbEmail;
const clientSecret = process.env.CLIENT_SECRET;
const pbPassword = process.env.PB_PASSWORD;

// -----------------------------
// EXCEL HEADER AND DATA ROW PARAMETERS
// -----------------------------
// Zero-based: headers on row 2 (index 1), data starts on row 3 (index 2)
const HEADER_ROW_INDEX = 1;
const DATA_START_ROW_INDEX = 2;

// -----------------------------
// LOGGING
// -----------------------------
function log(message) {
  console.log(message);
  const logfile = path.resolve(process.cwd(), "excelsync.log");
  try {
    fs.appendFileSync(logfile, message + "\n", "utf8");
  } catch (e) {
    console.error("Log write failed:", e?.message || e);
  }
}

// -----------------------------
// DATE CONVERSION HELPER
// -----------------------------
function convertExcelDateToUTC(value) {
  if (typeof value === "number") {
    // Excel serial date
    const dateObj = XLSX.SSF.parse_date_code(value);
    if (!dateObj) return null;
    const jsDate = new Date(Date.UTC(dateObj.y, dateObj.m - 1, dateObj.d, dateObj.H, dateObj.M, dateObj.S));
    return jsDate.toISOString(); // UTC ISO format
  } else if (typeof value === "string") {
    // Try parsing string date
    const jsDate = new Date(value);
    return isNaN(jsDate.getTime()) ? value : jsDate.toISOString();
  }
  return value; // Return as-is if not a date
}

// -----------------------------
// POCKETBASE TOKEN ACQUISITION
// -----------------------------
async function getPocketBaseClient() {
  const pb = new PocketBase(pbUrl);
  await pb.collection("users").authWithPassword(pbEmail, pbPassword);
  log("✅ PocketBase token acquired");
  return pb;
}

// -----------------------------
// GRAPH TOKEN ACQUISITION
// -----------------------------
async function getGraphToken() {
  const tokenUrl = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
  const body = qs.stringify({
    client_id: clientId,
    client_secret: clientSecret,
    scope: "https://graph.microsoft.com/.default",
    grant_type: "client_credentials",
  });
  const res = await axios.post(tokenUrl, body, {
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
  });
  log("✅ Graph token acquired");
  return res.data.access_token;
}

// -----------------------------
// GRAPH EXCEL DOWNLOAD HELPER
// -----------------------------
async function downloadExcelFromGraph(graphToken, driveId, itemId) {
  const url = `https://graph.microsoft.com/v1.0/drives/${driveId}/items/${itemId}/content`;
  const res = await axios.get(url, {
    headers: { Authorization: `Bearer ${graphToken}` },
    responseType: "arraybuffer",
  });
  return Buffer.from(res.data);
}

// -----------------------------
// MAIN SYNC LOGIC
// -----------------------------
(async () => {
  try {
    const graphToken = await getGraphToken();
    const pb = await getPocketBaseClient();

    // These IDs point to your Excel file in OneDrive/SharePoint
    const driveId = "b!9YOqqr2xM0G2DFBwMEJYY4UzQgocFddEtpLYWuS9_AtkCKl2q8yjQJteQ7Ti4QSx";
    const itemId = "01SPNXLDSQTMG4F6BDANCLJU2FZKEDQLVU";

    const excelBuffer = await downloadExcelFromGraph(graphToken, driveId, itemId);

    // Parse Excel
    const workbook = XLSX.read(excelBuffer, { type: "buffer" });
    const worksheet = workbook.Sheets["Job_List_Range"];
    const rows = XLSX.utils.sheet_to_json(worksheet, { header: 1 });

    const headers = rows[HEADER_ROW_INDEX]; // Row 2 (index 1)
    const dataRows = rows.slice(DATA_START_ROW_INDEX); // Row 3 onward

    log(`✅ Found ${dataRows.length} data rows`);

    for (const row of dataRows) {
      if (!row || row.length === 0) continue; // Skip empty rows

      const record = {};
      headers.forEach((header, i) => {
        let cellValue = row[i];
        // ✅ Convert all date fields to UTC ISO format
        if (header.toLowerCase().includes("date")) {
          cellValue = convertExcelDateToUTC(cellValue);
        }
        record[header] = cellValue;
      });

      const jobNumber = record["Job_Number"];
      if (!jobNumber) {
        log("⚠️ Skipped row with no Job_Number");
        continue;
      }

      try {
        // Check if record exists
        const existing = await pb.collection(pbCollection).getList(1, 1, {
          filter: `Job_Number="${jobNumber}"`,
        });

        if (existing.items.length > 0) {
          const id = existing.items[0].id;
          // Clear all fields except Job_Number
          const clearedData = { Job_Number: jobNumber };
          Object.assign(clearedData, record);
          await pb.collection(pbCollection).update(id, clearedData);
          log(`✅ Updated record for Job_Number: ${jobNumber}`);
        } else {
          await pb.collection(pbCollection).create(record);
          log(`✅ Created new record for Job_Number: ${jobNumber}`);
        }
      } catch (err) {
        log(`❌ Error processing Job_Number ${jobNumber}: ${err.message}`);
      }
    }

    log("✅ Sync complete");
  } catch (err) {
    log(`❌ Fatal error: ${err.message}`);
  }
})();
