// bridge.jsx —— AI绘匠 CEP 面板的 ExtendScript 桥（兼容 PS CC2015.5 ~ 2021）
// 面板通过 evalScript 调用这里的函数；所有返回都是字符串（ERR: 前缀表示失败）

/* ExtendScript 不保证提供原生 JSON；桥接返回值自行序列化。 */
function hjJsonQuote(value) {
  return '"' + String(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"')
    .replace(/\r/g, "\\r").replace(/\n/g, "\\n") + '"';
}

function hjJsonNumberArray(values) {
  var out = [];
  for (var i = 0; i < values.length; i++) out.push(Number(values[i]));
  return "[" + out.join(",") + "]";
}

function hjVersionInfo() {
  try {
    return '{"version":' + hjJsonQuote(app.version) + ',"docs":' + app.documents.length + '}';
  } catch (e) {
    return "ERR:" + e.toString();
  }
}

/* 当前选区 bounds（px），无选区返回 ERR:none */
function hjSelectionBounds() {
  try {
    var sb = app.activeDocument.selection.bounds;
    return hjJsonNumberArray([sb[0].as("px"), sb[1].as("px"), sb[2].as("px"), sb[3].as("px")]);
  } catch (e) {
    return "ERR:none";
  }
}

/* 抓取图像：mode = layer | selection | document
   实现：复制文档 → 只保留目标图层可见 → 裁剪 → 另存 PNG 到临时目录 → 关闭副本 */
function hjCapture(mode) {
  var dup = null;
  try {
    if (app.documents.length === 0) return "ERR:请先打开一个文档";
    var doc = app.activeDocument;
    if (doc.activeLayer == null) return "ERR:请选中一个图层";

    var selBounds = null;
    if (mode == "selection") {
      try {
        var sb = doc.selection.bounds;
        selBounds = [sb[0].as("px"), sb[1].as("px"), sb[2].as("px"), sb[3].as("px")];
      } catch (e) { selBounds = null; }
    }

    dup = doc.duplicate("hj_capture_tmp", false);
    app.activeDocument = dup;
    var target = dup.activeLayer;

    // 隐藏所有顶层非祖先图层（目标图层的父级组保持可见）
    hjHideOthers(dup, target);

    if (selBounds) {
      dup.crop(selBounds);
    } else if (mode == "layer") {
      try { dup.trim(TrimType.TRANSPARENT); } catch (e) {}
    }

    // PNG 输出统一转为 RGB 8 位，兼容 CMYK / 16 位原稿。
    try { if (dup.mode != DocumentMode.RGB) dup.changeMode(ChangeMode.RGB); } catch (e) {}
    try { dup.bitsPerChannel = BitsPerChannelType.EIGHT; } catch (e) {}
    var outW = dup.width.as("px"), outH = dup.height.as("px");
    var f = new File(Folder.temp.fsName + "/hj_" + new Date().getTime() + ".png");
    var opts = new PNGSaveOptions();
    dup.saveAs(f, opts, true, Extension.LOWERCASE);
    dup.close(SaveOptions.DONOTSAVECHANGES);
    dup = null;
    return '{"path":' + hjJsonQuote(f.fsName) + ',"bounds":' +
      (selBounds ? hjJsonNumberArray(selBounds) : "null") + ',"width":' + Number(outW) +
      ',"height":' + Number(outH) + '}';
  } catch (e) {
    if (dup) { try { dup.close(SaveOptions.DONOTSAVECHANGES); } catch (e2) {} }
    return "ERR:" + e.toString();
  }
}

function hjIsAncestor(maybe, layer) {
  var p = layer.parent;
  while (p && p.typename == "LayerSet") {
    if (p == maybe) return true;
    p = p.parent;
  }
  return false;
}

function hjHideOthers(doc, target) {
  for (var i = 0; i < doc.layers.length; i++) {
    var L = doc.layers[i];
    if (L == target || hjIsAncestor(L, target)) continue;
    try { L.visible = false; } catch (e) {}
  }
}

/* 插入生成图：无文档时直接打开为新文档；有文档时 place 为新图层。
   boundsJson（可选）= {"left":l,"top":t,"right":r,"bottom":b}（px）
   —— 等比铺满 bounds、居中并创建选区蒙版（选区外不可见） */
function hjInsert(path, boundsJson) {
  try {
    var f = new File(path);
    if (!f.exists) return "ERR:文件不存在";
    if (app.documents.length === 0) {
      var d = app.open(f);
      if (d) return "OK:opened";
      return "ERR:打开图片失败";
    }
    var placeDesc = new ActionDescriptor();
    placeDesc.putPath(charIDToTypeID("null"), f);
    placeDesc.putEnumerated(charIDToTypeID("FTcs"), charIDToTypeID("QCSt"), charIDToTypeID("Qcsa"));
    executeAction(charIDToTypeID("Plc "), placeDesc, DialogModes.NO);

    if (boundsJson) {
      try {
        var b = eval("(" + boundsJson + ")");
        var tw = b.right - b.left, th = b.bottom - b.top;
        var L = app.activeDocument.activeLayer;
        var lb = L.bounds;
        var w = lb[2].as("px") - lb[0].as("px");
        var h = lb[3].as("px") - lb[1].as("px");
        if (w > 0 && h > 0 && tw > 0 && th > 0) {
          var scale = Math.max(tw / w, th / h) * 100;
          L.resize(scale, scale, AnchorPosition.MIDDLECENTER);
          lb = L.bounds;
          w = lb[2].as("px") - lb[0].as("px");
          h = lb[3].as("px") - lb[1].as("px");
          var cx = (lb[0].as("px") + lb[2].as("px")) / 2;
          var cy = (lb[1].as("px") + lb[3].as("px")) / 2;
          var dx = (b.left + b.right) / 2 - cx;
          var dy = (b.top + b.bottom) / 2 - cy;
          if (Math.abs(dx) > 0.5 || Math.abs(dy) > 0.5) L.translate(dx, dy);
          hjMaskToBounds(b);
        }
      } catch (e) { return "ERR:贴回选区失败：" + e.toString(); }
    }
    return "OK";
  } catch (e) {
    return "ERR:" + e.toString();
  }
}

function hjMaskToBounds(b) {
  var doc = app.activeDocument;
  doc.selection.select([[b.left,b.top],[b.right,b.top],[b.right,b.bottom],[b.left,b.bottom]]);
  var d = new ActionDescriptor();
  d.putClass(charIDToTypeID("Nw  "), charIDToTypeID("Chnl"));
  var r = new ActionReference();
  r.putEnumerated(charIDToTypeID("Chnl"), charIDToTypeID("Chnl"), charIDToTypeID("Msk "));
  d.putReference(charIDToTypeID("At  "), r);
  d.putEnumerated(charIDToTypeID("Usng"), charIDToTypeID("UsrM"), charIDToTypeID("RvlS"));
  executeAction(charIDToTypeID("Mk  "), d, DialogModes.NO);
}
