/**
 * Function/Storage/large-file-finder.js
 * ---------------------------------------------------------------------------
 * LARGE FILE FINDER
 *
 * Scans a folder or drive for files above a size threshold and lists them with
 * size, location and last-modified date. Nothing is ever deleted here.
 * ---------------------------------------------------------------------------
 */

'use strict';

const os = require('os');
const path = require('path');
const kit = require('../../core/kit');
const system = require('../../core/system');
const scan = require('../../core/fs-scan');

/** Sensible starting points offered before the free-text field. */
function suggestions() {
  const home = os.homedir();
  return [
    { label: `Downloads  (${path.join(home, 'Downloads')})`, value: path.join(home, 'Downloads') },
    { label: `Documents  (${path.join(home, 'Documents')})`, value: path.join(home, 'Documents')},
    { label: `Videos     (${path.join(home, 'Videos')})`, value: path.join(home, 'Videos') },
    { label: `User profile (${home})`, value: home },
    ...scan.fixedDrives().map((drive) => ({ label: `Drive ${drive}`, value: drive })),
    { label: 'Enter another folder...', value: null },
  ];
}

module.exports = {
  name: 'Large File Finder',
  menuName: 'Large File Finder',
  description: 'Finds files above a size threshold in a folder or drive and lists where they are.',
  version: '1.0.0',
  author: 'InfinitySniper HFX',
  category: 'Storage',
  order: 30,
  requiredPermissions: 'normal',
  destructive: false,
  dependencies: [],
  minimumAppVersion: '1.0.0',
  permissions: ['filesystem:read', 'filesystem:write(reports)'],
  tags: ['files', 'large', 'space', 'disk', 'find'],
  config: { minimumMb: 100, maxResults: 50, timeBudgetSeconds: 120 },
  documentation:
    'Walks a folder or an entire drive and collects every file at or above the chosen size. ' +
    'Results are sorted largest first and show name, size, folder and last-modified date. ' +
    'The scan has a time budget so a huge drive cannot hang the application. ' +
    'This function never deletes anything - it only reports.',

  async selfTest() {
    const result = await scan.walk(os.tmpdir(), { maxDepth: 1, timeBudgetMs: 4000, collectFiles: false });
    return { ok: true, message: `walker reached ${result.totalFiles} file(s) in the temp folder` };
  },

  async execute(ctx) {
    const { ui, prompt, config, settings } = ctx;
    kit.header('Large File Finder', ['Find the biggest files in a folder or on a drive.', 'Nothing is deleted.']);

    // ---- target ---------------------------------------------------------
    const options = suggestions();
    const choice = await prompt.choose('Where should the scan start?', options.map((o) => o.label));
    if (choice === null) return kit.done('Scan cancelled.');

    let target = options[choice].value;
    if (!target) {
      target = await prompt.text('Folder path');
      if (!target) return kit.done('Scan cancelled.');
    }
    target = String(target).replace(/^"|"$/g, '').trim();

    if (!scan.isDirectory(target)) {
      ui.blank();
      ui.error(`"${target}" is not a folder that can be read.`);
      return { ok: false, reason: 'invalid-path' };
    }

    // ---- parameters -----------------------------------------------------
    const defaultMb = Number(settings.tools.largeFileMinimumMb) || Number(config.minimumMb) || 100;
    ui.blank();
    ui.info(`Default minimum size: ${defaultMb} MB (press ENTER to keep it)`);
    const chosenMb = await prompt.number('Minimum file size in MB', 1, 1024 * 1024);
    const minimumMb = chosenMb === null ? defaultMb : chosenMb;

    const defaultMax = Number(settings.tools.maxResults) || Number(config.maxResults) || 50;
    const chosenMax = await prompt.number('Maximum results to show', 5, 5000);
    const maxResults = chosenMax === null ? defaultMax : chosenMax;

    // ---- scan -----------------------------------------------------------
    ui.blank();
    ui.section('SCAN');
    ui.blank();
    kit.kv('Target Directory', target);
    kit.kv('Minimum File Size', `${minimumMb} MB`);
    kit.kv('Maximum Results', String(maxResults));
    ui.blank();

    const started = Date.now();
    const spin = ui.spinner('Scanning...');
    const result = await scan.walk(target, {
      minSize: minimumMb * 1024 * 1024,
      timeBudgetMs: Math.max(10, Number(config.timeBudgetSeconds) || 120) * 1000,
      onProgress: (state) => {
        spin.update(
          `Scanning... ${system.formatNumber(state.files)} files, ${system.formatBytes(state.bytes)} - ${kit.ui.truncate(state.current, 40)}`
        );
      },
    });
    spin.stop('OK', `Scan finished in ${((Date.now() - started) / 1000).toFixed(1)}s`);

    const files = result.files.sort((a, b) => b.size - a.size);

    ui.blank();
    kit.kv('Files Scanned', system.formatNumber(result.totalFiles));
    kit.kv('Folders Scanned', system.formatNumber(result.folders));
    kit.kv('Data Scanned', system.formatBytes(result.totalBytes));
    kit.kv('Matches', system.formatNumber(files.length));
    kit.kv('Size Of Matches', system.formatBytes(files.reduce((sum, file) => sum + file.size, 0)));
    if (result.errors.length) kit.kv('Unreadable Folders', system.formatNumber(result.errors.length));
    if (result.truncated) {
      ui.blank();
      ui.warning('The time budget was reached - the scan is partial. Narrow the folder for a complete result.');
    }

    if (!files.length) {
      ui.blank();
      ui.info(`No file of ${minimumMb} MB or more was found in this location.`);
      return { ok: true, matches: 0 };
    }

    ui.blank();
    ui.section('LARGEST FILES');
    ui.blank();
    kit.table(
      ['FILE', 'SIZE', 'MODIFIED', 'LOCATION'],
      files.slice(0, maxResults).map((file) => [
        ui.c.brightWhite(ui.truncate(file.name, 28)),
        ui.c.brightCyan(system.formatBytes(file.size)),
        ui.c.gray(system.isoLocal(new Date(file.mtimeMs)).slice(0, 10)),
        ui.c.gray(ui.truncate(file.dir, 34)),
      ]),
      { align: ['left', 'right', 'left', 'left'], limit: maxResults }
    );

    ui.blank();
    ui.println('  ' + ui.c.gray('Nothing was deleted. Review the list before removing anything yourself.'));

    await kit.offerExport('Large File Report', 'LargeFiles', (report) => {
      const section = report.section('SCAN');
      section.add('Target Directory', target);
      section.add('Minimum File Size', `${minimumMb} MB`);
      section.add('Files Scanned', system.formatNumber(result.totalFiles));
      section.add('Matches', system.formatNumber(files.length));
      section.add('Partial Scan', result.truncated ? 'Yes (time budget reached)' : 'No');

      const list = report.section('LARGEST FILES');
      files.slice(0, Math.max(maxResults, 200)).forEach((file, index) => {
        const group = list.group(`${index + 1}. ${file.name}`);
        group.add('Size', system.formatBytes(file.size));
        group.add('Location', file.dir);
        group.add('Last Modified', system.isoLocal(new Date(file.mtimeMs)));
      });
    });

    return kit.done(`${files.length} large file(s) found.`);
  },
};
