// ── Slash commands ──────────────────────────────────────────────────────────
// Commands are loaded dynamically from GET /api/commands (Hermes COMMAND_REGISTRY).
// Tier-2 Agent commands and passthrough handlers are added client-side.
// Each command either runs locally or is forwarded as a message to the agent.

let COMMANDS=[];  // Loaded async via loadCommands()

// Map Hermes passthrough command names to their fn.
// These commands are forwarded to the agent as-is.
const _PASSTHROUGH=['retry','undo','title','branch','stop','background','btw',
  'queue','status','profile','resume','snapshot','rollback','provider',
  'yolo','reasoning','fast','voice','reload','reload-mcp','cron','browser',
  'plugins','insights','platforms','debug','update','image','inbox'];

function _fnFor(name){
  if(name==='help'||name==='commands') return cmdHelp;
  if(name==='clear') return cmdClear;
  if(name==='compact'||name==='compress') return cmdCompact;
  if(name==='model') return cmdModel;
  if(name==='workspace') return cmdWorkspace;
  if(name==='new') return cmdNew;
  if(name==='usage') return cmdUsage;
  if(name==='theme') return cmdTheme;
  if(name==='skills') return cmdSkills;
  if(name==='personality') return cmdPersonality;
  if(_PASSTHROUGH.includes(name)) return cmdPassthrough;
  // Fallback: passthrough unknown commands so new Hermes commands work without JS changes
  return cmdPassthrough;
}

/**
 * Fetch commands from Hermes COMMAND_REGISTRY and merge with WebUI-specific commands.
 * Called once at boot time.
 */
async function loadCommands(){
  try{
    const data=await api('/api/commands');
    if(data.error) throw new Error(data.error);
    const cats=data.categories||{};

    // Flatten all categories into COMMANDS
    const merged=[];
    for(const [catName,cmds] of Object.entries(cats)){
      for(const c of cmds){
        merged.push({name:c.name, desc:c.desc, arg:c.arg||'(none)',
          aliases:c.aliases||[], fn:_fnFor(c.name)});
      }
    }

    // ── Tier-2 Domain Agents (WebUI-specific, override API entries) ──
    // Dedup: remove any API entries that would clash with Tier-2 agents
    const _agentNames=['sunflower','lotus','forget-me-not','iris','ivy',
                       'dandelion','root','back','inbox'];
    // Remove API entries for agent names (they may already be in the registry
    // from the API if agents registered themselves as commands there)
    const filtered=merged.filter(c=>!_agentNames.includes(c.name));
    // Add Tier-2 agents (these override any API entries of the same name)
    filtered.push(
      {name:'sunflower',     desc:'🌻 Finance, Wealth & Subscriptions', fn:cmdAgent, arg:'message'},
      {name:'lotus',         desc:'🪷 Health, Fitness & Recovery',      fn:cmdAgent, arg:'message'},
      {name:'forget-me-not', desc:'🌼 Calendar, Time & Social',         fn:cmdAgent, arg:'message'},
      {name:'iris',          desc:'⚜️ Career, Learning & Focus',        fn:cmdAgent, arg:'message'},
      {name:'ivy',           desc:'🌿 Smart Home & Environment',         fn:cmdAgent, arg:'message'},
      {name:'dandelion',     desc:'🛡 Communication Triage & Gatekeeping',fn:cmdAgent, arg:'message'},
      {name:'root',          desc:'🌳 DevOps, Logs & System Health',    fn:cmdAgent, arg:'message'},
      {name:'back',          desc:'🌹 Return to Rose (orchestrator)',    fn:cmdAgent, arg:'message'},
    );

    COMMANDS=filtered;
  }catch(e){
    console.warn('[commands] Failed to load from API, using fallback:',e.message);
    // Fallback: empty — user can still type commands manually
    COMMANDS=[];
  }
}

function parseCommand(text){
  if(!text.startsWith('/'))return null;
  const parts=text.slice(1).split(/\s+/);
  const name=parts[0].toLowerCase();
  const args=parts.slice(1).join(' ').trim();
  return {name,args};
}

function executeCommand(text){
  const parsed=parseCommand(text);
  if(!parsed)return false;
  const cmd=COMMANDS.find(c=>c.name===parsed.name);
  if(!cmd)return false;
  cmd.fn(parsed.args);
  return true;
}

function getMatchingCommands(prefix){
  const q=prefix.toLowerCase();
  return COMMANDS.filter(c=>{
    if(c.name.startsWith(q)) return true;
    // Also match aliases
    if(c.aliases&&c.aliases.some(a=>a.startsWith(q))) return true;
    return false;
  });
}

// ── Generic passthrough: send command text directly to agent ────────────

function cmdPassthrough(args){
  const parsed=parseCommand($('msg').value);
  if(!parsed)return;
  // Forward the raw command to the agent as a regular message
  $('msg').value=$('msg').value; // keep as-is
  send();
}

// ── Command handlers ────────────────────────────────────────────────────

function cmdHelp(){
  // Infer categories from command names (backwards-compatible with hardcoded categories)
  const categories={'Session':[],'Configuration':[],'Tools & Skills':[],'Info':[],'Agents':[]};
  COMMANDS.forEach(c=>{
    let cat='Info';
    if(['new','clear','compact','compress','retry','undo','title','branch',
        'stop','background','btw','queue','status','profile','resume',
        'snapshot','rollback'].includes(c.name)) cat='Session';
    else if(['model','provider','personality','workspace','theme','yolo',
        'reasoning','fast','voice','reload','reload-mcp'].includes(c.name)) cat='Configuration';
    else if(['skills','cron','browser','plugins'].includes(c.name)) cat='Tools & Skills';
    else if(['sunflower','lotus','forget-me-not','iris','ivy','dandelion',
        'root','back','inbox'].includes(c.name)) cat='Agents';
    if(!categories[cat])categories[cat]=[];
    categories[cat].push(c);
  });
  const lines=[];
  for(const [cat,cmds] of Object.entries(categories)){
    if(!cmds.length)continue;
    lines.push(`\n**${cat}**`);
    cmds.forEach(c=>{
      const usage=c.arg&&c.arg!=='(none)'?` <${c.arg}>`:'';
      lines.push(`  /${c.name}${usage} — ${c.desc}`);
    });
  }
  const msg={role:'assistant',content:'Available commands:\n'+lines.join('\n')};
  S.messages.push(msg);
  renderMessages();
  showToast('Type / to see commands');
}

function cmdClear(){
  if(!S.session)return;
  S.messages=[];S.toolCalls=[];
  clearLiveToolCards();
  renderMessages();
  $('emptyState').style.display='';
  showToast(t('conversation_cleared'));
}

async function cmdModel(args){
  if(!args){showToast('Usage: /model <model_name>');return;}
  const sel=$('modelSelect');
  if(!sel)return;
  const q=args.toLowerCase();
  let match=null;
  for(const opt of sel.options){
    if(opt.value.toLowerCase().includes(q)||opt.textContent.toLowerCase().includes(q)){
      match=opt.value;break;
    }
  }
  if(!match){showToast('No model matching "'+args+'"');return;}
  sel.value=match;
  await sel.onchange();
  showToast(t('switched_to')+match);
}

async function cmdWorkspace(args){
  if(!args){showToast('Usage: /workspace <name>');return;}
  try{
    const data=await api('/api/workspaces');
    const q=args.toLowerCase();
    const ws=(data.workspaces||[]).find(w=>
      (w.name||'').toLowerCase().includes(q)||w.path.toLowerCase().includes(q)
    );
    if(!ws){showToast('No workspace matching "'+args+'"');return;}
    if(typeof switchToWorkspace==='function') await switchToWorkspace(ws.path, ws.name||ws.path);
    else showToast(t('switched_workspace')+(ws.name||ws.path));
  }catch(e){showToast(t('workspace_switch_failed')+e.message);}
}

async function cmdNew(){
  await newSession();
  await renderSessionList();
  $('msg').focus();
  showToast(t('new_session'));
}

function cmdCompact(){
  $('msg').value='Please compress and summarize the conversation context to free up space.';
  send();
  showToast(t('compressing'));
}

async function cmdUsage(){
  const next=!window._showTokenUsage;
  window._showTokenUsage=next;
  try{
    await api('/api/settings',{method:'POST',body:JSON.stringify({show_token_usage:next})});
  }catch(e){}
  const cb=$('settingsShowTokenUsage');
  if(cb) cb.checked=next;
  renderMessages();
  showToast(next?t('token_usage_on'):t('token_usage_off'));
}

async function cmdTheme(args){
  const themes=['system','dark','light','slate','solarized','monokai','nord','oled'];
  if(!args||!themes.includes(args.toLowerCase())){
    showToast('Themes: '+themes.join(' | '));
    return;
  }
  const themeName=args.toLowerCase();
  localStorage.setItem('hermes-theme',themeName);
  _applyTheme(themeName);
  try{await api('/api/settings',{method:'POST',body:JSON.stringify({theme:themeName})});}catch(e){}
  const sel=$('settingsTheme');
  if(sel)sel.value=themeName;
  showToast(t('theme_set')+themeName);
}

async function cmdSkills(args){
  try{
    const data = await api('/api/skills');
    let skills = data.skills || [];
    if(args){
      const q = args.toLowerCase();
      skills = skills.filter(s =>
        (s.name||'').toLowerCase().includes(q) ||
        (s.description||'').toLowerCase().includes(q) ||
        (s.category||'').toLowerCase().includes(q)
      );
    }
    if(!skills.length){
      const msg = {role:'assistant', content: args ? `No skills matching "${args}".` : 'No skills found.'};
      S.messages.push(msg); renderMessages(); return;
    }
    const byCategory = {};
    skills.forEach(s => {
      const cat = s.category || 'General';
      if(!byCategory[cat]) byCategory[cat] = [];
      byCategory[cat].push(s);
    });
    const lines = [];
    for(const [cat, items] of Object.entries(byCategory).sort()){
      lines.push(`**${cat}**`);
      items.forEach(s => {
        const desc = s.description ? ` — ${s.description.slice(0,80)}${s.description.length>80?'...':''}` : '';
        lines.push(`  \`${s.name}\`${desc}`);
      });
      lines.push('');
    }
    const header = args
      ? `Skills matching "${args}" (${skills.length}):\n\n`
      : `Available skills (${skills.length}):\n\n`;
    S.messages.push({role:'assistant', content: header + lines.join('\n')});
    renderMessages();
  }catch(e){
    showToast('Failed to load skills: '+e.message);
  }
}

async function cmdPersonality(args){
  if(!S.session){showToast(t('no_active_session'));return;}
  if(!args){
    try{
      const data=await api('/api/personalities');
      if(!data.personalities||!data.personalities.length){
        showToast(t('no_personalities'));
        return;
      }
      const list=data.personalities.map(p=>`  **${p.name}**${p.description?' — '+p.description:''}`).join('\n');
      S.messages.push({role:'assistant',content:t('available_personalities')+'\n\n'+list+'\n\nSwitch with: /personality <name>'});
      renderMessages();
    }catch(e){showToast(t('personalities_load_failed'));}
    return;
  }
  const name=args.trim();
  if(name.toLowerCase()==='none'||name.toLowerCase()==='default'||name.toLowerCase()==='clear'){
    try{
      await api('/api/personality/set',{method:'POST',body:JSON.stringify({session_id:S.session.session_id,name:''})});
      showToast(t('personality_cleared'));
    }catch(e){showToast(t('failed_colon')+e.message);}
    return;
  }
  try{
    const res=await api('/api/personality/set',{method:'POST',body:JSON.stringify({session_id:S.session.session_id,name})});
    showToast(t('personality_set')+name);
  }catch(e){showToast(t('failed_colon')+e.message);}
}

// ── Tier-2 Agent Command Handler ────────────────────────────────────────

const AGENT_INFO={
  'sunflower':     {emoji:'🌻', name:'Sunflower',    file:'sunflower/soul.md',     domain:'Finance, Wealth & Subscriptions'},
  'lotus':         {emoji:'🪷', name:'Lotus',        file:'lotus/soul.md',         domain:'Health, Fitness & Recovery'},
  'forget-me-not': {emoji:'🌼', name:'Forget-me-not',file:'forget-me-not/soul.md', domain:'Calendar, Time & Social'},
  'iris':          {emoji:'⚜️', name:'Iris',         file:'iris/soul.md',          domain:'Career, Learning & Focus'},
  'ivy':           {emoji:'🌿', name:'Ivy',          file:'ivy/soul.md',           domain:'Smart Home & Environment'},
  'dandelion':     {emoji:'🛡', name:'Dandelion',    file:'dandelion/soul.md',     domain:'Communication Triage & Gatekeeping'},
  'root':          {emoji:'🌳', name:'Root',         file:'root/soul.md',          domain:'DevOps, Logs & System Health'},
  'back':          {emoji:'🌹', name:'Rose',         file:'rose/soul.md',          domain:'Orchestrator (return from agent)'},
};

function cmdAgent(args){
  const parsed=parseCommand($('msg').value);
  if(!parsed)return;
  const agentKey=parsed.name;
  const info=AGENT_INFO[agentKey];
  if(!info){showToast('Unknown agent: '+agentKey);return;}

  const userMsg=args||'';
  const contextMsg=`[Agent Switch: ${info.emoji} ${info.name}]\nLoad ~/.hermes/agents/${info.file} and handle this request as ${info.name} (${info.domain}).${userMsg?'\n\nUser message: '+userMsg:''}`;

  $('msg').value=contextMsg;
  send();
}

// ── Autocomplete dropdown ───────────────────────────────────────────────

let _cmdSelectedIdx=-1;

function showCmdDropdown(matches){
  const dd=$('cmdDropdown');
  if(!dd)return;
  dd.innerHTML='';
  _cmdSelectedIdx=-1;
  for(let i=0;i<matches.length;i++){
    const c=matches[i];
    const el=document.createElement('div');
    el.className='cmd-item';
    el.dataset.idx=i;
    const usage=c.arg&&c.arg!=='(none)'?` <span class="cmd-item-arg">${esc(c.arg)}</span>`:'';
    el.innerHTML=`<div class="cmd-item-name">/${esc(c.name)}${usage}</div><div class="cmd-item-desc">${esc(c.desc)}</div>`;
    el.onmousedown=(e)=>{
      e.preventDefault();
      $('msg').value='/'+c.name+(c.arg&&c.arg!=='(none)'?' ':'');
      hideCmdDropdown();
      $('msg').focus();
    };
    dd.appendChild(el);
  }
  dd.classList.add('open');
}

function hideCmdDropdown(){
  const dd=$('cmdDropdown');
  if(dd)dd.classList.remove('open');
  _cmdSelectedIdx=-1;
}

function navigateCmdDropdown(dir){
  const dd=$('cmdDropdown');
  if(!dd)return;
  const items=dd.querySelectorAll('.cmd-item');
  if(!items.length)return;
  items.forEach(el=>el.classList.remove('selected'));
  _cmdSelectedIdx+=dir;
  if(_cmdSelectedIdx<0)_cmdSelectedIdx=items.length-1;
  if(_cmdSelectedIdx>=items.length)_cmdSelectedIdx=0;
  items[_cmdSelectedIdx].classList.add('selected');
}

function selectCmdDropdownItem(){
  const dd=$('cmdDropdown');
  if(!dd)return;
  const items=dd.querySelectorAll('.cmd-item');
  if(_cmdSelectedIdx>=0&&_cmdSelectedIdx<items.length){
    items[_cmdSelectedIdx].onmousedown({preventDefault:()=>{}});
  } else if(items.length===1){
    items[0].onmousedown({preventDefault:()=>{}});
  }
  hideCmdDropdown();
}
