import 'dart:async';

import 'package:flutter/foundation.dart';

import '../models/wifi_network.dart';
import '../models/wifi_status.dart';
import '../services/http_api_service.dart';
import '../services/web_socket_service.dart';
import 'debug_provider.dart';

class WifiProvider extends ChangeNotifier {
  WifiProvider({
    required HttpApiService httpApiService,
    required WebSocketService webSocketService,
    required DebugProvider debugProvider,
  })  : _httpApiService = httpApiService,
        _webSocketService = webSocketService,
        _debugProvider = debugProvider {
    _wifiSubscription = _webSocketService.onWifiUpdate.listen((payload) {
      _status = WifiStatus.fromJson(payload);
      _debugProvider.addWsLog('Wifi provider update', details: payload);
      notifyListeners();
    });
  }

  final HttpApiService _httpApiService;
  final WebSocketService _webSocketService;
  final DebugProvider _debugProvider;
  late final StreamSubscription<Map<String, dynamic>> _wifiSubscription;

  WifiStatus _status = WifiStatus.disconnected();
  List<WifiNetwork> _networks = const <WifiNetwork>[];
  bool _isLoading = false;
  String? _errorMessage;
  bool _hotspotEnabled = false;

  WifiStatus get status => _status;
  List<WifiNetwork> get networks => _networks;
  bool get isLoading => _isLoading;
  String? get errorMessage => _errorMessage;
  bool get hotspotEnabled => _hotspotEnabled;

  Future<void> bootstrap() async {
    _setLoading(true);
    _debugProvider.addHttpLog('Bootstrap WiFi provider');
    try {
      final results = await Future.wait<dynamic>([
        _httpApiService.getWifiStatus(),
        _httpApiService.scanWifi(),
      ]);
      _status = results[0] as WifiStatus;
      _networks = results[1] as List<WifiNetwork>;
      _errorMessage = null;
      _debugProvider.addHttpLog(
        'WiFi provider bootstrapped',
        details: <String, Object>{'networks': _networks.length},
      );
    } catch (error) {
      _errorMessage = error.toString();
      _debugProvider.addHttpLog('Bootstrap WiFi provider failed', details: error);
    } finally {
      _setLoading(false);
    }
  }

  Future<void> refreshStatus() async {
    _debugProvider.addHttpLog('Refresh WiFi status');
    try {
      _status = await _httpApiService.getWifiStatus();
      _debugProvider.addHttpLog('WiFi status refreshed');
      notifyListeners();
    } catch (error) {
      _errorMessage = error.toString();
      _debugProvider.addHttpLog('Refresh WiFi status failed', details: error);
      notifyListeners();
    }
  }

  Future<void> scanNetworks() async {
    _setLoading(true);
    _debugProvider.addHttpLog('Scan WiFi networks');
    try {
      _networks = await _httpApiService.scanWifi();
      _errorMessage = null;
      _debugProvider.addHttpLog(
        'WiFi scan completed',
        details: <String, Object>{'networks': _networks.length},
      );
    } catch (error) {
      _errorMessage = error.toString();
      _debugProvider.addHttpLog('WiFi scan failed', details: error);
    } finally {
      _setLoading(false);
    }
  }

  Future<void> connect({required String ssid, required String password}) async {
    _setLoading(true);
    _debugProvider.addHttpLog(
      'Connect WiFi network',
      details: <String, Object>{'ssid': ssid},
    );
    try {
      await _httpApiService.connectWifi(ssid, password);
      await refreshStatus();
      _hotspotEnabled = false;
      _errorMessage = null;
      _debugProvider.addHttpLog('WiFi connected', details: <String, Object>{'ssid': ssid});
    } catch (error) {
      _errorMessage = error.toString();
      _debugProvider.addHttpLog('Connect WiFi failed', details: error);
      notifyListeners();
    } finally {
      _setLoading(false);
    }
  }

  Future<void> startHotspot({String? ssid, String? password}) async {
    _setLoading(true);
    _debugProvider.addHttpLog(
      'Start hotspot',
      details: <String, Object?>{'ssid': ssid},
    );
    try {
      await _httpApiService.startAP(ssid, password);
      _hotspotEnabled = true;
      _errorMessage = null;
      _debugProvider.addHttpLog('Hotspot started');
      notifyListeners();
    } catch (error) {
      _errorMessage = error.toString();
      _debugProvider.addHttpLog('Start hotspot failed', details: error);
      notifyListeners();
    } finally {
      _setLoading(false);
    }
  }

  Future<void> stopHotspot() async {
    _setLoading(true);
    _debugProvider.addHttpLog('Stop hotspot');
    try {
      await _httpApiService.stopAP();
      _hotspotEnabled = false;
      _errorMessage = null;
      _debugProvider.addHttpLog('Hotspot stopped');
      notifyListeners();
    } catch (error) {
      _errorMessage = error.toString();
      _debugProvider.addHttpLog('Stop hotspot failed', details: error);
      notifyListeners();
    } finally {
      _setLoading(false);
    }
  }

  void _setLoading(bool value) {
    _isLoading = value;
    notifyListeners();
  }

  @override
  void dispose() {
    unawaited(_wifiSubscription.cancel());
    super.dispose();
  }
}
