// ══════════════════════════════════════════════════════════════
// BOM Sheet Lock — Auto-Protection for Google Sheets
// By InterPetr — interpetr.com
// ══════════════════════════════════════════════════════════════
//
// Protects your BOM and Parts Master sheets from accidental edits.
// Toggle ON/OFF from the menu. When ON, sheets re-lock automatically
// after every change. Owner always retains access.
//
// SETUP:
//   1. Open Apps Script (Extensions > Apps Script)
//   2. Paste this code and save
//   3. Run "installTrigger" once from the function dropdown
//   4. Reload the spreadsheet — Sheet Lock menu appears
//
// CUSTOMIZE:
//   - Add editor emails to CONFIG.allowedEditors
//   - Add/remove sheet names in CONFIG.sheetsToLock
//   - Add sheet names to CONFIG.sheetsToSkip to exclude them
//
// ══════════════════════════════════════════════════════════════

var CONFIG = {
  allowedEditors: [
    // "engineer@company.com",
    // "shop@company.com",
  ],

  sheetsToLock: [
    "BOM Structure",
    "Parts Master",
    // Add any other sheets you want protected
  ],

  sheetsToSkip: [
    "Instructions",
    // Add sheets that should never be locked
  ],

  protectionLabel: "InterPetr-SheetLock",
};

// ── Menu ──
function onOpen() {
  var ui = SpreadsheetApp.getUi();
  var on = isAutoLockOn_();
  ui.createMenu("Sheet Lock")
    .addItem(on ? "Turn OFF" : "Turn ON", "toggleLock")
    .addSeparator()
    .addItem("Lock Now", "turnOn")
    .addItem("Unlock Now", "turnOff")
    .addSeparator()
    .addItem("Status", "showStatus")
    .addItem("Show Editors", "showEditors")
    .addToUi();
}

// ── State helpers ──
function isAutoLockOn_() {
  var val = PropertiesService.getDocumentProperties().getProperty("sheetLockEnabled");
  return val === "true";
}

function setAutoLock_(enabled) {
  PropertiesService.getDocumentProperties().setProperty("sheetLockEnabled", String(enabled));
}

// ── Install onChange trigger (run once from script editor) ──
function installTrigger() {
  var triggers = ScriptApp.getProjectTriggers();
  for (var i = 0; i < triggers.length; i++) {
    if (triggers[i].getEventType() === ScriptApp.EventType.ON_CHANGE) {
      ScriptApp.deleteTrigger(triggers[i]);
    }
  }

  ScriptApp.newTrigger("onSheetChange")
    .forSpreadsheet(SpreadsheetApp.getActive())
    .onChange()
    .create();

  SpreadsheetApp.getActive().toast(
    "Trigger installed. Use the Sheet Lock menu to turn ON/OFF.",
    "Setup Complete",
    5
  );
}

// ── Toggle / on / off ──
function toggleLock() {
  if (isAutoLockOn_()) {
    turnOff();
  } else {
    turnOn();
  }
}

function turnOn() {
  setAutoLock_(true);
  applyProtections_();
  SpreadsheetApp.getActive().toast(
    "Sheets are protected. Future changes will re-lock automatically.",
    "LOCKED",
    4
  );
}

function turnOff() {
  setAutoLock_(false);
  removeProtections_();
  SpreadsheetApp.getActive().toast(
    "Sheets are editable. Changes will NOT re-lock until you turn it back on.",
    "UNLOCKED",
    4
  );
}

// ── Auto re-lock on change ──
function onSheetChange(e) {
  if (!isAutoLockOn_()) return;
  try {
    applyProtections_();
  } catch (err) {
    Logger.log("Sheet Lock error: " + err.message);
  }
}

// ── Protection logic ──
function applyProtections_() {
  var ss = SpreadsheetApp.getActive();
  var sheets = getSheetsToLock_(ss);
  var allowed = getEditorEmails_();

  for (var i = 0; i < sheets.length; i++) {
    var sheet = sheets[i];

    var existing = sheet.getProtections(SpreadsheetApp.ProtectionType.SHEET);
    for (var j = 0; j < existing.length; j++) {
      if (existing[j].getDescription() === CONFIG.protectionLabel) {
        existing[j].remove();
      }
    }

    var protection = sheet.protect().setDescription(CONFIG.protectionLabel);
    protection.removeEditors(protection.getEditors());
    if (allowed.length > 0) {
      protection.addEditors(allowed);
    }
    protection.setDomainEdit(false);
  }
}

function removeProtections_() {
  var ss = SpreadsheetApp.getActive();
  var sheets = ss.getSheets();
  for (var i = 0; i < sheets.length; i++) {
    var protections = sheets[i].getProtections(SpreadsheetApp.ProtectionType.SHEET);
    for (var j = 0; j < protections.length; j++) {
      if (protections[j].getDescription() === CONFIG.protectionLabel) {
        protections[j].remove();
      }
    }
  }
}

// ── Status / info ──
function showStatus() {
  var ss = SpreadsheetApp.getActive();
  var sheets = ss.getSheets();
  var on = isAutoLockOn_();
  var lines = ["Auto-Lock: " + (on ? "ON" : "OFF"), ""];

  for (var i = 0; i < sheets.length; i++) {
    var name = sheets[i].getName();
    var protections = sheets[i].getProtections(SpreadsheetApp.ProtectionType.SHEET);
    var isLocked = false;
    for (var j = 0; j < protections.length; j++) {
      if (protections[j].getDescription() === CONFIG.protectionLabel) {
        isLocked = true;
        break;
      }
    }

    var skipped = CONFIG.sheetsToSkip.indexOf(name) !== -1;
    if (isLocked) {
      lines.push("LOCKED: " + name);
    } else if (skipped) {
      lines.push("UNLOCKED: " + name + " (excluded)");
    } else {
      lines.push("UNLOCKED: " + name);
    }
  }

  SpreadsheetApp.getUi().alert("Sheet Lock Status", lines.join("\n"), SpreadsheetApp.getUi().ButtonSet.OK);
}

function showEditors() {
  var allowed = getEditorEmails_();
  var lines = ["Allowed editors when locked:", ""];
  for (var k = 0; k < allowed.length; k++) {
    lines.push("  - " + allowed[k]);
  }
  lines.push("");
  lines.push("Owner is always included automatically.");
  lines.push("Edit CONFIG.allowedEditors in Apps Script to change.");

  SpreadsheetApp.getUi().alert("Allowed Editors", lines.join("\n"), SpreadsheetApp.getUi().ButtonSet.OK);
}

// ── Helpers ──
function getSheetsToLock_(ss) {
  var all = ss.getSheets();

  if (CONFIG.sheetsToLock.length > 0) {
    var result = [];
    for (var i = 0; i < CONFIG.sheetsToLock.length; i++) {
      var sheet = ss.getSheetByName(CONFIG.sheetsToLock[i]);
      if (sheet) result.push(sheet);
      else Logger.log("Sheet Lock: sheet '" + CONFIG.sheetsToLock[i] + "' not found.");
    }
    return result;
  }

  if (CONFIG.sheetsToSkip.length > 0) {
    var filtered = [];
    for (var i = 0; i < all.length; i++) {
      if (CONFIG.sheetsToSkip.indexOf(all[i].getName()) === -1) {
        filtered.push(all[i]);
      }
    }
    return filtered;
  }

  return all;
}

function getEditorEmails_() {
  var owner = SpreadsheetApp.getActive().getOwner();
  var emails = [];
  if (owner) emails.push(owner.getEmail());

  for (var i = 0; i < CONFIG.allowedEditors.length; i++) {
    var email = CONFIG.allowedEditors[i].trim().toLowerCase();
    if (email && emails.indexOf(email) === -1) {
      emails.push(email);
    }
  }
  return emails;
}
