// 简单航线生成器脚本
const fields = ['id','x','y','z','yaw','action','light','p1','p2'];
const ACTIONS = [
  '无动作，如果参数设定打开了协调转弯模式，在无人机不会在该航点精准停留',
  '在航点上悬停参数设定的一小段时间',
  '拍摄一次',
  '拍摄一次',
  '开始录像',
  '结束录像',
  '悬停一设定时间如3s，并录制该3s的视频一段',
  '执行停机坪降落，而不管参数finish_act设定',
  '执行原地降落，而不管参数finish_act设定',
  '设定一些任务相关参数',
  '从Mission任务模式切换如Hover悬停模式，任务暂停',
  '与action=0类似，不执行任何动作，但该航点上不运行执行协调转弯相关功能代码，即强制进行精准悬停。',
  '进入某种特殊飞行模式',
  '将雷达等设定的数据流录制到文件，默认录制需关闭',
  '结束录制。否则降落后自动结束。',
  '可选，若使用则必须为第一个航点的动作。检查当前无人机位置是否与航点position中xyz和yaw一致。超过参数表设定差值则报错，不执行任务。设定后，参数表内置的默认起飞位置检查不执行。',
  '局放检测仪',
  '如果因避障无法到达该航点，则跳转到航线内参数1指定航点并从该航点开始继续执行后续航线',
  '执行完该航点后，跳转到参数1指定航点并从该航点开始继续执行后续航线',
  '控制机械臂抓取的开合，参数1为0或1，分别代表抓取和放开，500-2500的pwm则直接设置机械臂到对应位置',
  '原地旋转yaw角度，正数顺时针旋转，p1为旋转角度（rad）'
];
// short labels to show in the select (keep full descriptions in ACTIONS for hover)
const ACTION_LABELS = [
  '无动作',
  '悬停',
  '拍照',
  '拍照(红外)',
  '开始录像',
  '结束录像',
  '悬停并录制',
  'Apron_Land',
  'Land',
  'set_param',
  'Hover',
  '精确悬停',
  'TunnelFly2',
  '开始雷达录制',
  '结束雷达录制',
  '起飞位置检查',
  '记录紫外数据',
  'Detour',
  '跳转Jump',
  'Grabber抓取',
  '旋转Yaw'
];

let waypoints = [];

function createDefaultWaypoint(){
  return {id:-1,x:0,y:0,z:0,yaw:0,action:0,light:0,p1:0,p2:0};
}

function renderList(){
  const container = document.getElementById('waypoint-list');
  container.innerHTML = '';
  waypoints.forEach((wp, idx) => {
    const row = document.createElement('div');
    row.className = 'wp-row';

    // index (read-only)
    const idxEl = document.createElement('div');
    idxEl.className = 'index-cell';
    idxEl.textContent = String(idx + 1);
    row.appendChild(idxEl);

    fields.forEach(f => {
      if(f === 'action'){
        const sel = document.createElement('select');
        sel.dataset.field = f;
        sel.dataset.idx = idx;
        ACTIONS.forEach((name, i) => {
          const opt = document.createElement('option');
          opt.value = String(i);
          const label = (typeof ACTION_LABELS[i] !== 'undefined') ? ACTION_LABELS[i] : name;
          opt.textContent = `${i}: ${label}`;
          sel.appendChild(opt);
        });
        // select current action (may be numeric)
        const actVal = Number.isFinite(wp.action) ? wp.action : 0;
        sel.value = String(actVal >=0 && actVal < ACTIONS.length ? actVal : 0);
        sel.addEventListener('change', onActionChange);
        sel.classList.add('action-select');
        row.appendChild(sel);
        // attach hover handlers to update the fixed action description box
        row.addEventListener('mouseenter', ()=> updateActionBox(wp.action));
        row.addEventListener('mouseleave', ()=> clearActionBox());
        return;
      }

      const inp = document.createElement('input');
      inp.value = wp[f] ?? '';
      inp.dataset.field = f;
      inp.dataset.idx = idx;
      inp.title = f;
      // numeric inputs: id, x/y/z/yaw (floats allowed), action, light, p1, p2
      if(['id','x','y','z','yaw','action','light','p1','p2'].includes(f)){
        inp.type = 'number';
        // allow floats for x,y,z,yaw,p1,p2
        if(['x','y','z','yaw','p1','p2'].includes(f)){
          inp.step = 'any';
        } else {
          inp.step = '1';
        }
        if(f === 'light'){
          inp.min = '0';
          inp.max = '100';
        }
      }
      if(f === 'p1' && wp.action === 20){
        inp.placeholder = '正数顺时针(rad)';
      }
      inp.addEventListener('input', onFieldInput);
      if(['light','id'].includes(f)) inp.classList.add('small');
      row.appendChild(inp);
    });

    const del = document.createElement('button');
    del.textContent = '删除';
    del.className = 'delete';
    del.addEventListener('click', ()=>{ removeWaypoint(idx); });
    row.appendChild(del);

    container.appendChild(row);
  });
}

function onFieldInput(e){
  const idx = Number(e.target.dataset.idx);
  const field = e.target.dataset.field;
  let val = e.target.value;
  if(['x','y','z','yaw','p1','p2'].includes(field)){
    val = val === '' ? 0 : Number(val);
    if(Number.isNaN(val)) val = 0;
  } else if(field === 'light'){
    // enforce integer 0-100
    if(val === '') val = 0;
    val = parseInt(val);
    if(Number.isNaN(val)) val = 0;
    val = Math.max(0, Math.min(100, val));
  } else if(field === 'action'){
    if(val === '') val = 0;
    val = parseInt(val);
    if(Number.isNaN(val)) val = 0;
  } else if(field === 'id'){
    if(val === '') val = -1;
    val = parseInt(val);
    if(Number.isNaN(val)) val = -1;
  }
  waypoints[idx][field] = val;
}

function onActionChange(e){
  const idx = Number(e.target.dataset.idx);
  const field = e.target.dataset.field;
  let val = parseInt(e.target.value);
  if(Number.isNaN(val) || val < 0 || val >= ACTIONS.length) val = 0;
  waypoints[idx][field] = val;
  updateActionBox(val);
  const p1Inp = e.target.parentElement.querySelector('input[data-field="p1"]');
  if(p1Inp){
    p1Inp.placeholder = (val === 20) ? '正数顺时针(rad)' : '';
  }
}

function updateActionBox(actionIndex){
  const box = document.getElementById('action-desc-box');
  if(!box) return;
  const i = Number(actionIndex);
  if(Number.isNaN(i) || i < 0 || i >= ACTIONS.length){
    box.textContent = '';
    return;
  }
  box.textContent = `${i}: ${ACTIONS[i]}`;
}

function clearActionBox(){
  const box = document.getElementById('action-desc-box');
  if(!box) return;
  box.textContent = '';
}

function addWaypoint(wp){
  waypoints.push(wp ?? createDefaultWaypoint());
  renderList();
}

function removeWaypoint(idx){
  waypoints.splice(idx,1);
  renderList();
}

function parseInput(text){
  text = text.trim();
  if(!text) return [];
  // try JSON
  try{
    const parsed = JSON.parse(text);
    // support either a plain array or an object with a `tasks` array
    if(Array.isArray(parsed)){
      return parsed.map(normalizeWaypoint);
    }
    if(parsed && typeof parsed === 'object' && Array.isArray(parsed.tasks)){
      return parsed.tasks.map(normalizeWaypoint);
    }
  }catch(e){/* not JSON */}

  // CSV or simple lines
  const lines = text.split(/\r?\n/).map(l=>l.trim()).filter(Boolean);
  if(lines.length===0) return [];

  // detect header
  const firstCols = lines[0].split(',').map(s=>s.trim().toLowerCase());
  let start = 0;
  let headerMap = null;
  if(firstCols.length>=8 && fields.every(f=>firstCols.includes(f))){
    headerMap = firstCols;
    start = 1;
  }

  const res = [];
  for(let i=start;i<lines.length;i++){
    const cols = lines[i].split(',').map(s=>s.trim());
    if(cols.length<8) continue;
    if(headerMap){
      const obj = {};
      headerMap.forEach((h, j)=>{ if(fields.includes(h)) obj[h]=cols[j]; });
      res.push(normalizeWaypoint(obj));
    } else {
      const obj = {};
      fields.forEach((f,j)=>{ obj[f]=cols[j]; });
      res.push(normalizeWaypoint(obj));
    }
  }
  return res;
}

function normalizeWaypoint(obj){
  const out = {};
  fields.forEach(f=>{
    if(f === 'id'){
      let v = obj[f]===undefined || obj[f]==='' ? -1 : parseInt(obj[f]);
      if(Number.isNaN(v)) v = -1;
      out[f] = v;
    } else if(['x','y','z','yaw','p1','p2'].includes(f)){
      out[f] = obj[f]===undefined || obj[f]==='' ? 0 : Number(obj[f]);
      if(Number.isNaN(out[f])) out[f] = 0;
    } else if(f === 'light'){
      let v = obj[f]===undefined || obj[f]==='' ? 0 : parseInt(obj[f]);
      if(Number.isNaN(v)) v = 0;
      out[f] = Math.max(0, Math.min(100, v));
    } else if(f === 'action'){
      // accept numeric action codes or action names
      if(obj[f]===undefined || obj[f]===''){
        out[f] = 0;
      } else if(typeof obj[f] === 'number' || /^\d+$/.test(String(obj[f]))){
        let v = parseInt(obj[f]);
        if(Number.isNaN(v)) v = 0;
        out[f] = (v >=0 && v < ACTIONS.length) ? v : 0;
      } else {
        // accept action names possibly prefixed with a numeric code like "1: 悬停"
        const raw = String(obj[f]);
        const name = raw.replace(/^\s*\d+\s*[:\-]?\s*/, '').toLowerCase();
        let idx = ACTIONS.findIndex(a=>a.toLowerCase() === name);
        if(idx < 0){
          idx = ACTION_LABELS.findIndex(a=>a.toLowerCase() === name);
        }
        out[f] = idx >= 0 ? idx : 0;
      }
    } else {
      out[f] = obj[f]===undefined ? '' : String(obj[f]);
    }
  });
  return out;
}

function importData(){
  const text = document.getElementById('input-area').value;
  const parsed = parseInput(text);
  if(parsed.length===0){
    alert('未识别到有效航点');
    return;
  }
  waypoints = parsed;
  renderList();
}

function exportJSON(){
  const payload = {
    post_task: 0,
    post_task_script_path: "",
    tasks: waypoints
  };
  const fmt = (document.getElementById('output-format') || {}).value || 'pretty';
  const out = fmt === 'compact' ? JSON.stringify(payload) : JSON.stringify(payload, null, 2);
  document.getElementById('output-area').value = out;
}

function refreshOutput(){
  const area = document.getElementById('output-area');
  if(!area) return;
  const current = area.value || '';
  // if empty, call exportJSON to generate content according to current format
  if(!current.trim()){
    exportJSON();
    return;
  }
  // try to parse existing output and reformat according to selector
  try{
    const parsed = JSON.parse(current);
    const fmt = (document.getElementById('output-format') || {}).value || 'pretty';
    area.value = fmt === 'compact' ? JSON.stringify(parsed) : JSON.stringify(parsed, null, 2);
  }catch(e){
    // not valid JSON, leave as-is
  }
}

function copyOutput(){
  const txt = document.getElementById('output-area');
  txt.select();
  document.execCommand('copy');
  alert('已复制到剪贴板');
}

function saveOutput(){
  let out = document.getElementById('output-area').value;
  if(!out){
    exportJSON();
    out = document.getElementById('output-area').value;
  }
  // prompt user for filename (default includes timestamp)
  const now = new Date();
  const pad = n => String(n).padStart(2,'0');
  const defaultName = `tasks_${now.getFullYear()}${pad(now.getMonth()+1)}${pad(now.getDate())}_${pad(now.getHours())}${pad(now.getMinutes())}${pad(now.getSeconds())}.mission`;
  let fname = window.prompt('请输入保存文件名（可带或不带 .mission）：', defaultName);
  if(fname === null) return; // user cancelled
  fname = String(fname).trim();
  if(fname === '') fname = 'tasks.mission';
  if(!/\.mission$/i.test(fname)) fname = fname + '.mission';
  const blob = new Blob([out], {type: 'application/json'});
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = fname;
  document.body.appendChild(a);
  a.click();
  a.remove();
  URL.revokeObjectURL(url);
}

function clearInput(){ document.getElementById('input-area').value = ''; }

function attachHandlers(){
  document.getElementById('add-wp').addEventListener('click', ()=>addWaypoint());
  document.getElementById('import-btn').addEventListener('click', importData);
  document.getElementById('export-btn').addEventListener('click', exportJSON);
  document.getElementById('copy-btn').addEventListener('click', copyOutput);
  document.getElementById('save-btn').addEventListener('click', saveOutput);
  const fmtSel = document.getElementById('output-format');
  if(fmtSel) fmtSel.addEventListener('change', refreshOutput);
  document.getElementById('clear-input').addEventListener('click', clearInput);
}

window.addEventListener('DOMContentLoaded', ()=>{
  attachHandlers();
  // start with one waypoint
  addWaypoint();
});
