/**
 * Function/Storage/disk-analyzer.js
 * ---------------------------------------------------------------------------
 * DISK SPACE ANALYZER
 *
 * Where the space went: usage per volume, then the largest top-level folders
 * of a chosen drive. Read-only - nothing is deleted.
 * ---------------------------------------------------------------------------
 */

'use strict';

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

const VOLUME_QUERY =
  '$ErrorActionPreference = "SilentlyContinue"; ' +
  '@(Get-CimInstance Win32_LogicalDisk -Filter "DriveType = 3" | Select-Object DeviceID, VolumeName, FileSystem, Size, FreeSpace) | ConvertTo-Json -Compress';

async function volumes() {
  const result = await system.runPowerShellJson(VOLUME_QUERY, { timeoutMs: 30000 });
  return result.ok ? system.asArray(result.data) : [];
}

function usageRow(ui, volume) {
  const size = Number(volume.Size) || 0;
  const free = Number(volume.FreeSpace) || 0;
  const used = size - free;
  const percent = size ? Math.round((used / size) * 100) : 0;
  return [
    ui.c.brightWhite(String(volume.DeviceID)),
    ui.c.gray(ui.truncate(system.clean(volume.VolumeName) || '-', 14)),
    ui.c.brightCyan(system.formatBytes(size)),
    ui.c.brightGreen(system.formatBytes(free)),
    percent >= 90 ? ui.c.brightRed(`${percent}%`) : ui.c.brightWhite(`${percent}%`),
  ];
}

/** Measure each top-level folder of a drive. */
async function analyzeFolders(ctx, target, budgetMs) {
  const { ui } = ctx;
  const folders = scan.subFolders(target);
  if (!folders.length) return [];

  const results = [];
  const perFolder = Math.max(3000, Math.floor(budgetMs / Math.max(1, folders.length)));

  for (let i = 0; i < folders.length; i += 1) {
    const folder = folders[i];
    ui.progressLine(`Measuring ${path.basename(folder)}`, i, folders.length);
    const measured = await scan.measure(folder, { timeBudgetMs: perFolder, maxDepth: 24 });
    results.push({
      path: folder,
      name: path.basename(folder),
      bytes: measured.bytes,
      files: measured.files,
      truncated: measured.truncated,
      denied: measured.errors.length,
    });
  }
  ui.endProgressLine();
  return results.sort((a, b) => b.bytes - a.bytes);
}

module.exports = {
  name: 'Disk Space Analyzer',
  menuName: 'Disk Space Analyzer',
  description: 'Usage per volume and the largest top-level folders of a drive.',
  version: '1.0.0',
  author: 'InfinitySniper HFX',
  category: 'Storage',
  order: 20,
  requiredPermissions: 'normal',
  destructive: false,
  dependencies: [],
  minimumAppVersion: '1.0.0',
  permissions: ['system:read', 'filesystem:read', 'wmi:query', 'filesystem:write(reports)'],
  tags: ['disk', 'space', 'analyzer', 'usage', 'folders'],
  config: { analysisBudgetSeconds: 90 },
  documentation:
    'Shows how full each fixed volume is, then measures the top-level folders of a drive you choose ' +
    'so you can see where the space actually went. Folders that cannot be read (permissions) are ' +
    'counted as skipped. Nothing is deleted - use the Cache Cleaner or Large File Finder for that.',

  async selfTest(ctx) {
    if (!ctx.system.IS_WINDOWS) return { ok: false, message: 'Windows only' };
    const list = await volumes();
    return list.length ? { ok: true, message: `${list.length} volume(s)` } : { ok: false, message: 'no volumes found' };
  },

  async execute(ctx) {
    const { ui, prompt, config } = ctx;
    kit.header('Disk Space Analyzer', ['Volume usage and the biggest folders on a drive.']);

    const spin = ui.spinner('Reading volumes...');
    const list = await volumes();
    spin.stop();

    if (!list.length) return kit.noData('volume information');

    ui.section('VOLUME USAGE');
    ui.blank();
    kit.table(
      ['DRIVE', 'LABEL', 'SIZE', 'FREE', 'USED'],
      list.map((volume) => usageRow(ui, volume)),
      { align: ['left', 'left', 'right', 'right', 'right'], limit: 26 }
    );

    for (const volume of list) {
      const size = Number(volume.Size) || 0;
      const free = Number(volume.FreeSpace) || 0;
      ui.blank();
      ui.println(
        '  ' + ui.c.brightWhite(ui.padEnd(String(volume.DeviceID), 6)) + ui.progressBar(size - free, size || 1, 26)
      );
    }

    ui.blank();
    const index = await prompt.choose(
      'Analyze which drive?',
      list.map((volume) => ({
        label: `${volume.DeviceID} ${system.clean(volume.VolumeName) || ''}`.trim(),
        hint: `${system.formatBytes(volume.FreeSpace)} free of ${system.formatBytes(volume.Size)}`,
      }))
    );
    if (index === null) return kit.done('Disk analysis finished.');

    const drive = `${list[index].DeviceID}\\`;
    const budgetMs = Math.max(10, Number(config.analysisBudgetSeconds) || 90) * 1000;

    ui.blank();
    ui.info(`Measuring the top-level folders of ${drive} - this can take a while.`);
    ui.blank();

    const folders = await analyzeFolders(ctx, drive, budgetMs);
    if (!folders.length) {
      ui.warning('No readable folder was found on this drive.');
      return kit.done('Disk analysis finished.');
    }

    const measured = folders.reduce((sum, folder) => sum + folder.bytes, 0);

    ui.blank();
    ui.section(`LARGEST FOLDERS ON ${drive}`);
    ui.blank();
    kit.table(
      ['FOLDER', 'SIZE', 'FILES', 'SHARE'],
      folders.map((folder) => [
        ui.c.brightWhite(ui.truncate(folder.name, 30)) + (folder.truncated ? ui.c.yellow(' *') : ''),
        ui.c.brightCyan(system.formatBytes(folder.bytes)),
        ui.c.gray(system.formatNumber(folder.files)),
        ui.c.brightYellow(measured ? `${Math.round((folder.bytes / measured) * 100)}%` : '-'),
      ]),
      { align: ['left', 'right', 'right', 'right'], limit: 20 }
    );

    if (folders.some((f) => f.truncated)) {
      ui.blank();
      ui.println('  ' + ui.c.yellow('* measurement hit the time budget - the real size is larger'));
    }
    const denied = folders.reduce((sum, folder) => sum + folder.denied, 0);
    if (denied) {
      ui.println('  ' + ui.c.gray(`${system.formatNumber(denied)} folder(s) could not be read (permissions).`));
    }

    ui.blank();
    kit.kv('Measured Total', system.formatBytes(measured));

    await kit.offerExport('Disk Space Report', 'DiskAnalysis', (report) => {
      const overview = report.section('VOLUMES');
      for (const volume of list) {
        overview.add(
          `${volume.DeviceID} ${system.clean(volume.VolumeName) || ''}`.trim(),
          `${system.formatBytes(volume.FreeSpace)} free of ${system.formatBytes(volume.Size)}`
        );
      }
      const section = report.section(`FOLDERS ON ${drive}`);
      folders.forEach((folder, position) => {
        section.add(
          `${position + 1}. ${folder.name}`,
          `${system.formatBytes(folder.bytes)} in ${system.formatNumber(folder.files)} file(s)${folder.truncated ? ' (partial)' : ''}`
        );
      });
    });

    return kit.done('Disk analysis finished.');
  },
};
