import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart';
import 'package:shared_preferences/shared_preferences.dart';

class AdminPage extends StatefulWidget {
  @override
  _AdminPageState createState() => _AdminPageState();
}

//Inisialisasi dan State Management
class _AdminPageState extends State<AdminPage> {
  BluetoothState _bluetoothState = BluetoothState.UNKNOWN;
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
  final FlutterBluetoothSerial _bluetooth = FlutterBluetoothSerial.instance;
  BluetoothConnection? connection;
  late int _deviceState;
  bool isDisconnecting = false;

  bool? get isConnected => connection != null && connection!.isConnected;

  List<BluetoothDevice> _devicesList = [];
  List<Map<String, String>> _addedDevices = [];
  BluetoothDevice? _device;
  bool _connected = false;
  bool _isButtonUnavailable = false;

  TextEditingController bluetoothNameController = TextEditingController();
  TextEditingController bluetoothAddressController = TextEditingController();
  TextEditingController passwordController = TextEditingController();

  int _passwordPrefixCounter = 1;

  String? _displayedIP;
//Inisialisasi dan Lifecycle Methods
  @override
  void initState() {
    super.initState();
    FlutterBluetoothSerial.instance.state.then((state) {
      setState(() {
        _bluetoothState = state;
      });
    });
    _deviceState = 0;
    enableBluetooth();
    FlutterBluetoothSerial.instance
        .onStateChanged()
        .listen((BluetoothState state) {
      setState(() {
        _bluetoothState = state;
        if (_bluetoothState == BluetoothState.STATE_OFF) {
          _isButtonUnavailable = true;
        }
        getPairedDevices();
      });
    });
    loadAddedDevices();
  }

  @override
  void dispose() {
    if (isConnected!) {
      isDisconnecting = true;
      connection?.dispose();
    }
    super.dispose();
  }

// Fungsi untuk Mengaktifkan Bluetooth jika tidak aktif.
  Future<void> enableBluetooth() async {
    _bluetoothState = await FlutterBluetoothSerial.instance.state;
    if (_bluetoothState == BluetoothState.STATE_OFF) {
      await FlutterBluetoothSerial.instance.requestEnable();
      await getPairedDevices();
    } else {
      await getPairedDevices();
    }
  }

//Mendapatkan daftar perangkat yang sudah terhubung (paired).
  Future<void> getPairedDevices() async {
    List<BluetoothDevice> devices = [];
    try {
      devices = await _bluetooth.getBondedDevices();
    } on PlatformException {
      debugPrint("Error");
    }
    if (!mounted) {
      return;
    }
    setState(() {
      _devicesList = devices;
    });
  }

//Memuat perangkat yang telah ditambahkan dari SharedPreferences
  Future<void> loadAddedDevices() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String? devicesJson = prefs.getString('added_devices');
    if (devicesJson != null) {
      List<Map<String, dynamic>> devices =
          List<Map<String, dynamic>>.from(jsonDecode(devicesJson));
      setState(() {
        _addedDevices =
            devices.map((device) => Map<String, String>.from(device)).toList();
        _passwordPrefixCounter = _addedDevices.length + 1;
      });
    }
  }

//Menyimpan perangkat yang telah ditambahkan ke SharedPreferences.
  Future<void> saveAddedDevices() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    String devicesJson = jsonEncode(_addedDevices);
    await prefs.setString('added_devices', devicesJson);
  }

//Fungsi untuk Menampilkan Pesan
  void showMessage(String message,
      {Duration duration = const Duration(seconds: 3)}) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(message),
        duration: duration,
      ),
    );
  }

//Fungsi untuk Mendapatkan Prefix Berikutnya
  int _getNextAvailablePrefix() {
    List<int> usedPrefixes = _addedDevices
        .map((device) => int.parse(device['prefix'] ?? '0'))
        .toList();
    usedPrefixes.sort();

    for (int i = 1; i <= usedPrefixes.length; i++) {
      if (!usedPrefixes.contains(i)) {
        return i;
      }
    }
    return usedPrefixes.length + 1;
  }

//Ui
  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        Navigator.of(context).popUntil((route) => route.isFirst);
        return false;
      },
      child: Scaffold(
        key: _scaffoldKey,
        appBar: AppBar(
          title: const Text("Smart Door"),
          backgroundColor: Color.fromARGB(255, 243, 146, 34),
          actions: <Widget>[
            ElevatedButton.icon(
              icon: const Icon(
                Icons.refresh,
                color: Color.fromARGB(255, 0, 0, 0),
              ),
              label: const Text(
                "",
                style: TextStyle(
                  color: Colors.white,
                ),
              ),
              onPressed: () async {
                await getPairedDevices().then((_) {
                  showMessage('Daftar perangkat diperbarui');
                });
              },
            ),
          ],
        ),
        body: SingleChildScrollView(
          child: Column(
            mainAxisSize: MainAxisSize.max,
            children: <Widget>[
              Visibility(
                visible: _isButtonUnavailable &&
                    _bluetoothState == BluetoothState.STATE_ON,
                child: const LinearProgressIndicator(
                  backgroundColor: Colors.yellow,
                  valueColor: AlwaysStoppedAnimation<Color>(Colors.red),
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(10),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: <Widget>[
                    const Expanded(
                      child: Text(
                        'Aktifkan Bluetooth',
                        style: TextStyle(
                          color: Colors.black,
                          fontSize: 16,
                        ),
                      ),
                    ),
                    Switch(
                      value: _bluetoothState.isEnabled,
                      onChanged: (bool value) {
                        future() async {
                          if (value) {
                            await FlutterBluetoothSerial.instance
                                .requestEnable();
                          } else {
                            await FlutterBluetoothSerial.instance
                                .requestDisable();
                          }
                          await getPairedDevices();
                          _isButtonUnavailable = false;
                          if (_connected) {
                            _disconnect();
                          }
                        }

                        future().then((_) {
                          setState(() {});
                        });
                      },
                    )
                  ],
                ),
              ),
              Stack(
                children: <Widget>[
                  Column(
                    children: <Widget>[
                      const Padding(
                        padding: EdgeInsets.only(top: 10),
                        child: Text(
                          "PERANGKAT TERPASANG",
                          style: TextStyle(
                            fontSize: 22,
                            color: Color.fromARGB(255, 0, 0, 0),
                            fontWeight: FontWeight.bold,
                          ),
                          textAlign: TextAlign.center,
                        ),
                      ),
                      Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: <Widget>[
                            const Text(
                              'Perangkat:',
                              style: TextStyle(
                                fontWeight: FontWeight.bold,
                              ),
                            ),
                            SizedBox(width: 10),
                            DropdownButton(
                              items: _getDeviceItems(),
                              onChanged: (value) async {
                                if (isConnected!) {
                                  await _disconnect(); // Putuskan koneksi jika ada
                                }
                                setState(() => _device = value);
                                await _connectToSelectedDevice();
                              },
                              value: _devicesList.isNotEmpty ? _device : null,
                            ),
                          ],
                        ),
                      ),
                      Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Row(
                              children: [
                                Text(
                                  'Perangkat Ditambahkan',
                                  style: TextStyle(
                                    fontSize: 18,
                                    fontWeight: FontWeight.bold,
                                  ),
                                ),
                                Spacer(),
                                IconButton(
                                  icon: Icon(Icons.add, color: Colors.blue),
                                  onPressed: () async {
                                    if (!isConnected!) {
                                      showMessage(
                                          'Harap hubungkan Bluetooth terlebih dahulu');
                                      return;
                                    }
                                    showDialog(
                                      context: context,
                                      builder: (context) => AlertDialog(
                                        title: Text('Tambah Perangkat'),
                                        content: Column(
                                          mainAxisSize: MainAxisSize.min,
                                          children: [
                                            TextField(
                                              controller:
                                                  bluetoothNameController,
                                              decoration: const InputDecoration(
                                                labelText:
                                                    'Nama Perangkat Bluetooth',
                                              ),
                                            ),
                                            TextField(
                                              controller:
                                                  bluetoothAddressController,
                                              decoration: const InputDecoration(
                                                labelText:
                                                    'Alamat Perangkat Bluetooth',
                                              ),
                                            ),
                                            Row(
                                              children: [
                                                Container(
                                                  width: 50,
                                                  child: TextField(
                                                    readOnly: true,
                                                    controller:
                                                        TextEditingController(
                                                      text:
                                                          _getNextAvailablePrefix()
                                                              .toString()
                                                              .padLeft(2, '0'),
                                                    ),
                                                    decoration: InputDecoration(
                                                      labelText: 'Prefix',
                                                    ),
                                                  ),
                                                ),
                                                SizedBox(width: 10),
                                                Expanded(
                                                  child: TextField(
                                                      controller:
                                                          passwordController,
                                                      decoration:
                                                          const InputDecoration(
                                                        labelText: 'Password',
                                                      ),
                                                      obscureText: true,
                                                      keyboardType: TextInputType
                                                          .number, // Hanya angka yang diperbolehkan
                                                      inputFormatters: <TextInputFormatter>[
                                                        FilteringTextInputFormatter
                                                            .digitsOnly // Filter hanya angka
                                                      ]),
                                                ),
                                              ],
                                            ),
                                          ],
                                        ),
                                        actions: [
                                          TextButton(
                                            onPressed: () {
                                              Navigator.of(context).pop();
                                            },
                                            child: Text('Batal'),
                                          ),
                                          TextButton(
                                            onPressed: () async {
                                              String name =
                                                  bluetoothNameController.text;
                                              String address =
                                                  bluetoothAddressController
                                                      .text;
                                              String password =
                                                  passwordController.text;

                                              bool addressExists =
                                                  _addedDevices.any((device) =>
                                                      device['address'] ==
                                                      address);
                                              if (addressExists) {
                                                showMessage(
                                                    'Alamat perangkat sudah ada dalam daftar');
                                                return;
                                              }
                                              if (name.isNotEmpty &&
                                                  address.isNotEmpty &&
                                                  password.isNotEmpty &&
                                                  password.length >= 6) {
                                                Navigator.of(context).pop();
                                                int nextPrefix =
                                                    _getNextAvailablePrefix();
                                                await addDeviceToESP32(
                                                    name,
                                                    address,
                                                    nextPrefix
                                                            .toString()
                                                            .padLeft(2, '0') +
                                                        password);
                                                setState(() {
                                                  _addedDevices.add({
                                                    'name': name,
                                                    'address': address,
                                                    'prefix':
                                                        nextPrefix.toString()
                                                  });
                                                  saveAddedDevices();
                                                  bluetoothNameController
                                                      .clear();
                                                  bluetoothAddressController
                                                      .clear();
                                                  passwordController.clear();
                                                });
                                                await _disconnect();
                                              } else {
                                                showMessage(
                                                    'Nama, alamat, dan password tidak boleh kosong atau password kurang dari 6 karakter');
                                              }
                                            },
                                            child: Text('Tambah'),
                                          ),
                                        ],
                                      ),
                                    );
                                  },
                                ),
                              ],
                            ),
                            Table(
                              border: TableBorder.all(color: Colors.black),
                              columnWidths: const <int, TableColumnWidth>{
                                0: FlexColumnWidth(2),
                                1: FlexColumnWidth(2),
                                2: FlexColumnWidth(1),
                              },
                              defaultVerticalAlignment:
                                  TableCellVerticalAlignment.middle,
                              children: [
                                TableRow(
                                  children: [
                                    Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: Text('Nama',
                                          style: TextStyle(
                                              fontWeight: FontWeight.bold)),
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: Text('Alamat',
                                          style: TextStyle(
                                              fontWeight: FontWeight.bold)),
                                    ),
                                    Padding(
                                      padding: const EdgeInsets.all(8.0),
                                      child: Text('Hapus',
                                          style: TextStyle(
                                              fontWeight: FontWeight.bold)),
                                    ),
                                  ],
                                ),
                                ..._addedDevices.map((device) {
                                  return TableRow(
                                    children: [
                                      Padding(
                                        padding: const EdgeInsets.all(8.0),
                                        child: Text(device['name'] ?? ''),
                                      ),
                                      Padding(
                                        padding: const EdgeInsets.all(8.0),
                                        child: Text(device['address'] ?? ''),
                                      ),
                                      IconButton(
                                        icon: Icon(Icons.delete,
                                            color: Colors.red),
                                        onPressed: () {
                                          showDeleteConfirmationDialog(device);
                                        },
                                      ),
                                    ],
                                  );
                                }).toList(),
                              ],
                            ),
                            if (_displayedIP != null)
                              Padding(
                                padding: const EdgeInsets.all(8.0),
                                child: Text(
                                  'IP Address: $_displayedIP',
                                  style: TextStyle(
                                    fontSize: 16,
                                    fontWeight: FontWeight.bold,
                                    color: Colors.blue,
                                  ),
                                ),
                              ),
                          ],
                        ),
                      ),
                    ],
                  ),
                  Container(
                    color: Colors.blue,
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }

  List<DropdownMenuItem<BluetoothDevice>> _getDeviceItems() {
    List<DropdownMenuItem<BluetoothDevice>> items = [];
    if (_devicesList.isEmpty) {
      items.add(const DropdownMenuItem(
        child: Text('NONE'),
      ));
    } else {
      _devicesList.forEach((device) {
        items.add(DropdownMenuItem(
          child: Text(device.name ?? ''),
          value: device,
        ));
      });
    }
    return items;
  }

//Menghubungkan ke perangkat Bluetooth yang dipilih.
  Future<void> _connectToSelectedDevice() async {
    setState(() {
      _isButtonUnavailable = true;
    });
    if (_device == null) {
      showMessage('Tidak ada perangkat yang dipilih');
    } else {
      if (isConnected!) {
        await _disconnect(); // Putuskan koneksi jika ada
      }
      await BluetoothConnection.toAddress(_device!.address).then((_connection) {
        showMessage('Terhubung ke perangkat');
        connection = _connection;
        setState(() {
          _connected = true;
        });
        connection!.input!.listen((Uint8List data) {
          String response = utf8.decode(data);
          print("Data diterima: $response");
          if (response.contains('{"ip":"')) {
            setState(() {
              _displayedIP = jsonDecode(response)['ip'];
              print("IP Address: $_displayedIP");
            });
          }
        }).onDone(() {
          if (isDisconnecting) {
            showMessage('Terputus secara lokal');
          } else {
            showMessage('Terputus secara remote');
          }
          if (mounted) {
            setState(() {});
          }
        });

        // Kirim perintah setelah berhasil terhubung
        String message = jsonEncode({
          "action": "get_ip",
        });
        connection!.output.add(utf8.encode(message + "\r\n"));
        connection!.output.allSent;
      }).catchError((error) {
        showMessage('Tidak bisa terhubung, terjadi kesalahan');
        debugPrint(error.toString());
      });
      setState(() => _isButtonUnavailable = false);
    }
  }

//Memutuskan koneksi Bluetooth.
  Future<void> _disconnect() async {
    await connection?.close();
    showMessage('Perangkat terputus');
    if (!connection!.isConnected) {
      setState(() {
        _connected = false;
        _isButtonUnavailable = false;
      });
    }
  }

//Menambahkan perangkat ke ESP32 dengan mengirimkan data melalui Bluetooth.
  Future<void> addDeviceToESP32(
      String name, String address, String password) async {
    if (isConnected!) {
      String message = jsonEncode({
        "action": "add",
        "name": name,
        "address": address,
        "password": password
      });
      connection!.output.add(utf8.encode(message + "\r\n"));
      await connection!.output.allSent;
    }
  }

//Menghapus perangkat dari ESP32 dengan mengirimkan data melalui Bluetooth.
  Future<void> deleteDeviceFromESP32(String address) async {
    if (isConnected!) {
      String message = jsonEncode({
        "action": "delete",
        "address": address,
      });
      connection!.output.add(utf8.encode(message + "\r\n"));
      await connection!.output.allSent;
    }
  }

  void showDeleteConfirmationDialog(Map<String, String> device) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text('Konfirmasi Hapus'),
        content: Text('Apakah Anda yakin ingin menghapus perangkat ini?'),
        actions: [
          TextButton(
            onPressed: () {
              Navigator.of(context).pop();
            },
            child: Text('Tidak'),
          ),
          TextButton(
            onPressed: () async {
              if (!isConnected!) {
                showMessage('Harap hubungkan Bluetooth terlebih dahulu');
                return;
              }
              Navigator.of(context).pop();
              await deleteDeviceFromESP32(device['address']!);
              setState(() {
                _addedDevices.remove(device);
                saveAddedDevices();
              });
              await _disconnect();
            },
            child: Text('Iya'),
          ),
        ],
      ),
    );
  }
}
