import 'package:flutter/foundation.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import '../models/device.dart';
import '../models/user_info.dart';
import '../models/static_talkgroup.dart';
import '../models/device_profile.dart';
import 'brandmeister_client.dart';

class AuthenticationManager extends ChangeNotifier {
  static const String _tokenKey = 'apiToken';

  late final FlutterSecureStorage _storage;

  AuthenticationManager() {
    _initStorage();
    _loadToken();
  }

  void _initStorage() {
    _storage = const FlutterSecureStorage(
      aOptions: AndroidOptions(
        encryptedSharedPreferences: true,
      ),
      iOptions: IOSOptions(
        accessibility: KeychainAccessibility.first_unlock,
      ),
      webOptions: WebOptions(
        dbName: 'bmmanager',
        publicKey: 'bmmanager_public_key',
      ),
    );
  }

  bool _isAuthenticated = false;
  bool _isInitializing = true;
  String _apiToken = '';
  UserInfo? _userInfo;
  BrandmeisterClient? _client;

  bool get isAuthenticated => _isAuthenticated;
  bool get isInitializing => _isInitializing;
  String get apiToken => _apiToken;
  UserInfo? get userInfo => _userInfo;

  Future<void> _loadToken() async {
    try {
      final token = await _storage.read(key: _tokenKey);
      if (token != null && token.isNotEmpty) {
        _apiToken = token;
        _client = BrandmeisterClient(apiToken: token);
        // Try to verify the token is still valid
        try {
          _userInfo = await _client!.whoami();
          _isAuthenticated = true;
        } catch (e) {
          // Token is invalid, clear it
          await logout();
        }
      }
    } catch (e) {
      debugPrint('Error loading token: $e');
    } finally {
      _isInitializing = false;
      notifyListeners();
    }
  }

  Future<void> _saveToken(String token) async {
    try {
      await _storage.write(key: _tokenKey, value: token);
      _apiToken = token;
      _client = BrandmeisterClient(apiToken: token);
    } catch (e) {
      throw BrandmeisterError('Failed to save token: $e');
    }
  }

  Future<UserInfo> verifyAndSaveToken(String token) async {
    if (token.isEmpty) {
      throw BrandmeisterError('Token cannot be empty');
    }

    final tempClient = BrandmeisterClient(apiToken: token);
    final user = await tempClient.whoami();

    await _saveToken(token);
    _userInfo = user;
    _isAuthenticated = true;
    notifyListeners();

    return user;
  }

  Future<void> logout() async {
    try {
      await _storage.delete(key: _tokenKey);
      _apiToken = '';
      _userInfo = null;
      _isAuthenticated = false;
      _client = null;
      notifyListeners();
    } catch (e) {
      debugPrint('Error during logout: $e');
    }
  }

  Future<void> refreshUserInfo() async {
    if (_client == null) return;

    try {
      _userInfo = await _client!.whoami();
      notifyListeners();
    } catch (e) {
      debugPrint('Error refreshing user info: $e');
      rethrow;
    }
  }

  // Device Operations
  Future<List<Device>> getDevices() async {
    if (_client == null || _userInfo == null) {
      throw BrandmeisterError('Not authenticated');
    }

    if (_userInfo!.username == null) {
      throw BrandmeisterError('Username not available');
    }

    return await _client!.getDevicesByCallsign(_userInfo!.username!);
  }

  Future<Device> getDevice(int dmrId) async {
    if (_client == null) {
      throw BrandmeisterError('Not authenticated');
    }

    return await _client!.getDevice(dmrId);
  }

  Future<DeviceProfile> getDeviceProfile(int dmrId) async {
    if (_client == null) {
      throw BrandmeisterError('Not authenticated');
    }

    return await _client!.getDeviceProfile(dmrId);
  }

  Future<List<StaticTalkgroup>> getTalkgroups(int dmrId) async {
    if (_client == null) {
      throw BrandmeisterError('Not authenticated');
    }

    return await _client!.getDeviceTalkgroups(dmrId);
  }

  Future<Map<String, String>> getAllTalkgroups() async {
    if (_client == null) {
      throw BrandmeisterError('Not authenticated');
    }

    return await _client!.getTalkgroups();
  }

  Future<void> linkTalkgroup({
    required int talkgroupId,
    required int dmrId,
    required int timeslot,
  }) async {
    if (_client == null) {
      throw BrandmeisterError('Not authenticated');
    }

    await _client!.addTalkgroup(
      dmrId: dmrId,
      talkgroupId: talkgroupId,
      slot: timeslot,
    );
  }

  Future<void> unlinkTalkgroup({
    required String talkgroupId,
    required int dmrId,
    required String timeslot,
  }) async {
    if (_client == null) {
      throw BrandmeisterError('Not authenticated');
    }

    final tgId = int.tryParse(talkgroupId);
    final slot = int.tryParse(timeslot);

    if (tgId == null || slot == null) {
      throw BrandmeisterError('Invalid talkgroup ID or timeslot');
    }

    await _client!.removeTalkgroup(
      dmrId: dmrId,
      talkgroupId: tgId,
      slot: slot,
    );
  }

  Future<void> dropAutoStaticGroup(int dmrId) async {
    if (_client == null) {
      throw BrandmeisterError('Not authenticated');
    }

    await _client!.dropAutoStaticGroup(dmrId);
  }
}
