الكود
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:isolate';
import 'dart:math';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:micro_panel/HomePage.dart';
import 'package:path_provider/path_provider.dart';
import 'package:router_os_client/router_os_client.dart';

void main() {
  runApp(const MicroPanelApp());
}

class MicroPanelApp extends StatelessWidget {
  const MicroPanelApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Micro Panel',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        fontFamily: 'Tajawal',
        useMaterial3: true,
      ),
      home: const SplashScreen(),
    );
  }
}

class SplashScreen extends StatefulWidget {
  const SplashScreen({super.key});

  @override
  State<SplashScreen> createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen>
    with SingleTickerProviderStateMixin {
  late final AnimationController _controller;
  late final Animation<double> _scaleAnimation;
  late final Animation<double> _fadeAnimation;
  late final Animation<Offset> _slideAnimation;

  @override
  void initState() {
    super.initState();
    _initAnimations();
    _navigateToLogin();
  }

  void _initAnimations() {
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 800),
    );
    _scaleAnimation = Tween<double>(begin: 0.9, end: 1.0).animate(
      CurvedAnimation(parent: _controller, curve: Curves.easeInOutQuart),
    );
    _fadeAnimation = Tween<double>(
      begin: 0.0,
      end: 1.0,
    ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeIn));
    _slideAnimation = Tween<Offset>(
      begin: const Offset(0.0, 0.3),
      end: Offset.zero,
    ).animate(CurvedAnimation(parent: _controller, curve: Curves.easeOutQuart));
    _controller.forward();
  }

  void _navigateToLogin() {
    Future.delayed(const Duration(seconds: 1), () {
      if (mounted) {
        Navigator.pushReplacement(
          context,
          PageRouteBuilder(
            pageBuilder: (_, __, ___) => const Login(),
            transitionsBuilder:
                (_, animation, __, child) =>
                    FadeTransition(opacity: animation, child: child),
            transitionDuration: const Duration(milliseconds: 500),
          ),
        );
      }
    });
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFF0A192F),
      body: Stack(
        children: [_buildBackgroundCircles(), Center(child: _buildContent())],
      ),
    );
  }

  Widget _buildBackgroundCircles() {
    return Stack(
      children: [
        Positioned(
          top: -50,
          right: -50,
          child: Container(
            width: 200,
            height: 200,
            decoration: BoxDecoration(
              shape: BoxShape.circle,
              color: Color(0xFF1E3A8A).withOpacity(0.2),
            ),
          ),
        ),
        Positioned(
          bottom: -100,
          left: -100,
          child: Container(
            width: 300,
            height: 300,
            decoration: BoxDecoration(
              shape: BoxShape.circle,
              color: Color(0xFF1E3A8A).withOpacity(0.1),
            ),
          ),
        ),
      ],
    );
  }

  Widget _buildContent() {
    return Padding(
      padding: const EdgeInsets.all(20.0),
      child: Directionality(
        textDirection: TextDirection.rtl,
        child: ScaleTransition(
          scale: _scaleAnimation,
          child: FadeTransition(
            opacity: _fadeAnimation,
            child: SlideTransition(
              position: _slideAnimation,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  _buildAppLogo(),
                  const SizedBox(height: 20),
                  _buildAppTitle(),
                  const SizedBox(height: 5),
                  _buildAppSubtitle(),
                  const SizedBox(height: 30),
                  _buildLoadingIndicator(),
                  const SizedBox(height: 15),
                  _buildLoadingText(),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildAppLogo() {
    return Hero(
      tag: 'app-logo',
      child: Container(
        padding: const EdgeInsets.all(15),
        decoration: BoxDecoration(
          color: Colors.white.withOpacity(0.1),
          shape: BoxShape.circle,
          border: Border.all(color: Colors.white.withOpacity(0.2), width: 1.5),
        ),
        child: Image.asset(
          'assets/img/control.png',
          height: 80,
          color: Colors.white.withOpacity(0.9),
        ),
      ),
    );
  }

  Widget _buildAppTitle() {
    return const Text(
      'Micro Panel',
      style: TextStyle(
        fontSize: 30,
        fontWeight: FontWeight.bold,
        color: Colors.white,
        letterSpacing: 1.2,
      ),
    );
  }

  Widget _buildAppSubtitle() {
    return const Text(
      'نظام إدارة أجهزة الميكروتك',
      style: TextStyle(color: Colors.white70, fontSize: 14),
    );
  }

  Widget _buildLoadingIndicator() {
    return SizedBox(
      width: 180,
      child: ClipRRect(
        borderRadius: BorderRadius.circular(8),
        child: LinearProgressIndicator(
          valueColor: AlwaysStoppedAnimation<Color>(
            Colors.white.withOpacity(0.9),
          ),
          backgroundColor: Colors.white.withOpacity(0.2),
          minHeight: 5,
        ),
      ),
    );
  }

  Widget _buildLoadingText() {
    return const Text(
      'جاري التحميل...',
      style: TextStyle(color: Colors.white, fontSize: 14),
    );
  }
}

class MikroTikApi {
  Socket? _socket;
  final String host;
  final int port;
  final String user, pass;
  final _recvBuffer = <int>[];

  MikroTikApi({
    required this.host,
    this.port = 8728,
    required this.user,
    required this.pass,
  });

  Future<void> connect() async {
    _socket = await Socket.connect(host, port);
    _socket!.listen(_onData, onError: _onError, onDone: _onDone);
  }

  void _onData(Uint8List chunk) {
    _recvBuffer.addAll(chunk);
  }

  void _onError(e) => throw 'Socket error: $e';
  void _onDone() => _socket = null;

  Uint8List _encodeWord(String s) {
    final b = utf8.encode(s);
    final len = b.length;
    final header = <int>[];
    if (len < 0x80)
      header.add(len);
    else if (len < 0x4000) {
      header.add((len >> 8) | 0x80);
      header.add(len & 0xFF);
    } else if (len < 0x200000) {
      header.add((len >> 16) | 0xC0);
      header.add((len >> 8) & 0xFF);
      header.add(len & 0xFF);
    } else {
      header.add((len >> 24) | 0xE0);
      header.add((len >> 16) & 0xFF);
      header.add((len >> 8) & 0xFF);
      header.add(len & 0xFF);
    }
    return Uint8List.fromList([...header, ...b]);
  }

  Future<void> sendSentence(List<String> words) async {
    final out = <int>[];
    for (var w in words) out.addAll(_encodeWord(w));
    out.add(0);
    _socket!.add(out);
    await _socket!.flush();
  }

  Future<List<List<String>>> _readSentences() async {
    final sentences = <List<String>>[];
    while (true) {
      await Future.delayed(Duration(milliseconds: 100));

      // تحقق من وجود بيانات في المخزن المؤقت
      if (_recvBuffer.isEmpty) continue;

      final buf = List<int>.from(_recvBuffer);
      try {
        var i = 0;
        while (i < buf.length) {
          final sentence = <String>[];
          while (i < buf.length && buf[i] != 0) {
            int len = buf[i++];
            int bytesCount = 1;

            if (len & 0x80 != 0) {
              bytesCount =
                  (len & 0xC0) == 0x80
                      ? 2
                      : (len & 0xE0) == 0xC0
                      ? 3
                      : 4;
              len = ((len & 0x7F) << ((bytesCount - 1) * 8));

              for (int j = 0; j < bytesCount - 1 && i < buf.length; j++) {
                len |= buf[i++] << ((bytesCount - 2 - j) * 8);
              }
            }

            if (i + len > buf.length) {
              // البيانات غير مكتملة، نعيد المؤشر ونخرج
              i -= bytesCount;
              break;
            }

            sentence.add(utf8.decode(buf.sublist(i, i + len)));
            i += len;
          }

          if (i < buf.length && buf[i] == 0) {
            i++; // تخطي حرف الإنهاء
            sentences.add(sentence);

            // إذا كانت الجملة تحتوي على !done، نخرج
            if (sentence.isNotEmpty && sentence.first == '!done') {
              _recvBuffer.removeRange(0, i);
              return sentences;
            }
          } else {
            break; // بيانات غير مكتملة
          }
        }

        _recvBuffer.removeRange(0, i);

        // إذا وجدنا جملة !done نعود بالنتيجة
        if (sentences.any((s) => s.isNotEmpty && s.first == '!done')) {
          return sentences;
        }
      } catch (e) {
        print('Error parsing sentences: $e');
        break;
      }
    }
    return sentences;
  }

  Future<bool> login() async {
    await sendSentence(['/login', '=name=$user', '=password=$pass']);
    final resp = await _readSentences();
    return resp.any((s) => s.first == '!done');
  }

  Future<List<Map<String, String>>> fetchHotspotUsers() async {
    await sendSentence(['/ip/hotspot/user/print']);
    final resp = await _readSentences();
    return resp.where((s) => s.first == '!re').map((s) {
      final m = <String, String>{};
      for (var tok in s.skip(1)) {
        if (tok.startsWith('=')) {
          final idx = tok.indexOf('=', 1);
          if (idx != -1) {
            final key = tok.substring(1, idx);
            final value = tok.substring(idx + 1);
            m[key] = value;
          }
        }
      }

      return m;
    }).toList();
  }

  void close() => _socket?.destroy();
}

class Login extends StatefulWidget {
  const Login({super.key});

  @override
  State<Login> createState() => _LoginState();
}

class _LoginState extends State<Login> {
  final _formKey = GlobalKey<FormState>();
  final List<TextEditingController> _ipControllers = List.generate(
    4,
    (index) => TextEditingController(),
  );
  final List<FocusNode> _ipFocusNodes = List.generate(
    4,
    (index) => FocusNode(),
  );
  final _usernameController = TextEditingController();
  final _passwordController = TextEditingController();
  final _portController = TextEditingController(text: '8728');
  bool _isLoading = false;
  bool _obscurePassword = true;
  bool _autoFetchEnabled = false;
  bool _hasSavedCredentials = false;
  Map<String, dynamic>? _savedCredentials;

  @override
  void initState() {
    super.initState();
    _loadSavedCredentials();
    for (int i = 0; i < _ipFocusNodes.length; i++) {
      _ipFocusNodes[i].onKey = (node, event) {
        if (event.logicalKey == LogicalKeyboardKey.tab) {
          if (event.isShiftPressed) return KeyEventResult.ignored;
          if (i > 0) {
            FocusScope.of(context).requestFocus(_ipFocusNodes[i - 1]);
          } else {
            FocusScope.of(context).requestFocus(_ipFocusNodes[0]);
          }
          return KeyEventResult.handled;
        }
        return KeyEventResult.ignored;
      };
    }
  }

  Future<void> _loadSavedCredentials() async {
    try {
      final directory = await getApplicationDocumentsDirectory();
      final file = File('${directory.path}/login_credentials.json');
      if (await file.exists()) {
        final contents = await file.readAsString();
        final credentials = jsonDecode(contents);
        if (credentials != null && credentials is Map) {
          setState(() {
            _savedCredentials = Map<String, dynamic>.from(credentials);
            _hasSavedCredentials = true;
            final savedIp = _savedCredentials?['ip']?.split('.') ?? [];
            for (int i = 0; i < 4 && i < savedIp.length; i++) {
              _ipControllers[i].text = savedIp[i];
            }
            _usernameController.text = _savedCredentials?['username'] ?? '';
            _passwordController.text = _savedCredentials?['password'] ?? '';
            _portController.text = _savedCredentials?['port'] ?? '8728';
          });
          print('done');
        }
      }
    } catch (e) {}
  }

  Future<void> _saveCredentials() async {
    try {
      final directory = await getApplicationDocumentsDirectory();
      final file = File('${directory.path}/login_credentials.json');
      final ip = _ipControllers.map((c) => c.text).join('.');
      final credentials = {
        'ip': ip,
        'username': _usernameController.text,
        'password': _passwordController.text,
        'port': _portController.text,
      };
      await file.writeAsString(jsonEncode(credentials));
      setState(() {
        _hasSavedCredentials = true;
        _savedCredentials = credentials;
      });
    } catch (e) {}
  }

  @override
  void dispose() {
    for (var controller in _ipControllers) controller.dispose();
    for (var node in _ipFocusNodes) node.dispose();
    _usernameController.dispose();
    _passwordController.dispose();
    _portController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final size = MediaQuery.of(context).size;
    final isMobile = size.width < 600;
    return Directionality(
      textDirection: TextDirection.rtl,
      child: Scaffold(
        backgroundColor: const Color(0xFF0A192F),
        body: SafeArea(
          child: LayoutBuilder(
            builder: (context, constraints) {
              if (constraints.maxWidth > 800) {
                return Row(
                  children: [
                    Expanded(
                      flex: 5,
                      child: Container(
                        padding: const EdgeInsets.symmetric(horizontal: 40),
                        color: const Color(0xFF0A192F),
                        child: Center(child: _buildLoginForm(isMobile)),
                      ),
                    ),
                    Expanded(
                      flex: 6,
                      child: Container(
                        decoration: const BoxDecoration(
                          gradient: LinearGradient(
                            begin: Alignment.topCenter,
                            end: Alignment.bottomCenter,
                            colors: [Color(0xFF1E3A8A), Color(0xFF0A192F)],
                          ),
                        ),
                        child: Center(
                          child: Column(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: [
                              Icon(
                                Icons.router_outlined,
                                size: 150,
                                color: Colors.white,
                              ),
                              const SizedBox(height: 20),
                              const Text(
                                'مرحبًا بك في Micro Panel',
                                style: TextStyle(
                                  color: Colors.white,
                                  fontSize: 28,
                                  fontWeight: FontWeight.bold,
                                ),
                              ),
                              const SizedBox(height: 10),
                              const Text(
                                'نظام إدارة أجهزة الميكروتك\n'
                                'بكل سهولة واحترافية',
                                textAlign: TextAlign.center,
                                style: TextStyle(
                                  color: Colors.white70,
                                  fontSize: 18,
                                ),
                              ),
                            ],
                          ),
                        ),
                      ),
                    ),
                  ],
                );
              } else {
                return CustomScrollView(
                  slivers: [
                    SliverFillRemaining(
                      hasScrollBody: false,
                      child: Container(
                        padding: const EdgeInsets.symmetric(
                          horizontal: 20,
                          vertical: 40,
                        ),
                        child: _buildLoginForm(isMobile),
                      ),
                    ),
                  ],
                );
              }
            },
          ),
        ),
      ),
    );
  }

  Widget _buildLoginForm(bool isMobile) {
    return Form(
      key: _formKey,
      child: Column(
        children: [
          _buildAppHeader(isMobile),
          const SizedBox(height: 30),
          _buildIpFields(),
          const SizedBox(height: 12),
          _buildUsernameField(),
          const SizedBox(height: 12),
          _buildPasswordField(),
          const SizedBox(height: 12),
          _buildPortField(),
          const SizedBox(height: 15),
          _buildAutoFetchCheckbox(),
          const SizedBox(height: 25),
          _buildLoginButton(),
          const SizedBox(height: 15),
        ],
      ),
    );
  }

  Widget _buildAppHeader(bool isMobile) {
    return Column(
      children: [
        Hero(
          tag: 'app-icon',
          child: Icon(
            Icons.router_outlined,
            size: isMobile ? 80 : 100,
            color: Colors.white,
          ),
        ),
        const SizedBox(height: 10),
        const Text(
          'Micro Panel',
          style: TextStyle(
            fontSize: 24,
            fontWeight: FontWeight.bold,
            color: Colors.white,
          ),
        ),
        const SizedBox(height: 4),
        const Text(
          'نظام إدارة أجهزة الميكروتك',
          style: TextStyle(color: Colors.white70, fontSize: 13),
        ),
      ],
    );
  }

  Widget _buildIpFields() {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Padding(
          padding: const EdgeInsets.only(bottom: 8.0, right: 8.0),
          child: Text('عنوان IP', style: TextStyle(color: Colors.white70)),
        ),
        Row(
          textDirection: TextDirection.ltr,
          children: [
            for (int i = 0; i <= 3; i++) ...[
              Expanded(
                child: TextFormField(
                  controller: _ipControllers[i],
                  validator: (value) => _validateIpPart(value, i),
                  style: const TextStyle(color: Colors.white),
                  decoration: InputDecoration(
                    labelStyle: const TextStyle(color: Colors.white70),
                    filled: true,
                    fillColor: Colors.white.withOpacity(0.1),
                    contentPadding: const EdgeInsets.symmetric(
                      vertical: 14,
                      horizontal: 16,
                    ),
                    enabledBorder: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(10),
                      borderSide: BorderSide(
                        color: Colors.white.withOpacity(0.2),
                      ),
                    ),
                    focusedBorder: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(10),
                      borderSide: const BorderSide(color: Color(0xFF3B82F6)),
                    ),
                  ),
                  keyboardType: TextInputType.number,
                  textInputAction:
                      i < 3 ? TextInputAction.next : TextInputAction.done,
                  inputFormatters: [
                    FilteringTextInputFormatter.digitsOnly,
                    LengthLimitingTextInputFormatter(3),
                  ],
                  focusNode: _ipFocusNodes[i],
                  onChanged: (value) {
                    if (value.length == 3 && i < 3) {
                      FocusScope.of(context).requestFocus(_ipFocusNodes[i + 1]);
                    }
                  },
                  textAlign: TextAlign.center,
                ),
              ),
              if (i < 3)
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 4.0),
                  child: Text('.', style: TextStyle(color: Colors.white)),
                ),
            ],
          ],
        ),
      ],
    );
  }

  Widget _buildUsernameField() {
    return TextFormField(
      controller: _usernameController,
      validator: (value) => _validateRequired(value, 'اسم المستخدم'),
      style: const TextStyle(color: Colors.white),
      decoration: InputDecoration(
        labelText: 'اسم المستخدم',
        labelStyle: const TextStyle(color: Colors.white70),
        prefixIcon: Icon(Icons.person_outline, color: Colors.white70),
        filled: true,
        fillColor: Colors.white.withOpacity(0.1),
        contentPadding: const EdgeInsets.symmetric(
          vertical: 14,
          horizontal: 16,
        ),
        enabledBorder: OutlineInputBorder(
          borderRadius: BorderRadius.circular(10),
          borderSide: BorderSide(color: Colors.white.withOpacity(0.2)),
        ),
        focusedBorder: OutlineInputBorder(
          borderRadius: BorderRadius.circular(10),
          borderSide: const BorderSide(color: Color(0xFF3B82F6)),
        ),
      ),
      textInputAction: TextInputAction.next,
      onFieldSubmitted:
          (_) => FocusScope.of(
            context,
          ).requestFocus(_passwordController as FocusNode?),
    );
  }

  Widget _buildPasswordField() {
    return TextFormField(
      controller: _passwordController,
      obscureText: _obscurePassword,
      validator:
          (value) =>
              value == null || value.isEmpty ? 'يرجى إدخال كلمة المرور' : null,
      style: const TextStyle(color: Colors.white),
      decoration: InputDecoration(
        labelText: 'كلمة المرور',
        labelStyle: const TextStyle(color: Colors.white70),
        prefixIcon: Icon(Icons.lock_outline, color: Colors.white70),
        suffixIcon: IconButton(
          icon: Icon(
            _obscurePassword ? Icons.visibility_off : Icons.visibility,
            color: Colors.white70,
          ),
          onPressed: () => setState(() => _obscurePassword = !_obscurePassword),
        ),
        filled: true,
        fillColor: Colors.white.withOpacity(0.1),
        contentPadding: const EdgeInsets.symmetric(
          vertical: 14,
          horizontal: 16,
        ),
        enabledBorder: OutlineInputBorder(
          borderRadius: BorderRadius.circular(10),
          borderSide: BorderSide(color: Colors.white.withOpacity(0.2)),
        ),
        focusedBorder: OutlineInputBorder(
          borderRadius: BorderRadius.circular(10),
          borderSide: const BorderSide(color: Color(0xFF3B82F6)),
        ),
      ),
      textInputAction: TextInputAction.next,
      onFieldSubmitted: (_) => _connectToMikrotik(),
    );
  }

  Widget _buildPortField() {
    return TextFormField(
      controller: _portController,
      validator: _validatePort,
      style: const TextStyle(color: Colors.white),
      decoration: InputDecoration(
        labelText: 'المنفذ',
        labelStyle: const TextStyle(color: Colors.white70),
        prefixIcon: Icon(Icons.settings_ethernet, color: Colors.white70),
        filled: true,
        fillColor: Colors.white.withOpacity(0.1),
        contentPadding: const EdgeInsets.symmetric(
          vertical: 14,
          horizontal: 16,
        ),
        enabledBorder: OutlineInputBorder(
          borderRadius: BorderRadius.circular(10),
          borderSide: BorderSide(color: Colors.white.withOpacity(0.2)),
        ),
        focusedBorder: OutlineInputBorder(
          borderRadius: BorderRadius.circular(10),
          borderSide: const BorderSide(color: Color(0xFF3B82F6)),
        ),
      ),
      keyboardType: TextInputType.number,
      onFieldSubmitted: (_) => _connectToMikrotik(),
    );
  }

  Widget _buildAutoFetchCheckbox() {
    return Row(
      children: [
        Transform.scale(
          scale: 0.8,
          child: Checkbox(
            value: _autoFetchEnabled,
            onChanged:
                (value) => setState(() => _autoFetchEnabled = value ?? false),
            fillColor: MaterialStateProperty.resolveWith<Color>((states) {
              if (states.contains(MaterialState.selected))
                return const Color(0xFF3B82F6);
              return Colors.transparent;
            }),
            side: BorderSide(color: Colors.white.withOpacity(0.5)),
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(4),
            ),
          ),
        ),
        const SizedBox(width: 4),
        Text(
          'تحميل مستخدمي الهوتسبوت تلقائياً',
          style: TextStyle(color: Colors.white70, fontSize: 13),
        ),
      ],
    );
  }

  Widget _buildLoginButton() {
    return SizedBox(
      width: double.infinity,
      height: 48,
      child: ElevatedButton(
        onPressed: _isLoading ? null : _connectToMikrotik,
        style: ElevatedButton.styleFrom(
          backgroundColor: _isLoading ? Colors.grey : const Color(0xFF3B82F6),
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(10),
          ),
        ),
        child:
            _isLoading
                ? const SizedBox(
                  width: 20,
                  height: 20,
                  child: CircularProgressIndicator(
                    color: Colors.white,
                    strokeWidth: 3,
                  ),
                )
                : Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: const [
                    Icon(Icons.login, color: Colors.white, size: 20),
                    SizedBox(width: 8),
                    Text(
                      'تسجيل الدخول',
                      style: TextStyle(fontSize: 15, color: Colors.white),
                    ),
                  ],
                ),
      ),
    );
  }

  Future<void> _connectToMikrotik() async {
    if (!_formKey.currentState!.validate()) return;
    setState(() => _isLoading = true);
    try {
      final ip = _ipControllers.map((c) => c.text).join('.');
      final port = int.tryParse(_portController.text) ?? 8728;

      final client = RouterOSClient(
        address: ip,
        port: port,
        user: _usernameController.text,
        password: _passwordController.text,
        useSsl: false,
        verbose: false,
      );
      final isLoggedIn = await client.login();

      if (!isLoggedIn) {
        throw Exception("فشل تسجيل الدخول إلى جهاز الميكروتك");
      }

      await _saveCredentials();

      if (_autoFetchEnabled) {
        if (mounted) {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder:
                  (context) => DataLoadingScreen(
                    client: client,
                    host: ip, // هذا هو عنوان IP من حقول الإدخال
                    port: port, // هذا هو المنفذ من حقل الإدخال
                    username: _usernameController.text,
                    password: _passwordController.text,
                  ),
            ),
          );
        }
      } else {
        if (mounted) {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => RouterDetailsPage(client: client),
            ),
          );
        }
      }
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('خطأ في الاتصال: ${e.toString()}')),
        );
      }
    } finally {
      if (mounted) {
        setState(() => _isLoading = false);
      }
    }
  }

  String? _validateRequired(String? value, String fieldName) {
    if (value == null || value.isEmpty) return 'يرجى إدخال $fieldName';
    final regex = RegExp(r'^[a-zA-Z0-9]+$');
    if (!regex.hasMatch(value))
      return 'يجب أن يحتوي $fieldName على أحرف إنجليزية وأرقام فقط';
    return null;
  }

  String? _validateIpPart(String? value, int part) {
    if (value == null || value.isEmpty) return 'يرجى إدخال جزء $part من الـ IP';
    if (!RegExp(r'^\d+$').hasMatch(value))
      return 'يجب أن يحتوي جزء $part على أرقام فقط';
    final num = int.tryParse(value) ?? 0;
    if (num < 0 || num > 255) return 'يجب أن يكون جزء $part بين 0 و 255';
    return null;
  }

  String? _validatePort(String? value) {
    if (value == null || value.isEmpty) return 'يرجى إدخال المنفذ';
    if (!RegExp(r'^\d+$').hasMatch(value))
      return 'يجب أن يحتوي المنفذ على أرقام فقط';
    final port = int.tryParse(value) ?? 0;
    if (port <= 0 || port > 65535) return 'يجب أن يكون المنفذ بين 1 و 65535';
    return null;
  }
}

class DataLoadingScreen extends StatefulWidget {
  final MikroTikApi? api; // يمكن إزالته لاحقًا إذا لم تعد تحتاج إليه
  final String host;
  final int port;
  final String username;
  final String password;
  final RouterOSClient client;

  const DataLoadingScreen({
    super.key,
    required this.client,
    required this.host,
    required this.port,
    required this.username,
    required this.password,
    this.api,
  });

  @override
  State<DataLoadingScreen> createState() => _DataLoadingScreenState();
}

class _DataLoadingScreenState extends State<DataLoadingScreen>
    with SingleTickerProviderStateMixin {
  bool _loading = true;
  int _userCount = 0;
  int _currentProgress = 0;
  bool _hasError = false;
  String _errorMessage = '';
  late final StreamController<int> _progressController;
  late final Stream<int> _progressStream;
  Isolate? _isolate;
  ReceivePort? _receivePort;
  int _totalUsers = 0;
  int _batchSize = 500;
  Timer? _simulationTimer;
  Random _random = Random();
  bool _realDataStarted = false;

  @override
  void initState() {
    super.initState();
    _progressController = StreamController<int>();
    _progressStream = _progressController.stream;
    _initDataLoading();
  }

  Future<void> _initDataLoading() async {
    try {
      await _startIsolate();
    } catch (e) {
      _handleError('فشل في بدء عملية الجلب: ${e.toString()}');
      print('$e');
    }
  }

  Future<void> _startIsolate() async {
    _receivePort = ReceivePort();

    await Isolate.spawn(
      _fetchUsersInBackground,
      _IsolateData(
        host: widget.host,
        port: widget.port,
        username: widget.username,
        password: widget.password,
        sendPort: _receivePort!.sendPort,
      ),
      onError: _receivePort!.sendPort,
      onExit: _receivePort!.sendPort,
    );
    _receivePort!.listen(_handleIsolateMessage);
  }

  void _handleIsolateMessage(dynamic message) {
    if (message is _ProgressUpdate) {
      if (!_realDataStarted) {
        _startSimulation(message.total);
        setState(() => _realDataStarted = true);
      }
      _updateProgress(message.current, message.total);
    } else if (message is List) {
      // نتأكد من أن القائمة تحتوي على بيانات
      if (message.isNotEmpty && message.first is Map<String, dynamic>) {
        _handleSuccess(message.cast<Map<String, dynamic>>());
      } else {
        _handleError('لم يتم استلام بيانات صحيحة من الـ Isolate');
      }
    } else if (message is String) {
      _handleError(message);
    } else {
      _handleError('استلام رسالة غير معروفة من الـ Isolate');
    }
  }

  void _startSimulation(int totalUsers) {
    _simulationTimer?.cancel();
    _totalUsers = totalUsers;
    _currentProgress = 0;
    _simulationTimer = Timer.periodic(Duration(milliseconds: 300), (timer) {
      if (_currentProgress < _totalUsers) {
        _currentProgress += 1 + _random.nextInt(40);
        if (_currentProgress > _totalUsers) {
          _currentProgress = _totalUsers;
        }
        _progressController.add(_currentProgress);
      } else {
        timer.cancel();
      }
    });
  }

  void _updateProgress(int current, int total) {
    if (!mounted) return;
    setState(() {
      _currentProgress = current;
      _totalUsers = total;
    });
    _progressController.add(current);
  }

  Future<void> _handleSuccess(List<Map<String, dynamic>> users) async {
    try {
      final directory = await getApplicationDocumentsDirectory();
      final file = File('${directory.path}/hotspot_users.json');
      await file.writeAsBytes(utf8.encode(jsonEncode(users)));
      if (mounted) {
        setState(() {
          _userCount = users.length;
          _loading = false;
        });
        Navigator.pushReplacement(
          context,
          MaterialPageRoute(
            builder: (context) => RouterDetailsPage(client: widget.client),
          ),
        );
      }
    } catch (e) {
      _handleError('فشل في حفظ البيانات: ${e.toString()}');
    }
  }

  void _handleError(String message) {
    if (!mounted) return;
    _simulationTimer?.cancel();
    setState(() {
      _hasError = true;
      _errorMessage = message;
      _loading = false;
    });
    _cleanUpResources();
  }

  void _cleanUpResources() {
    _simulationTimer?.cancel();
    _progressController.close();
    _isolate?.kill(priority: Isolate.immediate);
    _receivePort?.close();
  }

  static Future<void> _fetchUsersInBackground(_IsolateData isolateData) async {
    final sendPort = isolateData.sendPort;
    try {
      final api = MikroTikApi(
        host: isolateData.host,
        port: isolateData.port,
        user: isolateData.username,
        pass: isolateData.password,
      );

      await api.connect();
      bool loggedIn = await api.login();

      if (!loggedIn) {
        sendPort.send("فشل تسجيل الدخول إلى جهاز الميكروتك");
        return;
      }

      final users = await api.fetchHotspotUsers();
      sendPort.send(_ProgressUpdate(users.length, users.length));
      sendPort.send(users);
    } catch (e, stackTrace) {
      sendPort.send('حدث خطأ أثناء جلب البيانات:\n$e\n$stackTrace');
    }
  }

  @override
  void dispose() {
    _cleanUpResources();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFF0A192F),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              if (_hasError)
                _buildErrorWidget()
              else if (_loading)
                _buildLoadingWidget()
              else
                _buildSuccessWidget(),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildErrorWidget() {
    return Column(
      children: [
        const Icon(Icons.error_outline, color: Colors.red, size: 40),
        const SizedBox(height: 16),
        Text(
          _errorMessage,
          style: const TextStyle(color: Colors.white, fontSize: 15),
          textAlign: TextAlign.center,
        ),
        const SizedBox(height: 20),
        ElevatedButton(
          onPressed: () => Navigator.pop(context),
          style: ElevatedButton.styleFrom(
            backgroundColor: const Color(0xFF3B82F6),
            padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 10),
          ),
          child: const Text('العودة', style: TextStyle(fontSize: 15)),
        ),
      ],
    );
  }

  Widget _buildLoadingWidget() {
    int displayedProgress = 0;
    int displayedTotal = _totalUsers;
    double displayedPercentage = 0.0;

    void updateDisplayedValues() {
      final progressDiff = _currentProgress - displayedProgress;
      final totalDiff = _totalUsers - displayedTotal;
      if (progressDiff > 0) {
        displayedProgress += (progressDiff / 5).ceil();
        if (displayedProgress > _currentProgress) {
          displayedProgress = _currentProgress;
        }
      }
      if (totalDiff > 0) {
        displayedTotal += (totalDiff / 3).ceil();
        if (displayedTotal > _totalUsers) {
          displayedTotal = _totalUsers;
        }
      }
      if (displayedTotal > 0) {
        displayedPercentage = (displayedProgress / displayedTotal * 100);
      }
    }

    return Column(
      children: [
        const SizedBox(
          width: 30,
          height: 30,
          child: CircularProgressIndicator(color: Colors.white, strokeWidth: 3),
        ),
        const SizedBox(height: 16),
        Text(
          _realDataStarted
              ? 'جاري جلب بيانات المستخدمين...'
              : 'جاري تهئية عملية الجلب...',
          style: const TextStyle(color: Colors.white, fontSize: 16),
        ),
        const SizedBox(height: 8),
        StreamBuilder<int>(
          stream: _progressStream,
          builder: (context, snapshot) {
            updateDisplayedValues();
            return Column(
              children: [
                Text(
                  '$displayedProgress من $displayedTotal (${displayedPercentage.toStringAsFixed(1)}%)',
                  style: const TextStyle(color: Colors.white70, fontSize: 13),
                ),
                const SizedBox(height: 16),
                LinearProgressIndicator(
                  value:
                      displayedTotal > 0
                          ? displayedProgress / displayedTotal
                          : 0,
                  backgroundColor: Colors.white.withOpacity(0.2),
                  valueColor: const AlwaysStoppedAnimation<Color>(
                    Colors.blueAccent,
                  ),
                  minHeight: 6,
                ),
              ],
            );
          },
        ),
      ],
    );
  }

  Widget _buildSuccessWidget() {
    return Column(
      children: [
        const Icon(Icons.check_circle_outline, color: Colors.green, size: 40),
        const SizedBox(height: 16),
        Text(
          'تم جلب $_userCount مستخدم بنجاح',
          style: const TextStyle(color: Colors.white, fontSize: 16),
        ),
        const SizedBox(height: 8),
        const SizedBox(
          width: 20,
          height: 20,
          child: CircularProgressIndicator(
            color: Colors.white70,
            strokeWidth: 2,
          ),
        ),
        const SizedBox(height: 8),
        const Text(
          'جاري التوجيه إلى لوحة التحكم...',
          style: TextStyle(color: Colors.white70, fontSize: 13),
        ),
      ],
    );
  }
}

class HotspotUsersPage extends StatefulWidget {
  final MikroTikApi api;
  const HotspotUsersPage({super.key, required this.api});

  @override
  _HotspotUsersPageState createState() => _HotspotUsersPageState();
}

class _HotspotUsersPageState extends State<HotspotUsersPage> {
  List<Map<String, String>> allUsers = [];
  bool loading = false;
  String error = '';
  bool showUsers = false;
  bool dataLoaded = false;
  int currentPage = 0;
  final int usersPerPage = 25;

  List<Map<String, String>> get paginatedUsers {
    final start = currentPage * usersPerPage;
    final end =
        (start + usersPerPage > allUsers.length)
            ? allUsers.length
            : start + usersPerPage;
    return allUsers.sublist(start, end);
  }

  int get totalPages => (allUsers.length / usersPerPage).ceil();

  Future<void> fetchUsers() async {
    setState(() {
      loading = true;
      error = '';
      dataLoaded = false;
      showUsers = false;
    });
    try {
      final users = await widget.api.fetchHotspotUsers();
      setState(() {
        allUsers = users;
        loading = false;
        dataLoaded = true;
        currentPage = 0;
      });
    } catch (e) {
      setState(() {
        error = 'خطأ: $e';
        loading = false;
      });
    }
  }

  @override
  void initState() {
    super.initState();
    fetchUsers();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('مستخدمي الهوتسبوت (${allUsers.length})'),
        backgroundColor: Colors.teal,
      ),
      body: Column(
        children: [
          SizedBox(height: 16),
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              ElevatedButton.icon(
                onPressed: loading ? null : fetchUsers,
                icon: Icon(Icons.download),
                label: Text('تحميل البيانات'),
              ),
              if (dataLoaded)
                ElevatedButton.icon(
                  onPressed: () => setState(() => showUsers = !showUsers),
                  icon: Icon(
                    showUsers ? Icons.visibility_off : Icons.visibility,
                  ),
                  label: Text(
                    showUsers ? 'إخفاء المستخدمين' : 'عرض المستخدمين',
                  ),
                ),
            ],
          ),
          SizedBox(height: 16),
          if (loading)
            Expanded(child: Center(child: CircularProgressIndicator())),
          if (error.isNotEmpty)
            Expanded(
              child: Center(
                child: Text(
                  error,
                  style: TextStyle(color: Colors.red, fontSize: 18),
                ),
              ),
            ),
          if (dataLoaded && !loading && error.isEmpty && showUsers)
            Expanded(
              child: Column(
                children: [
                  Expanded(
                    child: ListView.builder(
                      itemCount: paginatedUsers.length,
                      itemBuilder: (context, index) {
                        final user = paginatedUsers[index];
                        return Card(
                          margin: EdgeInsets.symmetric(
                            horizontal: 8,
                            vertical: 4,
                          ),
                          child: ListTile(
                            leading: Icon(Icons.person),
                            title: Text(
                              'الاسم: ${user['name'] ?? 'غير معروف'}',
                            ),
                            subtitle: Column(
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: [
                                Text(
                                  'الباقة: ${user['profile'] ?? 'غير محدد'}',
                                ),
                                if (user['comment'] != null)
                                  Text('ملاحظات: ${user['comment']}'),
                              ],
                            ),
                          ),
                        );
                      },
                    ),
                  ),
                  if (totalPages > 1)
                    Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          IconButton(
                            icon: Icon(Icons.arrow_back),
                            onPressed:
                                currentPage > 0
                                    ? () => setState(() => currentPage--)
                                    : null,
                          ),
                          Text('صفحة ${currentPage + 1} من $totalPages'),
                          IconButton(
                            icon: Icon(Icons.arrow_forward),
                            onPressed:
                                currentPage < totalPages - 1
                                    ? () => setState(() => currentPage++)
                                    : null,
                          ),
                        ],
                      ),
                    ),
                ],
              ),
            ),
        ],
      ),
    );
  }
}

class _IsolateData {
  final String host;
  final int port;
  final String username;
  final String password;
  final SendPort sendPort;

  _IsolateData({
    required this.host,
    required this.port,
    required this.username,
    required this.password,
    required this.sendPort,
  });
}

class _ProgressUpdate {
  final int current;
  final int total;

  _ProgressUpdate(this.current, this.total);
}

اريد طلب الاذونات في هذة الواجهه
الاذونات المطلوبة
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" android:minSdkVersion="33" />
<uses-permission android:name="android.permission.CAMERA" />
    <!-- لأجهزة Android 10 والإصدارات الأحدث -->
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
        android:minSdkVersion="30" />

    <application
        android:label="Micro Panel"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher"
         android:requestLegacyExternalStorage="true"
        >
        
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:taskAffinity=""
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <!-- Specifies an Android theme to apply to this Activity as soon as
                 the Android process has started. This theme is visible to the user
                 while the Flutter UI initializes. After that, this theme continues
                 to determine the Window background behind the Flutter UI. -->
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <!-- Don't delete the meta-data below.
             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
    </application>
    <!-- Required to query activities that can process text, see:
         https://developer.android.com/training/package-visibility and
         https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.

         In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
    <queries>
        <intent>
            <action android:name="android.intent.action.PROCESS_TEXT"/>
            <data android:mimeType="text/plain"/>
        </intent>
    </queries>

      <!-- لأذونات فتح الملفات -->
    <queries>
        <intent>
            <action android:name="android.intent.action.VIEW" />
            <data android:mimeType="application/pdf" />
        </intent>
        <intent>
            <action android:name="android.intent.action.PICK" />
        </intent>
        <intent>
            <action android:name="android.intent.action.GET_CONTENT" />
        </intent>
    </queries>
</manifest>