import 'dart:io';

import 'package:auto_updater/auto_updater.dart';
import 'package:injectable/injectable.dart';
import 'package:moonwell_launcher/config.dart';
import 'package:moonwell_launcher/features/launcher/data/launcher_log_service.dart';

abstract interface class LauncherUpdateClient {
  Future<void> setFeedUrl(String feedUrl);

  Future<void> disableScheduledChecks();

  Future<void> checkInBackground();
}

final class AutoUpdaterLauncherUpdateClient implements LauncherUpdateClient {
  @override
  Future<void> setFeedUrl(String feedUrl) => autoUpdater.setFeedURL(feedUrl);

  @override
  Future<void> disableScheduledChecks() =>
      autoUpdater.setScheduledCheckInterval(0);

  @override
  Future<void> checkInBackground() =>
      autoUpdater.checkForUpdates(inBackground: true);
}

@lazySingleton
class LauncherUpdateService {
  LauncherUpdateService(LauncherLogService launcherLogService)
    : this.forTesting(
        launcherLogService: launcherLogService,
        updateClient: AutoUpdaterLauncherUpdateClient(),
        isWindows: Platform.isWindows,
      );

  LauncherUpdateService.forTesting({
    required LauncherLogService launcherLogService,
    required LauncherUpdateClient updateClient,
    required bool isWindows,
  }) : _launcherLogService = launcherLogService,
       _updateClient = updateClient,
       _isWindows = isWindows;

  final LauncherLogService _launcherLogService;
  final LauncherUpdateClient _updateClient;
  final bool _isWindows;

  bool _hasChecked = false;

  Future<void> checkForUpdates({
    String feedUrl = Config.launcherAppcastUrl,
  }) async {
    if (!_isWindows || _hasChecked) {
      return;
    }

    final normalizedFeedUrl = feedUrl.trim();
    if (normalizedFeedUrl.isEmpty) {
      await _launcherLogService.info(
        'Launcher self-update is disabled because no AppCast URL is configured.',
      );
      return;
    }

    final uri = Uri.tryParse(normalizedFeedUrl);
    if (uri == null ||
        !uri.isAbsolute ||
        uri.scheme != 'https' ||
        !uri.hasAuthority ||
        uri.host.isEmpty) {
      await _launcherLogService.error(
        'Launcher self-update AppCast URL is invalid.',
        details: <String, Object?>{'feedUrl': normalizedFeedUrl},
      );
      return;
    }

    _hasChecked = true;

    try {
      await _updateClient.setFeedUrl(normalizedFeedUrl);
      await _updateClient.disableScheduledChecks();
      await _updateClient.checkInBackground();
      await _launcherLogService.info(
        'Launcher self-update check started.',
        details: <String, Object?>{'feedUrl': normalizedFeedUrl},
      );
    } catch (error, stackTrace) {
      await _launcherLogService.error(
        'Launcher self-update check failed.',
        details: <String, Object?>{'feedUrl': normalizedFeedUrl},
        error: error,
        stackTrace: stackTrace,
      );
    }
  }
}
