import { readFileSync } from 'node:fs'; import { execFileSync } from 'node:child_process'; import { join } from 'node:path';
export type SessionIdentity={sessionId:string;name:string;nameSource:'session-name'|'worktree-slug'|'unresolved';terminal:string|null;workspace:string|null;cwd:string;host:string};
export type IdentityDeps={readProc:(pid:number)=>{ppid:number;comm:string}|null;readSessionState:(pid:number)=>Record<string,unknown>|null;findWorkspace:(pid:number)=>string|null;hostname:()=>string};
function slug(cwd:string){const m=cwd.match(/\.worktrees\/([^/]+)/);return m?.[1]??null}
export function resolveSessionIdentity(pid:number,deps:IdentityDeps):SessionIdentity {let current=pid,state:Record<string,unknown>|null=null, terminalPid:number|undefined, emu:string|null=null, ssh=false;for(let n=0;n<40;n++){state=deps.readSessionState(current);if(state)break;const p=deps.readProc(current);if(!p)break;const c=p.comm; if(!terminalPid&&/^(gnome-terminal-|vte|xterm|konsole|kitty|alacritty)/.test(c)){terminalPid=current;emu=c.replace(/-$/,'')}if(c==='sshd')ssh=true;if(!p.ppid||p.ppid===current)break;current=p.ppid}const cwd=typeof state?.cwd==='string'&&state.cwd?state.cwd:process.cwd();const sid=typeof state?.sessionId==='string'&&state.sessionId?state.sessionId:`unknown-${pid}`;const named=typeof state?.name==='string'&&state.name.trim();const work=slug(cwd);let name:string,nameSource:SessionIdentity['nameSource'];if(named){name=named;nameSource='session-name'}else if(work){name=work;nameSource='worktree-slug'}else{name='unresolved session';nameSource='unresolved'}const tmux=typeof state?.tmux==='string'&&state.tmux;const terminal=tmux?`tmux:${tmux.split(':')[0]}`:emu??(ssh?'ssh':null);return {sessionId:sid,name,nameSource,terminal,workspace:terminalPid?deps.findWorkspace(terminalPid):null,cwd,host:deps.hostname()}}
// A session name the owner sees must also be a session he can resume: Claude Code's own
// `--resume` picker matches on session id inside the project slug it derives from cwd, never
// on overdeck's friendly name. Any surface naming a session must carry both, or degrade
// honestly (never invent a cwd or fabricate a session id) when either is unknown.
export function hasSessionIdentity(i:SessionIdentity):boolean {
  return typeof i.sessionId==='string' && i.sessionId.length>0 && !i.sessionId.startsWith('unknown-');
}
export function resumeHint(i:SessionIdentity):string {
  return hasSessionIdentity(i) ? `resume: cd ${i.cwd} && claude --resume ${i.sessionId}` : `directory: ${i.cwd}`;
}

export const productionIdentityDeps:IdentityDeps={readProc(pid){try{const stat=readFileSync(`/proc/${pid}/stat`,'utf8');const end=stat.lastIndexOf(')');const x=stat.slice(end+2).split(' ');return {ppid:Number(x[1]),comm:stat.slice(stat.indexOf('(')+1,end)}}catch{return null}},readSessionState(pid){try{return JSON.parse(readFileSync(join(process.env.HOME??'',`.claude/sessions/${pid}.json`),'utf8'))}catch{return null}},findWorkspace(pid){if(process.env.XDG_SESSION_TYPE!=='x11')return null;try{const w=execFileSync('xdotool',['search','--pid',String(pid)],{encoding:'utf8'}).trim().split(/\s+/)[0];if(!w)return null;const d=execFileSync('xdotool',['get_desktop_for_window',w],{encoding:'utf8'}).trim();return /^\d+$/.test(d)?`Workspace ${Number(d)+1}`:null}catch{return null}},hostname(){return process.env.HOSTNAME??'localhost'}};
