import 'dart:convert';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:http/http.dart' as http;
import 'package:audioplayers/audioplayers.dart';

import '../layout/main_layout.dart';
import 'ibu_drawer.dart';

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

  @override
  State<DashboardIbuPage> createState() => _DashboardIbuPageState();
}

class _DashboardIbuPageState extends State<DashboardIbuPage> {
  DateTime _selectedDate = DateTime.now();
  static const String baseUrl = "http://ta.myhost.id/E31230549/mposyandu_api";

  Timer? _pollingTimer;
  final AudioPlayer _audioPlayer = AudioPlayer();
  int _notificationCount = 0;
  List<String> _knownJadwalIds = [];

  Map? dataKehamilan;
  List dataBalita = [];
  List dataJadwal = [];
  List dataJadwalAnc = [];
  String namaUser = "Ibu";
  bool isLoading = true;
  bool _isPasswordVisible = false;

  @override
  void initState() {
    super.initState();
    _audioPlayer.setReleaseMode(ReleaseMode.stop);
    _initDashboard();
    _pollingTimer = Timer.periodic(const Duration(seconds: 15), (timer) {
      getDashboardData(isPolling: true);
    });
  }

  @override
  void dispose() {
    _pollingTimer?.cancel();
    _audioPlayer.dispose();
    super.dispose();
  }

  Future<void> _initDashboard() async {
    final prefs = await SharedPreferences.getInstance();
    String? idUser = prefs.getString("id_user");

    setState(() {
      namaUser = prefs.getString("nama") ?? "Ibu";
      _notificationCount = prefs.getInt('notif_count_$idUser') ?? 0;
      _knownJadwalIds = prefs.getStringList('known_ids_$idUser') ?? [];
    });

    await _checkLoginStatus();
    _checkPasswordStatus();
    await getDashboardData(isPolling: false);
  }

  // ================= LOGIKA CEK & UPDATE PASSWORD DEFAULT (NIK) =================

  Future<void> _checkPasswordStatus() async {
    final prefs = await SharedPreferences.getInstance();
    String? id = prefs.getString("id_user");

    if (id == null) return;

    bool isChanged = prefs.getBool("is_password_changed_$id") ?? false;
    if (isChanged) return;

    try {
      final res = await http.post(
          Uri.parse("$baseUrl/cek_password_default_ibu.php"),
          body: {"id": id}).timeout(const Duration(seconds: 10));

      if (res.statusCode == 200) {
        final data = json.decode(res.body);
        if (data["success"] == true && data["password_default"] == true) {
          WidgetsBinding.instance.addPostFrameCallback((_) {
            _showChangePasswordDialog();
          });
        } else if (data["success"] == true) {
          await prefs.setBool("is_password_changed_$id", true);
        }
      }
    } catch (e) {
      debugPrint("Gagal cek password default: $e");
    }
  }

  void _showChangePasswordDialog() {
    final TextEditingController passwordController = TextEditingController();
    String? localError;

    showDialog(
      context: context,
      barrierDismissible: false,
      builder: (context) => StatefulBuilder(
        builder: (context, setDialogState) {
          return AlertDialog(
            shape:
                RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
            title: Text("Keamanan Akun",
                style: GoogleFonts.poppins(fontWeight: FontWeight.bold)),
            content: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Text(
                  "Akun Anda terdeteksi masih menggunakan password bawaan. Silakan ubah password (6 digit, berisi huruf & angka) demi keamanan data.",
                  style: GoogleFonts.poppins(fontSize: 13),
                ),
                const SizedBox(height: 20),
                TextField(
                  controller: passwordController,
                  obscureText: !_isPasswordVisible,
                  maxLength: 6,
                  keyboardType: TextInputType.visiblePassword,
                  decoration: InputDecoration(
                    labelText: "Password Baru",
                    hintText: "Contoh: abc123",
                    errorText: localError,
                    border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(12)),
                    suffixIcon: IconButton(
                      icon: Icon(_isPasswordVisible
                          ? Icons.visibility
                          : Icons.visibility_off),
                      onPressed: () => setDialogState(
                          () => _isPasswordVisible = !_isPasswordVisible),
                    ),
                  ),
                ),
              ],
            ),
            actions: [
              SizedBox(
                width: double.infinity,
                child: ElevatedButton(
                  style: ElevatedButton.styleFrom(
                    backgroundColor: Colors.blue,
                    shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(10)),
                  ),
                  onPressed: () async {
                    String val = passwordController.text.trim();

                    bool hasLetter = val.contains(RegExp(r'[a-zA-Z]'));
                    bool hasNumber = val.contains(RegExp(r'[0-9]'));

                    if (val.isEmpty) {
                      setDialogState(() => localError = "Wajib diisi");
                    } else if (val.length != 6) {
                      setDialogState(
                          () => localError = "Harus tepat 6 karakter");
                    } else if (!hasLetter || !hasNumber) {
                      setDialogState(
                          () => localError = "Harus kombinasi huruf & angka");
                    } else {
                      setDialogState(() => localError = null);
                      await _updatePassword(val);
                    }
                  },
                  child: Text("Simpan Password",
                      style: GoogleFonts.poppins(
                          color: Colors.white, fontWeight: FontWeight.bold)),
                ),
              ),
            ],
          );
        },
      ),
    );
  }

  Future<void> _updatePassword(String p) async {
    final prefs = await SharedPreferences.getInstance();
    String? id = prefs.getString("id_user");
    if (id == null) return;
    try {
      final res = await http.post(Uri.parse("$baseUrl/update_password_ibu.php"),
          body: {"id": id, "password": p});
      final data = json.decode(res.body);

      if (data["success"]) {
        await prefs.setBool("is_password_changed_$id", true);
        if (mounted) {
          Navigator.pop(context);
          ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
              content: Text("Password berhasil diperbarui"),
              backgroundColor: Colors.green));
        }
      }
    } catch (e) {
      debugPrint("Update error: $e");
    }
  }

  // ================= LOGIKA DATA & NOTIFIKASI =================

  Future<void> getDashboardData({required bool isPolling}) async {
    final prefs = await SharedPreferences.getInstance();
    String? idUser = prefs.getString("id_user");
    if (idUser == null) return;

    try {
      final response = await http.post(Uri.parse("$baseUrl/dashboard_ibu.php"),
          body: {"user_id": idUser});
      final data = json.decode(response.body);

      if (data["success"]) {
        List currentPosyandu = data["jadwal"] ?? [];
        List currentAnc = data["jadwal_anc"] ?? [];
        List allIncoming = [...currentPosyandu, ...currentAnc];

        bool hasNewJadwal = false;
        int newItemsCount = 0;

        for (var item in allIncoming) {
          String uniqueId = "${item['id']}_${item['tanggal']}";
          if (!_knownJadwalIds.contains(uniqueId)) {
            _knownJadwalIds.add(uniqueId);
            newItemsCount++;
            hasNewJadwal = true;
          }
        }

        if (hasNewJadwal) {
          await prefs.setStringList('known_ids_$idUser', _knownJadwalIds);
          if (isPolling) {
            _playNotifSound();
            setState(() {
              _notificationCount += newItemsCount;
            });
            await prefs.setInt('notif_count_$idUser', _notificationCount);
          }
        }

        if (mounted) {
          setState(() {
            dataKehamilan = data["kehamilan"];
            dataBalita = data["balita"] ?? [];
            dataJadwal = currentPosyandu;
            dataJadwalAnc = currentAnc;
            isLoading = false;
          });
        }
      }
    } catch (e) {
      if (mounted) setState(() => isLoading = false);
    }
  }

  Future<void> _playNotifSound() async {
    try {
      await _audioPlayer.stop();
      await _audioPlayer.play(AssetSource('sounds/notif.mp3'));
    } catch (e) {
      debugPrint("Audio Error: $e");
    }
  }

  Map<String, dynamic> _getJadwalStatus(Map item, bool isAnc) {
    try {
      DateTime sekarang = DateTime.now();
      String tglStr = item["tanggal"] ?? "";
      String jamMulaiStr = item["jam_mulai"]?.toString() ?? "08:00:00";
      if (jamMulaiStr.length == 5) jamMulaiStr = "$jamMulaiStr:00";

      DateTime mulai = DateTime.parse("${tglStr.trim()} ${jamMulaiStr.trim()}");
      DateTime selesai;

      if (isAnc) {
        selesai = mulai.add(const Duration(hours: 4));
      } else {
        String jamSelesaiStr = item["jam_selesai"]?.toString() ?? "";
        if (jamSelesaiStr == "-" || jamSelesaiStr.isEmpty) {
          selesai = mulai.add(const Duration(hours: 4));
        } else {
          if (jamSelesaiStr.length == 5) jamSelesaiStr = "$jamSelesaiStr:00";
          selesai = DateTime.parse("${tglStr.trim()} ${jamSelesaiStr.trim()}");
        }
      }

      if (sekarang.isAfter(selesai)) {
        return {"label": "Selesai", "color": Colors.white.withOpacity(0.4)};
      } else if (sekarang.isAfter(mulai) && sekarang.isBefore(selesai)) {
        return {"label": "Berlangsung", "color": Colors.greenAccent};
      } else {
        return {"label": "Mendatang", "color": Colors.white.withOpacity(0.2)};
      }
    } catch (e) {
      return {"label": "-", "color": Colors.transparent};
    }
  }

  @override
  Widget build(BuildContext context) {
    final selectedKey =
        "${_selectedDate.year}-${_selectedDate.month.toString().padLeft(2, '0')}-${_selectedDate.day.toString().padLeft(2, '0')}";
    final posyanduAtDate =
        dataJadwal.where((j) => j["tanggal"] == selectedKey).toList();
    final ancAtDate =
        dataJadwalAnc.where((j) => j["tanggal"] == selectedKey).toList();

    if (isLoading) {
      return const Scaffold(body: Center(child: CircularProgressIndicator()));
    }

    return PopScope(
      canPop: false,
      onPopInvokedWithResult: (didPop, result) async {
        if (didPop) return;
        await SystemNavigator.pop();
      },
      child: Theme(
        data: Theme.of(context).copyWith(
            textTheme:
                GoogleFonts.poppinsTextTheme(Theme.of(context).textTheme)),
        child: Stack(
          children: [
            MainLayout(
              title: "",
              drawer: const IbuDrawer(),
              body: RefreshIndicator(
                onRefresh: () => getDashboardData(isPolling: false),
                child: SingleChildScrollView(
                  physics: const AlwaysScrollableScrollPhysics(),
                  padding: const EdgeInsets.all(16),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      _buildHeader(),
                      const SizedBox(height: 20),
                      _buildHeroImage(),
                      const SizedBox(height: 30),
                      if (dataKehamilan != null) ...[
                        _buildKehamilanCard(),
                        const SizedBox(height: 15)
                      ],
                      if (dataBalita.isNotEmpty) ...[
                        _buildBalitaCard(),
                        const SizedBox(height: 30)
                      ],
                      _buildCalendarSection(posyanduAtDate, ancAtDate),
                      const SizedBox(height: 20),
                    ],
                  ),
                ),
              ),
            ),
            _buildNotificationIcon(),
          ],
        ),
      ),
    );
  }

  Widget _buildNotificationIcon() {
    return Positioned(
      top: MediaQuery.of(context).padding.top + 5,
      right: 12,
      child: Stack(
        alignment: Alignment.center,
        children: [
          IconButton(
              icon: const Icon(Icons.notifications,
                  color: Colors.white, size: 28),
              onPressed: _showNotifDialog),
          if (_notificationCount > 0)
            Positioned(
              right: 8,
              top: 8,
              child: Container(
                padding: const EdgeInsets.all(2),
                decoration: BoxDecoration(
                    color: Colors.red,
                    shape: BoxShape.circle,
                    border: Border.all(color: Colors.white, width: 1.5)),
                constraints: const BoxConstraints(minWidth: 18, minHeight: 18),
                child: Center(
                    child: Text(
                        _notificationCount > 9 ? "9+" : "$_notificationCount",
                        style: const TextStyle(
                            color: Colors.white,
                            fontSize: 9,
                            fontWeight: FontWeight.bold))),
              ),
            )
        ],
      ),
    );
  }

  void _showNotifDialog() async {
    final prefs = await SharedPreferences.getInstance();
    String? idUser = prefs.getString("id_user");
    setState(() {
      _notificationCount = 0;
    });
    await prefs.setInt('notif_count_$idUser', 0);

    showDialog(
      context: context,
      builder: (_) => AlertDialog(
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
        title: Text("Pemberitahuan Jadwal",
            textAlign: TextAlign.center,
            style:
                GoogleFonts.poppins(fontWeight: FontWeight.bold, fontSize: 16)),
        content: Container(
          width: 300,
          constraints: const BoxConstraints(maxHeight: 450),
          child: dataJadwal.isEmpty && dataJadwalAnc.isEmpty
              ? Text("Tidak ada riwayat jadwal.",
                  textAlign: TextAlign.center,
                  style: GoogleFonts.poppins(fontSize: 13))
              : SingleChildScrollView(
                  child: Column(mainAxisSize: MainAxisSize.min, children: [
                    ...dataJadwal
                        .map((j) => _buildMiniSchedule(j, Colors.blue, false)),
                    ...dataJadwalAnc
                        .map((j) => _buildMiniSchedule(j, Colors.pink, true)),
                  ]),
                ),
        ),
        actions: [
          Center(
              child: TextButton(
                  onPressed: () => Navigator.pop(context),
                  child: const Text("Tutup")))
        ],
      ),
    );
  }

  Widget _buildMiniSchedule(Map item, Color color, bool isAnc) {
    var status = _getJadwalStatus(item, isAnc);
    return Container(
      width: double.infinity,
      margin: const EdgeInsets.only(bottom: 12),
      padding: const EdgeInsets.all(14),
      decoration: BoxDecoration(
          color: color,
          borderRadius: BorderRadius.circular(12),
          boxShadow: [
            BoxShadow(
                color: Colors.black.withOpacity(0.1),
                blurRadius: 4,
                offset: const Offset(0, 2))
          ]),
      child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
        Row(children: [
          const Icon(Icons.event_available, size: 18, color: Colors.white),
          const SizedBox(width: 8),
          Expanded(
              child: Text(item["keterangan"] ?? "Kegiatan",
                  style: GoogleFonts.poppins(
                      fontWeight: FontWeight.bold,
                      fontSize: 14,
                      color: Colors.white))),
          Container(
              padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
              decoration: BoxDecoration(
                  color: status["color"],
                  borderRadius: BorderRadius.circular(6)),
              child: Text(status["label"],
                  style: const TextStyle(
                      fontSize: 10,
                      color: Colors.white,
                      fontWeight: FontWeight.bold)))
        ]),
        Divider(height: 20, color: Colors.white.withOpacity(0.3), thickness: 1),
        Row(children: [
          const Icon(Icons.calendar_month, size: 14, color: Colors.white),
          const SizedBox(width: 8),
          Text(_formatDateToIndo(item["tanggal"]),
              style: const TextStyle(
                  fontSize: 12,
                  color: Colors.white,
                  fontWeight: FontWeight.w500))
        ]),
        const SizedBox(height: 6),
        Row(children: [
          const Icon(Icons.location_on, size: 14, color: Colors.white),
          const SizedBox(width: 8),
          Expanded(
              child: Text(item["lokasi"] ?? "-",
                  style: const TextStyle(fontSize: 12, color: Colors.white)))
        ]),
      ]),
    );
  }

  Widget _buildHeader() => RichText(
          text: TextSpan(children: [
        TextSpan(
            text: 'Selamat Datang Ibu $namaUser\n',
            style: GoogleFonts.poppins(
                fontSize: 18, fontWeight: FontWeight.bold, color: Colors.blue)),
        TextSpan(
            text: 'Pantau kesehatan ibu dan buah hati tercinta ',
            style: GoogleFonts.poppins(fontSize: 13, color: Colors.black87)),
        const WidgetSpan(
            child: Icon(Icons.favorite, color: Colors.blue, size: 18)),
      ]));

  Widget _buildHeroImage() => Center(
      child: Image.asset('assets/images/logoo.webp',
          width: 300,
          height: 180,
          errorBuilder: (_, __, ___) =>
              const Icon(Icons.image, size: 100, color: Colors.grey)));

  // ================= UPDATE CARD INFORMASI KEHAMILAN =================
  Widget _buildKehamilanCard() =>
      _infoBox(color: Colors.lightGreen, title: "Informasi Kehamilan", items: [
        _infoItem(Icons.info_outline, "Status Kehamilan",
            _capitalize(dataKehamilan?["status"])),
        _infoItem(Icons.calendar_today, "HPHT",
            _formatDateToIndo(dataKehamilan?["hpht"])),
        _infoItem(Icons.pregnant_woman, "Usia Kandungan",
            "${dataKehamilan!["hpht"] != "0000-00-00" && dataKehamilan?["status"] == "aktif" ? (DateTime.now().difference(DateTime.parse(dataKehamilan!["hpht"])).inDays ~/ 7) : 0} Minggu"),
        _infoItem(Icons.event, "HPL", _formatDateToIndo(dataKehamilan?["hpl"])),
        _infoItem(Icons.history, "Tgl Persalinan Sblm",
            _formatDateToIndo(dataKehamilan?["tanggal_persalinan_sebelumnya"])),
        _infoItem(Icons.looks_one, "Gravida",
            dataKehamilan?["gravida"].toString() ?? "-"),
        _infoItem(
            Icons.looks_two, "Para", dataKehamilan?["para"].toString() ?? "-"),
        _infoItem(Icons.looks_3, "Abortus",
            dataKehamilan?["abortus"].toString() ?? "-"),
        _infoItem(Icons.favorite_border, "Hidup",
            dataKehamilan?["hidup"].toString() ?? "-"),
        _infoItem(
            Icons.payment, "Pembiayaan", dataKehamilan?["pembiayaan"] ?? "-"),
      ]);

  // ================= UPDATE CARD INFORMASI ANAK =================
  Widget _buildBalitaCard() {
    bool isFirstChildFemale = dataBalita.isNotEmpty &&
        dataBalita[0]["jenis_kelamin"]?.toString().toUpperCase() == "P";

    return Container(
        width: double.infinity,
        decoration: BoxDecoration(
            color: isFirstChildFemale ? Colors.pink : Colors.blue,
            borderRadius: BorderRadius.circular(16),
            boxShadow: const [
              BoxShadow(
                  blurRadius: 8, color: Colors.black12, offset: Offset(0, 4))
            ]),
        child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
          Padding(
              padding: const EdgeInsets.all(16),
              child: Text("Informasi Anak",
                  style: GoogleFonts.poppins(
                      color: Colors.white,
                      fontWeight: FontWeight.bold,
                      fontSize: 16))),
          ...dataBalita.asMap().entries.map((entry) {
            var anak = entry.value;
            bool isP = anak["jenis_kelamin"]?.toString().toUpperCase() == "P";

            String tempatLahir = anak["tempat_lahir"] ?? "-";
            String tanggalLahirIndo = _formatDateToIndo(anak["tanggal_lahir"]);
            String tempatTanggalLahir = "$tempatLahir, $tanggalLahirIndo";

            return Container(
                width: double.infinity,
                padding: const EdgeInsets.all(16),
                decoration: BoxDecoration(
                    color: isP ? Colors.pink : Colors.blue,
                    borderRadius: entry.key == dataBalita.length - 1
                        ? const BorderRadius.vertical(
                            bottom: Radius.circular(16))
                        : null),
                child: Column(children: [
                  _infoItemCustom(Icons.info_outline, "Status Balita",
                      _capitalize(anak["status"]), Colors.white),
                  _infoItemCustom(Icons.child_care, "Nama Balita",
                      anak["nama"] ?? "-", Colors.white),
                  _infoItemCustom(Icons.person, "Jenis Kelamin",
                      formatJenisKelamin(anak["jenis_kelamin"]), Colors.white),
                  _infoItemCustom(Icons.location_city, "Tempat Tanggal Lahir",
                      tempatTanggalLahir, Colors.white),
                  _infoItemCustom(Icons.cake, "Usia",
                      hitungUsiaBalita(anak["tanggal_lahir"]), Colors.white),
                  _infoItemCustom(Icons.format_list_numbered, "Anak Ke",
                      anak["anak_ke"]?.toString() ?? "-", Colors.white),
                  if (entry.key < dataBalita.length - 1)
                    const Divider(color: Colors.white30, height: 20)
                ]));
          }).toList(),
        ]));
  }

  Widget _buildCalendarSection(List s, List a) => Column(children: [
        Center(
            child: Text("Jadwal Kegiatan",
                style: GoogleFonts.poppins(
                    fontWeight: FontWeight.bold, fontSize: 16))),
        const SizedBox(height: 20),
        if (s.isEmpty && a.isEmpty)
          _emptySchedule()
        else
          Column(children: [
            ...s.map((i) => _scheduleDetail(i, Colors.blue)),
            ...a.map((i) => _scheduleDetail(i, Colors.pink))
          ]),
        const SizedBox(height: 20),
        _buildCalendarPicker(),
      ]);

  Widget _buildCalendarPicker() => Center(
      child: Container(
          padding: const EdgeInsets.all(8),
          decoration: BoxDecoration(
              color: Colors.white,
              borderRadius: BorderRadius.circular(16),
              boxShadow: [
                BoxShadow(color: Colors.black.withOpacity(0.05), blurRadius: 10)
              ]),
          child: SizedBox(
              width: 300,
              height: 280,
              child: CalendarDatePicker(
                  initialDate: _selectedDate,
                  firstDate: DateTime(2020),
                  lastDate: DateTime(2030),
                  onDateChanged: (d) => setState(() => _selectedDate = d)))));

  Widget _scheduleDetail(Map item, Color color) {
    String jamSelesai = item["jam_selesai"]?.toString() ?? "-";
    String displayJam = (jamSelesai == "-" || jamSelesai.isEmpty)
        ? "${item["jam_mulai"] ?? "00:00"} - Selesai"
        : "${item["jam_mulai"] ?? "00:00"} - $jamSelesai";
    return Padding(
        padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 8),
        child: Column(children: [
          Row(mainAxisAlignment: MainAxisAlignment.center, children: [
            Icon(Icons.stars, color: color, size: 20),
            const SizedBox(width: 8),
            Flexible(
                child: Text(item["keterangan"] ?? "Kegiatan",
                    textAlign: TextAlign.center,
                    style: GoogleFonts.poppins(
                        fontSize: 14,
                        fontWeight: FontWeight.bold,
                        color: color)))
          ]),
          const SizedBox(height: 8),
          Row(mainAxisAlignment: MainAxisAlignment.center, children: [
            const Icon(Icons.access_time, size: 14, color: Colors.grey),
            const SizedBox(width: 6),
            Text(displayJam, style: GoogleFonts.poppins(fontSize: 12))
          ]),
          const SizedBox(height: 4),
          Row(mainAxisAlignment: MainAxisAlignment.center, children: [
            const Icon(Icons.location_on_outlined,
                size: 14, color: Colors.grey),
            const SizedBox(width: 6),
            Flexible(
                child: Text("Lokasi: ${item["lokasi"] ?? "-"}",
                    textAlign: TextAlign.center,
                    style: GoogleFonts.poppins(fontSize: 12)))
          ]),
          Divider(thickness: 1, color: color.withOpacity(0.2)),
        ]));
  }

  String _formatDateToIndo(String? dateString) {
    if (dateString == null || dateString.isEmpty || dateString == "0000-00-00")
      return "-";
    try {
      DateTime date = DateTime.parse(dateString);
      const bulan = [
        "",
        "Januari",
        "Februari",
        "Maret",
        "April",
        "Mei",
        "Juni",
        "Juli",
        "Agustus",
        "September",
        "Oktober",
        "November",
        "Desember"
      ];
      return "${date.day} ${bulan[date.month]} ${date.year}";
    } catch (e) {
      return "-";
    }
  }

  String hitungUsiaBalita(String? tanggalLahir) {
    if (tanggalLahir == null || tanggalLahir.isEmpty) return "-";
    try {
      DateTime lahir = DateTime.parse(tanggalLahir);
      DateTime sekarang = DateTime.now();

      int tahun = sekarang.year - lahir.year;
      int selisihBulan = ClinicalMonthDiff(sekarang, lahir);

      if (sekarang.day < lahir.day) selisihBulan--;

      if (selisihBulan < 0) {
        tahun--;
        selisihBulan += 12;
      }
      return "$tahun Thn $selisihBulan Bln";
    } catch (e) {
      return "-";
    }
  }

  int ClinicalMonthDiff(DateTime a, DateTime b) {
    return a.month - b.month;
  }

  String formatJenisKelamin(String? jk) {
    if (jk == null) return "-";
    return (jk.toUpperCase() == "L")
        ? "Laki-laki"
        : (jk.toUpperCase() == "P" ? "Perempuan" : jk);
  }

  String _capitalize(String? text) {
    if (text == null || text.isEmpty) return "-";
    return text[0].toUpperCase() + text.substring(1).toLowerCase();
  }

  Widget _infoBox(
          {required Color color,
          required String title,
          required List<Widget> items}) =>
      Container(
          width: double.infinity,
          padding: const EdgeInsets.all(16),
          decoration: BoxDecoration(
              color: color,
              borderRadius: BorderRadius.circular(16),
              boxShadow: const [
                BoxShadow(
                    blurRadius: 8, color: Colors.black12, offset: Offset(0, 4))
              ]),
          child:
              Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
            Text(title,
                style: GoogleFonts.poppins(
                    color: Colors.white,
                    fontWeight: FontWeight.bold,
                    fontSize: 16)),
            const SizedBox(height: 12),
            ...items
          ]));

  Widget _infoItem(IconData i, String t, String v) => Padding(
      padding: const EdgeInsets.only(bottom: 6),
      child: Row(children: [
        Icon(i, color: Colors.white, size: 18),
        const SizedBox(width: 10),
        SizedBox(
            width: 150,
            child: Text(t,
                style: GoogleFonts.poppins(color: Colors.white, fontSize: 13))),
        const Text(": ", style: TextStyle(color: Colors.white)),
        Expanded(
            child: Text(v,
                style: GoogleFonts.poppins(color: Colors.white, fontSize: 13)))
      ]));

  Widget _infoItemCustom(IconData i, String t, String v, Color c) => Padding(
      padding: const EdgeInsets.only(bottom: 6),
      child: Row(children: [
        Icon(i, color: c, size: 18),
        const SizedBox(width: 10),
        SizedBox(
            width: 150,
            child: Text(t, style: GoogleFonts.poppins(color: c, fontSize: 13))),
        Text(": ", style: TextStyle(color: c)),
        Expanded(
            child: Text(v, style: GoogleFonts.poppins(color: c, fontSize: 13)))
      ]));

  Widget _emptySchedule() => Column(children: [
        const Icon(Icons.event_busy, size: 30, color: Colors.grey),
        Text("Tidak ada kegiatan",
            style: GoogleFonts.poppins(color: Colors.grey, fontSize: 12))
      ]);

  Future<void> _checkLoginStatus() async {
    final prefs = await SharedPreferences.getInstance();
    if (!(prefs.getBool("isLogin") ?? false) && mounted) {
      Navigator.pushReplacementNamed(context, "/login");
    }
  }
}
