/**
 * Function/Maintenance/recycle-bin.js
 * ---------------------------------------------------------------------------
 * RECYCLE BIN INFORMATION
 *
 * Shows how much the Recycle Bin holds and, as a separate confirmed action,
 * empties it. Emptying is permanent, so it is always opt-in, numeric-confirmed
 * and blocked in Safe Mode.
 * ---------------------------------------------------------------------------
 */

'use strict';

const kit = require('../../core/kit');
const system = require('../../core/system');

/** Shell.Application reaches the Recycle Bin without administrator rights. */
const INSPECT = [
  '$ErrorActionPreference = "SilentlyContinue"',
  '$shell = New-Object -ComObject Shell.Application',
  '$bin = $shell.Namespace(0xA)',
  '$items = @()',
  '$count = 0',
  '$size = 0',
  'if ($bin) {',
  '  foreach ($item in $bin.Items()) {',
  '    $count++',
  '    $bytes = 0',
  '    try { $bytes = [long] $item.ExtendedProperty("Size") } catch { }',
  '    $size += $bytes',
  '    if ($items.Count -lt 40) {',
  '      $items += [ordered]@{ Name = $item.Name; Size = $bytes; Deleted = $bin.GetDetailsOf($item, 2); Origin = $bin.GetDetailsOf($item, 1) }',
  '    }',
  '  }',
  '}',
  '[ordered]@{ count = $count; size = $size; items = @($items) } | ConvertTo-Json -Depth 4 -Compress',
].join('\n');

const EMPTY = [
  '$ErrorActionPreference = "Stop"',
  'try {',
  '  Clear-RecycleBin -Force -ErrorAction Stop',
  '  "OK"',
  '} catch {',
  '  if ($_.Exception.Message -match "empty") { "EMPTY" } else { "ERROR: " + $_.Exception.Message }',
  '}',
].join('\n');

async function inspect() {
  const result = await system.runPowerShellJson(INSPECT, { timeoutMs: 90000 });
  if (!result.ok || !result.data) return null;
  return {
    count: Number(result.data.count) || 0,
    size: Number(result.data.size) || 0,
    items: system.asArray(result.data.items),
  };
}

module.exports = {
  name: 'Recycle Bin',
  menuName: 'Recycle Bin Information',
  description: 'Shows the size and contents of the Recycle Bin and can empty it after confirmation.',
  version: '1.0.0',
  author: 'InfinitySniper HFX',
  category: 'Maintenance',
  order: 20,
  requiredPermissions: 'normal',
  destructive: true,
  dependencies: [],
  minimumAppVersion: '1.0.0',
  permissions: ['shell:recycle-bin', 'filesystem:delete(recycle bin)'],
  tags: ['recycle', 'bin', 'trash', 'cleanup', 'space'],
  documentation:
    'Reports how many items the Recycle Bin holds and how much space they use, with a preview of the ' +
    'most recent entries. Emptying is a separate action that requires a numeric confirmation, is ' +
    'blocked in Safe Mode and does nothing in Dry Run. Emptying is permanent - the files cannot be ' +
    'restored afterwards.',

  async selfTest(ctx) {
    if (!ctx.system.IS_WINDOWS) return { ok: false, message: 'Windows only' };
    const info = await inspect();
    return info ? { ok: true, message: `${info.count} item(s) in the bin` } : { ok: false, message: 'bin not readable' };
  },

  async execute(ctx) {
    const { ui, prompt } = ctx;
    kit.header('Recycle Bin', ['Size and contents of the Recycle Bin.', 'Emptying is permanent and confirmed.']);
    if (!kit.requireWindows('The Recycle Bin function')) return { ok: false, reason: 'unsupported-platform' };

    for (;;) {
      const spin = ui.spinner('Inspecting the Recycle Bin...');
      const info = await inspect();
      spin.stop();

      if (!info) {
        ui.warning('The Recycle Bin could not be inspected on this system.');
        return { ok: false, reason: 'not-available' };
      }

      ui.blank();
      ui.section('RECYCLE BIN');
      ui.blank();
      kit.kv('Items', system.formatNumber(info.count));
      kit.kv('Estimated Size', system.formatBytes(info.size), 'brightGreen');

      if (info.count === 0) {
        ui.blank();
        ui.completed('The Recycle Bin is empty - nothing to recover here.');
        return { ok: true, count: 0 };
      }

      if (info.items.length) {
        ui.blank();
        ui.section('CONTENTS (preview)');
        ui.blank();
        kit.table(
          ['NAME', 'SIZE', 'DELETED'],
          info.items.map((item) => [
            ui.c.brightWhite(ui.truncate(system.clean(item.Name) || 'Unknown', 32)),
            ui.c.brightCyan(system.formatBytes(item.Size)),
            ui.c.gray(ui.truncate(system.clean(item.Deleted) || '-', 18)),
          ]),
          { align: ['left', 'right', 'left'], limit: 15 }
        );
        if (info.count > info.items.length) {
          ui.println('  ' + ui.c.gray(`... and ${info.count - info.items.length} more item(s)`));
        }
      }

      ui.blank();
      ui.menu(
        [
          { key: '1', label: 'Refresh' },
          { key: '2', label: 'Export the contents as a TXT report' },
          { key: '3', label: 'Empty the Recycle Bin', color: 'brightRed' },
          { separator: true },
          { key: '0', label: 'Back', color: 'gray' },
        ],
        { title: 'RECYCLE BIN' }
      );
      ui.blank();

      const answer = await prompt.select();
      if (!answer && prompt.isClosed()) break;
      if (answer === '0') break;

      if (answer === '1') {
        ui.clear();
        continue;
      }

      if (answer === '2') {
        const report = kit.report('Recycle Bin Report');
        const section = report.section('RECYCLE BIN');
        section.add('Items', system.formatNumber(info.count));
        section.add('Estimated Size', system.formatBytes(info.size));
        const list = report.section('CONTENTS');
        info.items.forEach((item, index) => {
          list.add(
            `${index + 1}. ${system.clean(item.Name) || 'Unknown'}`,
            `${system.formatBytes(item.Size)} - deleted ${system.clean(item.Deleted) || '?'} - from ${system.clean(item.Origin) || '?'}`
          );
        });
        kit.saveReport(report, 'RecycleBin');
        await prompt.pause();
        continue;
      }

      if (answer === '3') {
        if (ctx.safeMode) {
          ui.blank();
          ui.warning('Safe Mode is enabled - emptying the Recycle Bin is blocked.');
          await prompt.pause();
          continue;
        }
        if (ctx.dryRun) {
          ui.blank();
          ui.info(`Dry Run: ${info.count} item(s) (${system.formatBytes(info.size)}) would be deleted permanently.`);
          await prompt.pause();
          continue;
        }

        ui.blank();
        ui.warning('Emptying the Recycle Bin permanently deletes its contents - this cannot be undone.');
        const confirmed = await prompt.confirm(
          `Permanently delete ${system.formatNumber(info.count)} item(s) and recover ${system.formatBytes(info.size)}?`,
          { danger: true }
        );
        if (confirmed !== true) {
          ui.info('Cancelled - the Recycle Bin was not touched.');
          await prompt.pause();
          continue;
        }

        const spin2 = ui.spinner('Emptying the Recycle Bin...');
        const outcome = await system.runPowerShell(EMPTY, { timeoutMs: 180000 });
        spin2.stop();
        const text = outcome.stdout.trim();

        ui.blank();
        if (text.startsWith('OK')) {
          ui.completed(`Recycle Bin emptied - ${system.formatBytes(info.size)} recovered.`);
          ctx.logger.info('recycle-bin', 'Recycle Bin emptied', { items: info.count, bytes: info.size });
        } else if (text.startsWith('EMPTY')) {
          ui.completed('The Recycle Bin was already empty.');
        } else {
          ui.error(`The Recycle Bin could not be emptied: ${text || outcome.stderr || 'unknown error'}`);
          ctx.logger.error('recycle-bin', 'Empty failed', text || outcome.stderr);
        }
        await prompt.pause();
        continue;
      }

      ui.warning('Enter one of the numbers shown above, or 0 to go back.');
      await prompt.pause();
    }

    return kit.done('Recycle Bin function closed.');
  },
};
