import { NotesService } from '../notes/notes-service.js';

export interface InjectConfig {
  perNoteMaxKb: number;
  totalMaxKb: number;
  overBudgetStrategy: 'truncate_last' | 'skip_remaining' | 'degrade_to_search';
}

export interface BuildInjectArgs {
  user: Express.User;
  service: NotesService;
  config: InjectConfig;
}

export function buildInjectSection(args: BuildInjectArgs): string {
  const rows = args.service.listInjectableForConsumer(args.user);
  if (rows.length === 0) return '';
  const perNoteMaxBytes = args.config.perNoteMaxKb * 1024;
  const totalMaxBytes = args.config.totalMaxKb * 1024;
  const lines: string[] = [
    '## Subscribed Notes',
    '',
    "The following notes are auto-included because you've subscribed to them in inject-mode.",
    '',
  ];
  let totalBytes = 0;
  let injectedCount = 0;
  let skippedOversized = 0;
  for (const row of rows) {
    if (row.content_size > perNoteMaxBytes) {
      skippedOversized++;
      continue;
    }
    const remaining = totalMaxBytes - totalBytes;
    if (row.content_size > remaining) {
      if (args.config.overBudgetStrategy === 'truncate_last' && remaining > 256) {
        const display = row.publisher_name ?? row.owner_id;
        lines.push(`### From ${display}/${row.folder}/${row.file_name}`);
        lines.push('');
        lines.push(row.body.slice(0, remaining));
        lines.push('');
        lines.push(`[truncated to fit ${args.config.totalMaxKb}KB budget]`);
        totalBytes += remaining;
        injectedCount++;
      } else if (args.config.overBudgetStrategy === 'degrade_to_search') {
        // Collect remaining notes that didn't fit and emit a search-only placeholder
        const skippedNames: string[] = [];
        const overBudgetRows = rows.slice(rows.indexOf(row));
        for (const r of overBudgetRows) {
          if (r.content_size <= args.config.perNoteMaxKb * 1024) {
            const d = r.publisher_name ?? r.owner_id;
            skippedNames.push(`${d}/${r.folder}/${r.file_name}`);
          }
        }
        if (skippedNames.length > 0) {
          lines.push('### Budget exceeded — use SearchNotes to access remaining notes');
          lines.push('');
          lines.push(
            `The following ${skippedNames.length} note(s) did not fit in the inject budget ` +
            `(${args.config.totalMaxKb}KB). Use the SearchNotes tool to retrieve their content:`
          );
          lines.push('');
          for (const n of skippedNames) {
            lines.push(`- ${n}`);
          }
          lines.push('');
          injectedCount++;
        }
      }
      break;
    }
    const display = row.publisher_name ?? row.owner_id;
    lines.push(`### From ${display}/${row.folder}/${row.file_name}`);
    lines.push('');
    lines.push(row.body);
    lines.push('');
    totalBytes += row.content_size;
    injectedCount++;
  }
  if (injectedCount === 0 && skippedOversized === 0) return '';
  return lines.join('\n');
}
