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

class UserPage extends StatefulWidget {
  @override
  _UserPageState createState() => _UserPageState();
}

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

  Map<String, Color> colors = {
    'onBorderColor': Colors.green,
    'offBorderColor': Colors.red,
    'neutralBorderColor': Colors.transparent,
    'onTextColor': Colors.green,
    'offTextColor': Colors.red,
    'neutralTextColor': Colors.blue,
  };

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

  List<BluetoothDevice> _devicesList = [];
  BluetoothDevice? _device;
  bool _connected = false;
  bool _isButtonUnavailable = false;
  bool _isLoading = false;
//Dipanggil ketika widget diinisialisasi. Digunakan untuk mengatur state awal dan mengaktifkan Bluetooth.
  @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();
      });
    });
  }

//Dipanggil ketika widget dihancurkan. Digunakan untuk membersihkan resource yang digunakan.
  @override
  void dispose() {
    if (isConnected!) {
      isDisconnecting = true;
      connection?.dispose();
      connection = null;
    }
    super.dispose();
  }

//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
  Future<void> getPairedDevices() async {
    List<BluetoothDevice> devices = [];
    try {
      devices = await _bluetooth.getBondedDevices();
    } on PlatformException {
      debugPrint("Error");
    }
    if (!mounted) {
      return;
    }
    setState(() {
      _devicesList = devices;
    });
  }

//ui
  @override
  Widget build(BuildContext context) {
    return 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((_) {
                show('Daftar perangkat diperbarui');
              });
            },
          ),
        ],
      ),
      body: Column(
        mainAxisSize: MainAxisSize.max,
        children: <Widget>[
          Visibility(
            visible: _isLoading,
            child: LinearProgressIndicator(
              backgroundColor: Colors.yellow,
              valueColor: AlwaysStoppedAnimation<Color>(Colors.red),
            ),
          ),
          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(
                    'Nyalakan 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: Center(
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                          const Text(
                            'Perangkat:',
                            style: TextStyle(
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                          SizedBox(width: 10),
                          DropdownButton(
                            items: _getDeviceItems(),
                            onChanged: (value) {
                              setState(() {
                                _device = value;
                                _isButtonUnavailable = false;
                              });
                            },
                            value: _devicesList.isNotEmpty ? _device : null,
                          ),
                        ],
                      ),
                    ),
                  ),
                ],
              ),
              Container(
                color: Colors.blue,
              ),
            ],
          ),
          Expanded(
            child: Center(
              child: ElevatedButton(
                onPressed: _device != null ? _handleUnlock : null,
                child: const Icon(Icons.lock_open, size: 100),
                style: ElevatedButton.styleFrom(
                  shape: CircleBorder(),
                  padding: EdgeInsets.all(40),
                  backgroundColor: Color.fromARGB(255, 251, 252, 255),
                ),
              ),
            ),
          ),
          Expanded(
            child: Padding(
              padding: const EdgeInsets.all(20),
              child: Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    const Text(
                      "CATATAN: Jika Anda tidak dapat menemukan perangkat dalam daftar, silakan pasangkan perangkat melalui pengaturan Bluetooth",
                      style: TextStyle(
                        fontSize: 15,
                        fontWeight: FontWeight.bold,
                        color: Colors.red,
                      ),
                    ),
                    const SizedBox(height: 15),
                    ElevatedButton(
                      child: const Text("Pengaturan Bluetooth"),
                      onPressed: () {
                        FlutterBluetoothSerial.instance.openSettings();
                      },
                    ),
                  ],
                ),
              ),
            ),
          )
        ],
      ),
    );
  }

//Membuat daftar item dropdown dari perangkat Bluetooth yang tersedia.
  List<DropdownMenuItem<BluetoothDevice>> _getDeviceItems() {
    List<DropdownMenuItem<BluetoothDevice>> items = [];
    if (_devicesList.isEmpty) {
      items.add(const DropdownMenuItem(
        child: Text('TIDAK ADA'),
      ));
    } else {
      for (var device in _devicesList) {
        items.add(DropdownMenuItem(
          value: device,
          child: Text(device.name!),
        ));
      }
    }
    return items;
  }

//Menghubungkan ke perangkat Bluetooth yang dipilih.
  Future<void> _connect() async {
    if (_device == null) {
      show('Tidak ada perangkat yang dipilih');
      setState(() {
        _isButtonUnavailable = false;
        _isLoading = false;
      });
    } else {
      if (!isConnected!) {
        setState(() {
          _isLoading = true;
        });

        try {
          connection = await BluetoothConnection.toAddress(_device!.address)
              .timeout(Duration(seconds: 5));

          debugPrint('Terhubung ke perangkat');
          setState(() {
            _connected = true;
            _isButtonUnavailable = false;
            _isLoading = false;
          });

          connection?.input?.listen((Uint8List data) {
            final message = utf8.decode(data);
            debugPrint('Data masuk: $message');
            setState(() {
              _deviceState = data.isNotEmpty ? data.last : 0;
            });
          }).onDone(() {
            debugPrint('Terputus oleh permintaan jarak jauh');
            if (isDisconnecting) {
              debugPrint('Memutuskan secara lokal!');
            } else {
              show('Terputus dari jarak jauh');
            }
            if (mounted) {
              setState(() {});
            }
          });
        } catch (error) {
          debugPrint('Tidak dapat terhubung, terjadi pengecualian');
          debugPrint(error.toString());
          setState(() {
            _isButtonUnavailable = false;
            _isLoading = false;
          });
          show('Tidak dapat terhubung dalam waktu 5 detik');
        }
      }
    }
  }

//Memutuskan koneksi Bluetooth.
  void _disconnect() async {
    setState(() {
      _isButtonUnavailable = true;
      _deviceState = 0;
    });

    await connection?.close();
    show('Perangkat terputus');
    if (!connection!.isConnected) {
      setState(() {
        _connected = false;
        _isButtonUnavailable = false;
      });
    }
  }

//Mengirim pesan untuk membuka pintu ke perangkat Bluetooth.
  void _sendUnlockMessage() async {
    final jsonData = jsonEncode({
      'action': 'open_door',
      'name': 'User',
      'address': _device?.address ?? 'unknown_address'
    });
    connection?.output.add(Uint8List.fromList(utf8.encode(jsonData)));
    await connection?.output.allSent;
    show('Sinyal buka kunci dikirim');
    setState(() {
      _deviceState = 1; // State unlocked
    });

    Future.delayed(Duration(seconds: 5), _disconnect);
  }

//Mengelola proses pembukaan pintu
  void _handleUnlock() async {
    setState(() {
      _isLoading = true;
    });

    if (!_connected) {
      await _connect();
    }

    if (_connected) {
      _sendUnlockMessage();
    }
  }

//Menampilkan pesan menggunakan SnackBar.
  Future show(String message,
      {Duration duration = const Duration(seconds: 3)}) async {
    await Future.delayed(const Duration(milliseconds: 100));
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(message),
        duration: duration,
      ),
    );
  }
}
