// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only

/// Runs the Build workspace script.
library;

import 'dart:io';

/// Builds platform-specific Flutter desktop release artifacts.
Future<void> main(List<String> arguments) async {
  final platform = _option(arguments, '--platform') ?? 'current';
  final outputDirectory =
      Directory(_option(arguments, '--output') ?? 'build/releases');
  await outputDirectory.create(recursive: true);

  final resolved = platform == 'current' ? _currentPlatform() : platform;
  switch (resolved) {
    case 'macos':
      await _buildMacOs(outputDirectory);
      break;
    case 'windows':
      await _buildWindows(outputDirectory);
      break;
    case 'linux':
      await _buildLinux(outputDirectory);
      break;
    default:
      throw ArgumentError.value(
        platform,
        '--platform',
        'Expected current, macos, windows, or linux.',
      );
  }
}

/// Top-level helper that performs the `_buildMacOs` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Future<void> _buildMacOs(Directory outputDirectory) async {
  await _run('flutter', <String>['build', 'macos', '--release']);
  final releaseDir = Directory('build/macos/Build/Products/Release');
  final apps = releaseDir
      .listSync()
      .whereType<Directory>()
      .where((entry) => entry.path.endsWith('.app'))
      .toList(growable: false);
  if (apps.isEmpty) {
    throw StateError('No macOS .app found in ${releaseDir.path}.');
  }
  for (final app in apps) {
    await _copyDirectory(
        app, Directory(_join(outputDirectory.path, _basename(app.path))));
  }
}

/// Top-level helper that performs the `_buildWindows` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Future<void> _buildWindows(Directory outputDirectory) async {
  await _run('flutter', <String>['build', 'windows', '--release']);
  final bundle = Directory('build/windows/x64/runner/Release');
  if (!await bundle.exists()) {
    throw StateError('No Windows release bundle found in ${bundle.path}.');
  }
  await _copyDirectory(
      bundle, Directory(_join(outputDirectory.path, 'windows')));
  await _run('dart', <String>['run', 'msix:create']);
  final msixFiles = Directory.current
      .listSync(recursive: true)
      .whereType<File>()
      .where((file) => file.path.endsWith('.msix'))
      .toList(growable: false);
  if (msixFiles.isEmpty) {
    throw StateError('No .msix artifact produced by dart run msix:create.');
  }
  for (final file in msixFiles) {
    await file.copy(_join(outputDirectory.path, _basename(file.path)));
  }
}

/// Top-level helper that performs the `_buildLinux` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Future<void> _buildLinux(Directory outputDirectory) async {
  await _run('flutter', <String>['build', 'linux', '--release']);
  await _run('appimage-builder', <String>[
    '--recipe',
    'AppImageBuilder.yml',
    '--skip-test',
  ]);
  final appImages = Directory.current
      .listSync(recursive: true)
      .whereType<File>()
      .where((file) => file.path.endsWith('.AppImage'))
      .toList(growable: false);
  if (appImages.isEmpty) {
    throw StateError('No AppImage artifact produced by appimage-builder.');
  }
  for (final file in appImages) {
    await file.copy(_join(outputDirectory.path, _basename(file.path)));
  }
}

/// Top-level helper that performs the `_run` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Future<void> _run(String executable, List<String> arguments) async {
  stdout.writeln('> $executable ${arguments.join(' ')}');
  final result = await Process.run(
    executable,
    arguments,
    runInShell: Platform.isWindows,
  );
  stdout.write(result.stdout);
  stderr.write(result.stderr);
  if (result.exitCode != 0) {
    throw ProcessException(
      executable,
      arguments,
      'Command failed with exit code ${result.exitCode}.',
      result.exitCode,
    );
  }
}

/// Top-level helper that performs the `_copyDirectory` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
Future<void> _copyDirectory(Directory source, Directory destination) async {
  await destination.create(recursive: true);
  await for (final entity in source.list(recursive: false)) {
    final targetPath = _join(destination.path, _basename(entity.path));
    if (entity is Directory) {
      await _copyDirectory(entity, Directory(targetPath));
    } else if (entity is File) {
      await entity.copy(targetPath);
    }
  }
}

/// Top-level helper that performs the `_currentPlatform` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _currentPlatform() {
  if (Platform.isMacOS) return 'macos';
  if (Platform.isWindows) return 'windows';
  if (Platform.isLinux) return 'linux';
  throw UnsupportedError('No Flutter desktop build target for this platform.');
}

/// Top-level helper that performs the `_basename` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _basename(String path) {
  final normalized = path.replaceAll('\\', '/');
  return normalized.substring(normalized.lastIndexOf('/') + 1);
}

/// Top-level helper that performs the `_join` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String _join(String first, String second) {
  final separator = Platform.pathSeparator;
  final left = first.endsWith(separator)
      ? first.substring(0, first.length - separator.length)
      : first;
  final right = second.startsWith(separator) ? second.substring(1) : second;
  return '$left$separator$right';
}

/// Top-level helper that performs the `_option` operation for this file.
/// Keeping the helper private makes the surrounding flow easier to read while preventing unrelated libraries from depending on implementation detail.
String? _option(List<String> arguments, String name) {
  final index = arguments.indexOf(name);
  if (index == -1 || index + 1 >= arguments.length) {
    return null;
  }
  return arguments[index + 1];
}
