










(function () {
  'use strict';

  function TargetsUI(rootEl, opts) {
    opts = opts || {};
    this.root = rootEl;
    this.scene = opts.vizScene;
    this.desc = opts.robotDesc;
    this.getDragEnabled = opts.getDragEnabled || function () { return false; };
    
    
    
    this.getSkipContinuity = opts.getSkipContinuity || function () { return false; };
    this.getAxesVisible = opts.getAxesVisible || function () { return true; };
    this.getLabelsVisible = opts.getLabelsVisible || function () { return true; };
    
    
    this.getToolOffset = opts.getToolOffset || function () { return 0; };
    this.items = [];              
    this.onGoto = opts.onGoto || function () {};
    
    
    this.onSolution = opts.onSolution || function () {};
    this.selected = null;         
    
    
    this.multi = [];
    this._anchor = null;          
    
    
    this._seq = 0;
    this.onMenu = opts.onMenu || function () {};            
    this.onRemoved = opts.onRemoved || function () {};      
    
    this.getRefs = opts.getRefs ||
      function () { return { segs: 0, motions: [], doomed: [] }; };
    
    this.confirmDelete = opts.confirmDelete || function (item, refs, ok) { ok(); };
    this.onAdd = opts.onAdd || function () {};              
    this.onToggleFold = opts.onToggleFold || function () {};  
    
    
    this.onToggleEye = opts.onToggleEye || function () {};
    
    
    this.onToggleUseTcp = opts.onToggleUseTcp || function () {};
    this._tcpShow = false;        
    this._tcpOn = false;
    this._build();
  }

  TargetsUI.prototype._build = function () {
    var self = this;
    
    
    this.section = PanelSection.make({
      key: 'targets', i18nKey: 'viz_targets_title', title: '目标点',
      listId: 'tgt-list',
      


      hint: {
        i18nTitleKey: 'viz_targets_hint_keys',
        title: 'Shift + 点目标点：从上次点的那条连选到这条\n' +
               'Ctrl + 点目标点：逐个多选（用于右键「创建运动」）\n' +
               '按住 Alt：临时拖拽末端，松开退出'
      },
      buttons: [{
        



        id: 'tgt-eye', text: '👁',
        i18nTitleKey: 'viz_targets_eye', title: '显示/隐藏所有目标点（坐标系与名称）',
        onClick: function () { self.onToggleEye(); }
      }, {
        id: 'tgt-add', text: '+',
        i18nTitleKey: 'viz_add_target', title: '新增目标点',
        
        onClick: function (e) { self.onAdd(e.clientX, e.clientY); }
      }],
      onToggle: this.onToggleFold
    });
    var sec = this.section.sec;
    this.eyeEl = sec.querySelector('#tgt-eye');
    this.paintEye();
    this._buildTcpRow();
    
    sec.addEventListener('contextmenu', function (e) {
      e.preventDefault();
      e.stopPropagation();
      self.onMenu(e.clientX, e.clientY);
    });
    this.root.appendChild(sec);
    this.listEl = this.section.listEl;
    this._render();
  };

  



  TargetsUI.prototype._buildTcpRow = function () {
    var self = this;
    var wrap = document.createElement('label');
    wrap.id = 'tgt-use-tcp';
    wrap.style.cssText = 'display:none; align-items:center; gap:6px; cursor:pointer;' +
      ' font-size:11px; color:#8f979e; margin:0 0 8px; user-select:none;';
    var box = document.createElement('input');
    box.type = 'checkbox';
    box.style.cssText = 'flex:0 0 auto; margin:0; cursor:pointer;';
    var txt = document.createElement('span');
    txt.setAttribute('data-i18n', 'viz_target_use_tcp');
    wrap.setAttribute('data-i18n-title', 'viz_target_use_tcp_tip');
    wrap.appendChild(box);
    wrap.appendChild(txt);
    
    wrap.addEventListener('click', function (e) { e.stopPropagation(); });
    box.addEventListener('change', function () { self.onToggleUseTcp(box.checked); });
    this.tcpRowEl = wrap;
    this.tcpBoxEl = box;
    this.tcpTxtEl = txt;
    this.section.extraEl.appendChild(wrap);
    this._paintTcpRow();
  };

  


  TargetsUI.prototype.paintTcpRow = function (toolMounted, checked) {
    this._tcpShow = !!toolMounted;
    this._tcpOn = !!checked;
    this._paintTcpRow();
  };

  TargetsUI.prototype._paintTcpRow = function () {
    if (!this.tcpRowEl) return;
    
    
    var show = this._tcpShow && this.items.length > 0;
    this.tcpRowEl.style.display = show ? 'flex' : 'none';
    this.tcpBoxEl.checked = this._tcpOn;
    this.tcpTxtEl.textContent = VizI18n.tr('viz_target_use_tcp', '目标点按工具尖端定位');
    this.tcpRowEl.title = VizI18n.tr('viz_target_use_tcp_tip',
      '勾上：目标点的坐标系画在夹爪/吸盘的尖端。不勾：画在手腕法兰面上（装工具之前就是这样）。');
  };

  TargetsUI.prototype.record = function (jointsDeg, tcp) {
    this.selected = null;         
    this.multi = [];
    this._anchor = null;
    this._seq++;
    
    return this._add({
      name: 'target' + this._seq,
      joints_deg: jointsDeg.slice(),
      tcp: tcp || null
    });
  };

  

  TargetsUI.prototype._add = function (item) {
    var self = this;
    item.gizmo = null;
    item.rowLabelEl = null;
    this.items.push(item);
    this._render();

    var place = function (resolvedTcp) {
      if (resolvedTcp) item.tcp = resolvedTcp;
      var g = new Gizmo(self.scene, self.desc, {
        getSeed: function () { return item.joints_deg.slice(); },
        onSolution: function (payload, fromDrag) {
          self._onTargetSolution(item, payload, fromDrag);
        },
        
        handlesFollowAxes: true
      });
      g.setLabelVisible(self.getLabelsVisible());   
      g.setLabel(item.name);                 
      g.setOriginSphere(true);               
      g.setAxesVisible(self.getAxesVisible());
      g.setToolOffset(self.getToolOffset());   
      if (item.tcp) g.syncToTcp(item.tcp);
      g.setEnabled(self.getDragEnabled());   
      g.skipContinuity = self.getSkipContinuity();   
      item.gizmo = g;
    };

    if (item.tcp) {
      place(null);
    } else if (window.VizChannel && VizChannel.bridge) {
      
      
      
      var reqId = VizChannel.request(function (p) { place(p.ok ? p.tcp : null); });
      VizChannel.bridge.compute_fk(JSON.stringify(
        { req_id: reqId, joints_deg: item.joints_deg, keep: true }));
    } else {
      place(null);
    }
    return item;
  };

  






  TargetsUI.prototype._onTargetSolution = function (item, payload, fromDrag) {
    if (payload.ok) {
      item.joints_deg = payload.joints_deg.slice();
      item.tcp = payload.tcp;
      if (item.rowLabelEl) item.rowLabelEl.innerHTML = this._labelHtml(item);
    }
    this.onSolution(item, payload, fromDrag);
  };

  TargetsUI.prototype._labelHtml = function (item) {
    var j = item.joints_deg.map(function (v) { return v.toFixed(0); }).join(', ');
    return '<b>' + item.name + '</b> <span style="color:#8f979e;">[' + j + ']</span>';
  };

  TargetsUI.prototype._remove = function (idx) {
    var item = this.items[idx];
    if (item === this.selected) this.selected = null;
    if (item === this._anchor) this._anchor = null;   
    var at = this.multi.indexOf(item);
    if (at !== -1) this.multi.splice(at, 1);
    if (item.gizmo) item.gizmo.destroy();
    this.items.splice(idx, 1);
    this._render();
    this.onRemoved(item);        
  };

  

  TargetsUI.prototype.applyPoseToSelected = function (jointsDeg, tcp) {
    var item = this.selected;
    if (!item) return false;
    item.joints_deg = jointsDeg.slice();
    item.tcp = tcp;
    if (item.gizmo) item.gizmo.syncToTcp(tcp);
    if (item.rowLabelEl) item.rowLabelEl.innerHTML = this._labelHtml(item);
    return true;
  };

  

  TargetsUI.prototype.clearSelection = function () {
    if (!this.selected && this.multi.length === 0) return;
    this.selected = null;
    this.multi = [];
    this._anchor = null;
    this._updateSelectionHighlight();
  };

  TargetsUI.prototype._updateSelectionHighlight = function () {
    var self = this;
    this.items.forEach(function (item) {
      if (!item.rowEl) return;
      var order = self.multi.indexOf(item);          
      var on = (order !== -1) || (item === self.selected);
      item.rowEl.style.borderColor = on ? '#4da3ff' : '#3a4148';
      
      
      if (item.orderEl) {
        var show = order !== -1 && self.multi.length > 1;
        item.orderEl.style.display = show ? 'inline-block' : 'none';
        item.orderEl.textContent = show ? (order + 1) : '';
      }
    });
  };

  
  TargetsUI.prototype.getMultiSelection = function () {
    return this.multi.slice();
  };

  

  
  TargetsUI.prototype.serialize = function () {
    return this.items.map(function (it) {
      return {
        name: it.name,
        joints_deg: it.joints_deg.slice(),
        tcp: it.tcp ? {
          xyz_mm: it.tcp.xyz_mm.slice(),
          euler_xyz_deg: it.tcp.euler_xyz_deg.slice()
        } : null
      };
    });
  };

  TargetsUI.prototype.clearAll = function () {
    this.items.forEach(function (it) { if (it.gizmo) it.gizmo.destroy(); });
    this.items = [];
    this.selected = null;
    this.multi = [];
    this._anchor = null;
    this._render();
  };

  
  TargetsUI.prototype.restore = function (list) {
    this.clearAll();
    var self = this;
    (list || []).forEach(function (t) {
      self._add({
        name: t.name,
        joints_deg: t.joints_deg.slice(),
        tcp: t.tcp || null
      });
    });
    
    this._seq = this.items.reduce(function (mx, it) {
      var m = /(\d+)$/.exec(it.name);
      return m ? Math.max(mx, parseInt(m[1], 10)) : mx;
    }, this.items.length);
    return this.items;
  };

  
  TargetsUI.prototype.setDragEnabled = function (on) {
    this.items.forEach(function (item) { if (item.gizmo) item.gizmo.setEnabled(on); });
  };

  




  TargetsUI.prototype.paintEye = function (on) {
    if (!this.eyeEl) return;
    this.eyeEl.textContent = on === false ? '🚫' : '👁';
    this.eyeEl.style.opacity = on === false ? '.55' : '';
  };

  


  TargetsUI.prototype.setSkipContinuity = function (on) {
    this.items.forEach(function (item) { if (item.gizmo) item.gizmo.skipContinuity = on; });
  };

  




  TargetsUI.prototype.setToolOffset = function (m) {
    this.items.forEach(function (item) {
      if (!item.gizmo) return;
      item.gizmo.setToolOffset(m);
      if (item.tcp) item.gizmo.syncToTcp(item.tcp);
    });
  };

  



  TargetsUI.prototype.selectForEdit = function (item) {
    if (!item || this.selected === item) return;
    this.selected = item;
    this._updateSelectionHighlight();
  };

  
  TargetsUI.prototype.setAxesVisible = function (on) {
    this.items.forEach(function (item) { if (item.gizmo) item.gizmo.setAxesVisible(on); });
  };

  
  TargetsUI.prototype.setLabelsVisible = function (on) {
    this.items.forEach(function (item) { if (item.gizmo) item.gizmo.setLabelVisible(on); });
  };

  

  TargetsUI.prototype.updateLabels = function () {
    this.items.forEach(function (item) { if (item.gizmo) item.gizmo.updateLabel(); });
  };

  

  TargetsUI.prototype.refresh = function () { this._render(); };

  TargetsUI.prototype._render = function () {
    var self = this;
    
    
    this._paintTcpRow();
    
    
    
    this.section.setCount(this.items.length);
    this.section.setHintVisible(this.items.length > 0);
    this.listEl.innerHTML = '';
    if (this.items.length === 0) {
      var empty = document.createElement('div');
      empty.style.cssText = 'color:#8f979e; font-size:11px; padding:4px 0;';
      empty.textContent = VizI18n.tr('viz_targets_empty', '（暂无目标点）');
      this.listEl.appendChild(empty);
      return;
    }
    this.items.forEach(function (item, idx) {
      self.listEl.appendChild(self._renderItem(item, idx));
    });
    this._updateSelectionHighlight();   
    this.paintRefs();
  };

  


  TargetsUI.prototype.paintRefs = function () {
    var self = this;
    this.items.forEach(function (item) {
      var el = item.refsEl;
      if (!el) return;
      var r = self.getRefs(item);
      if (!r || !r.segs) { el.style.display = 'none'; el.textContent = ''; return; }
      el.style.display = '';
      el.textContent = '×' + r.segs;
      el.title = VizI18n.tr('viz_target_refs_tip', '被 {names} 引用（{n} 段）')
        .replace('{names}', r.motions.join('、')).replace('{n}', r.segs);
    });
  };

  TargetsUI.prototype._renderItem = function (item, idx) {
    var self = this;
    var el = document.createElement('div');
    el.style.cssText = 'display:flex; align-items:center; justify-content:space-between; ' +
      'gap:6px; padding:4px 6px; margin:3px 0; border:1px solid #3a4148; border-radius:4px; ' +
      
      
      'font-size:11px; cursor:pointer;';
    el.style.borderColor = (item === this.selected) ? '#4da3ff' : '#3a4148';   
    item.rowEl = el;
    el.addEventListener('mouseenter', function () { el.style.background = '#2d5f8b'; });
    el.addEventListener('mouseleave', function () { el.style.background = ''; });

    
    var order = document.createElement('span');
    order.style.cssText = 'display:none; flex:0 0 auto; min-width:14px; height:14px; ' +
      'line-height:14px; text-align:center; border-radius:7px; background:#4da3ff; ' +
      'color:#fff; font-size:10px; padding:0 3px;';
    item.orderEl = order;
    el.appendChild(order);

    var label = document.createElement('span');
    label.style.cssText = 'flex:1 1 auto; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;';
    label.innerHTML = this._labelHtml(item);
    item.rowLabelEl = label;
    el.appendChild(label);

    




    var refs = document.createElement('span');
    refs.style.cssText = 'display:none; flex:0 0 auto; color:#8f979e; font-size:10px; ' +
      'white-space:nowrap;';
    item.refsEl = refs;
    el.appendChild(refs);

    var del = document.createElement('button');
    del.textContent = '×';
    del.title = VizI18n.tr('viz_delete', '删除');
    del.style.cssText = 'flex:0 0 auto; padding:0 6px; line-height:1.4;';
    del.addEventListener('click', function (e) {
      e.stopPropagation();
      
      self.confirmDelete(item, self.getRefs(item), function () {
        var at = self.items.indexOf(item);
        if (at !== -1) self._remove(at);
      });
    });
    el.appendChild(del);

    





    el.addEventListener('click', function (e) {
      if (e.ctrlKey || e.metaKey) {
        var at = self.multi.indexOf(item);
        if (at === -1) self.multi.push(item);
        else self.multi.splice(at, 1);
        self._anchor = item;                
        self._updateSelectionHighlight();
        return;
      }
      if (e.shiftKey) {
        
        var a = self.items.indexOf(self._anchor);
        if (a === -1) a = idx;
        
        
        
        var step = (idx >= a) ? 1 : -1;
        self.multi = [];
        for (var i = a; ; i += step) {
          self.multi.push(self.items[i]);
          if (i === idx) break;
        }
        self._updateSelectionHighlight();
        return;
      }
      self.selected = item;                 
      self.multi = [item];                  
      self._anchor = item;
      self._updateSelectionHighlight();
      self.onGoto(idx, item);
    });
    
    el.addEventListener('contextmenu', function (e) {
      e.preventDefault();
      e.stopPropagation();
      
      if (self.multi.indexOf(item) === -1) {
        self.multi = [item];
        self.selected = item;
        self._anchor = item;
        self._updateSelectionHighlight();
      }
      self.onMenu(e.clientX, e.clientY);
    });
    return el;
  };

  window.TargetsUI = TargetsUI;
})();
