// ignore_for_file: use_build_context_synchronously, deprecated_member_use, prefer_const_constructors
import 'dart:async';

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:latlong2/latlong.dart';

import '../../../app/injection_container.dart';
import '../../../core/network/api_client.dart';
import '../../../core/services/websocket_service.dart';
import '../../../core/storage/secure_storage.dart';

// ─────────────────────────────────────────────────────────────────────────────
//  GUARDIAN DASHBOARD SCREEN
//  Fully live — fetches real data from backend, subscribes to WebSocket
//  for real-time GPS updates and SOS alerts.
// ─────────────────────────────────────────────────────────────────────────────

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

  @override
  State<GuardianDashboardScreen> createState() =>
      _GuardianDashboardScreenState();
}

class _GuardianDashboardScreenState extends State<GuardianDashboardScreen>
    with TickerProviderStateMixin {
  // ── Data state ──────────────────────────────────────────────────────────────
  _DashboardData? _data;
  bool _loading = true;
  String? _error;
  String _guardianName = 'Guardian';

  // ── Live location (WebSocket) ────────────────────────────────────────────────
  LatLng? _liveLatLng;
  bool _liveConnected = false;
  final MapController _mapController = MapController();

  // ── Pulse animation for live dot ────────────────────────────────────────────
  late final AnimationController _pulseCtrl = AnimationController(
    vsync: this,
    duration: const Duration(milliseconds: 1800),
  )..repeat(reverse: true);
  late final Animation<double> _pulseAnim =
      Tween<double>(begin: 0.4, end: 1.0).animate(
    CurvedAnimation(parent: _pulseCtrl, curve: Curves.easeInOut),
  );

  // ── SOS flash animation ──────────────────────────────────────────────────────
  late final AnimationController _sosCtrl = AnimationController(
    vsync: this,
    duration: const Duration(milliseconds: 600),
  );
  bool _sosAlert = false;

  // ── Refresh button animation ─────────────────────────────────────────────────
  late final AnimationController _refreshCtrl = AnimationController(
    vsync: this,
    duration: const Duration(milliseconds: 700),
  );

  @override
  void initState() {
    super.initState();
    _loadAll();
    _subscribeWebSocket();
  }

  @override
  void dispose() {
    _pulseCtrl.dispose();
    _sosCtrl.dispose();
    _refreshCtrl.dispose();
    super.dispose();
  }

  Dio get _api => sl<ApiClient>().dio;

  // ── Load all dashboard data in parallel ────────────────────────────────────
  Future<void> _loadAll({bool silent = false}) async {
    if (!silent) {
      setState(() {
        _loading = true;
        _error = null;
      });
    }
    try {
      _guardianName =
          await sl<SecureStorage>().getDisplayName() ?? 'Guardian';

      // Run dashboard + activity + SOS in parallel
      final results = await Future.wait([
        _fetchDashboard(),
        _fetchActivity(),
        _fetchSosPending(),
      ]);

      final dashboard = results[0] as Map<String, dynamic>?;
      final activityList =
          results[1] as List<Map<String, dynamic>>;
      final sosPending = results[2] as int;

      // Extract latest GPS from dashboard
      final lastLoc = dashboard?['lastLocation'] as Map<String, dynamic>?;
      LatLng? newLatLng;
      if (lastLoc != null &&
          lastLoc['lat'] != null &&
          lastLoc['lng'] != null) {
        newLatLng = LatLng(
          (lastLoc['lat'] as num).toDouble(),
          (lastLoc['lng'] as num).toDouble(),
        );
      }

      // Extract user info
      final userStatus =
          dashboard?['userStatus'] as Map<String, dynamic>?;

      setState(() {
        _data = _DashboardData(
          userName: userStatus?['displayName']?.toString() ??
              dashboard?['userName']?.toString() ??
              'User',
          userOnline:
              userStatus?['online'] as bool? ?? false,
          userLastSeen:
              userStatus?['lastSeenAt']?.toString(),
          battery: userStatus?['battery'] as int?,
          speed: userStatus?['lastSpeed'] as double?,
          obstaclesTotal:
              userStatus?['obstaclesToday'] as int? ??
                  dashboard?['obstaclesToday'] as int? ??
                  0,
          unreadNotif:
              dashboard?['unreadNotifCount'] as int? ?? 0,
          unreadSos: sosPending,
          lastLat: lastLoc?['lat'] != null
              ? (lastLoc!['lat'] as num).toDouble()
              : null,
          lastLng: lastLoc?['lng'] != null
              ? (lastLoc!['lng'] as num).toDouble()
              : null,
          lastLocationTime:
              lastLoc?['createdAt']?.toString(),
          recentActivity: activityList,
          isPaired: userStatus != null || dashboard != null,
        );
        if (newLatLng != null) {
          _liveLatLng = newLatLng;
        }
        _loading = false;
      });

      // If SOS pending, start flash
      if (sosPending > 0 && !_sosAlert) {
        _triggerSosFlash();
      }

      // Move map to latest location
      if (newLatLng != null) {
        try {
          _mapController.move(newLatLng, 15);
        } catch (_) {}
      }
    } catch (e) {
      setState(() {
        _loading = false;
        _error = _friendlyError(e);
      });
    }
  }

  Future<Map<String, dynamic>?> _fetchDashboard() async {
    try {
      final res = await _api
          .get('/guardian/dashboard')
          .timeout(const Duration(seconds: 8));
      final d = res.data['data'];
      return d is Map ? Map<String, dynamic>.from(d) : null;
    } catch (_) {
      return null;
    }
  }

  Future<List<Map<String, dynamic>>> _fetchActivity() async {
    try {
      final res = await _api
          .get('/guardian/activity-logs',
              queryParameters: {'size': 5, 'page': 0})
          .timeout(const Duration(seconds: 8));
      final data = res.data['data'];
      final content =
          data is Map ? data['content'] : null;
      if (content is List) {
        return content
            .whereType<Map>()
            .map((e) => Map<String, dynamic>.from(e))
            .toList();
      }
    } catch (_) {}
    return const [];
  }

  Future<int> _fetchSosPending() async {
    try {
      final res = await _api
          .get('/guardian/sos-events',
              queryParameters: {'size': 10, 'page': 0})
          .timeout(const Duration(seconds: 8));
      final data = res.data['data'];
      final content =
          data is Map ? data['content'] : null;
      if (content is List) {
        return content
            .whereType<Map>()
            .where((e) => e['status'] == 'TRIGGERED')
            .length;
      }
    } catch (_) {}
    return 0;
  }

  // ── WebSocket subscription ──────────────────────────────────────────────────
  void _subscribeWebSocket() {
    final ws = sl<WebSocketService>();
    Future.microtask(() async {
      try {
        final userId = await _getLinkedUserId();
        if (userId == null) return;
        ws.subscribeLocation(userId, (lat, lng) {
          if (!mounted) return;
          final newPos = LatLng(lat, lng);
          setState(() {
            _liveLatLng = newPos;
            _liveConnected = true;
          });
          try {
            _mapController.move(newPos, 15);
          } catch (_) {}
        });
        ws.subscribeSos((sosData) {
          if (!mounted) return;
          _triggerSosFlash();
          setState(() {
            _data = _data?.copyWith(
                unreadSos: (_data?.unreadSos ?? 0) + 1);
          });
          _showSosSnackbar(sosData);
        });
        if (mounted) setState(() => _liveConnected = true);
      } catch (_) {}
    });
  }

  Future<String?> _getLinkedUserId() async {
    try {
      final res = await _api
          .get('/shared/pairing/status')
          .timeout(const Duration(seconds: 5));
      final d = res.data['data'];
      if (d is Map && d['status'] == 'ACTIVE') {
        return d['pairedWithId']?.toString() ??
            d['userId']?.toString();
      }
    } catch (_) {}
    return null;
  }

  void _triggerSosFlash() {
    if (_sosAlert) return;
    setState(() => _sosAlert = true);
    _sosCtrl.repeat(reverse: true);
    // Auto-dismiss after 30s
    Future.delayed(const Duration(seconds: 30), () {
      if (mounted) {
        setState(() => _sosAlert = false);
        _sosCtrl.stop();
      }
    });
  }

  void _showSosSnackbar(Map<String, dynamic> data) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        backgroundColor: const Color(0xFFDC2626),
        duration: const Duration(seconds: 8),
        content: Row(children: [
          const Icon(Icons.warning_rounded,
              color: Colors.white),
          const SizedBox(width: 10),
          Expanded(
            child: Text(
              '🚨 SOS dari User! Koordinat: ${data['lat']?.toStringAsFixed(4) ?? '-'}, ${data['lng']?.toStringAsFixed(4) ?? '-'}',
              style: const TextStyle(
                  color: Colors.white,
                  fontWeight: FontWeight.w700),
            ),
          ),
        ]),
        action: SnackBarAction(
          label: 'Lihat',
          textColor: Colors.white,
          onPressed: () => context.go('/guardian/logs'),
        ),
      ),
    );
  }

  Future<void> _refresh() async {
    HapticFeedback.lightImpact();
    _refreshCtrl.forward(from: 0);
    await _loadAll(silent: true);
  }

  String _friendlyError(Object e) {
    if (e is DioException) {
      if (e.type == DioExceptionType.connectionError) {
        return 'Tidak bisa ke server. Pastikan backend running.';
      }
      if (e.response?.statusCode == 403) {
        return 'Login sebagai Guardian untuk melihat dashboard.';
      }
    }
    return 'Gagal memuat dashboard. Coba refresh.';
  }

  // ─────────────────────────────────────────────────────────────────────────
  //  BUILD
  // ─────────────────────────────────────────────────────────────────────────
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFFF0F4FF),
      body: SafeArea(
        child: Column(
          children: [
            _buildTopBar(),
            if (_sosAlert) _buildSosBanner(),
            Expanded(
              child: _loading
                  ? _buildSkeleton()
                  : _error != null
                      ? _buildError()
                      : RefreshIndicator(
                          onRefresh: _refresh,
                          color: const Color(0xFF1A56DB),
                          child: SingleChildScrollView(
                            physics:
                                const AlwaysScrollableScrollPhysics(),
                            padding: const EdgeInsets.all(16),
                            child: Column(
                              crossAxisAlignment:
                                  CrossAxisAlignment.start,
                              children: [
                                _buildGreetingRow(),
                                const SizedBox(height: 14),
                                _buildKpiStrip(),
                                const SizedBox(height: 14),
                                _buildMainRow(),
                                const SizedBox(height: 14),
                                _buildActivitySection(),
                                const SizedBox(height: 14),
                                _buildQuickActions(),
                                const SizedBox(height: 8),
                              ],
                            ),
                          ),
                        ),
            ),
          ],
        ),
      ),
    );
  }

  // ── Top bar ─────────────────────────────────────────────────────────────────
  Widget _buildTopBar() {
    return Container(
      height: 56,
      padding: const EdgeInsets.symmetric(horizontal: 16),
      decoration: const BoxDecoration(
        color: Colors.white,
        border: Border(
            bottom:
                BorderSide(color: Color(0xFFE2E8F0), width: 1)),
      ),
      child: Row(children: [
        // Logo
        Container(
          width: 30,
          height: 30,
          decoration: BoxDecoration(
            gradient: const LinearGradient(
              colors: [Color(0xFF1A56DB), Color(0xFF3B82F6)],
              begin: Alignment.topLeft,
              end: Alignment.bottomRight,
            ),
            borderRadius: BorderRadius.circular(8),
          ),
          child: const Icon(Icons.navigation_rounded,
              color: Colors.white, size: 16),
        ),
        const SizedBox(width: 10),
        Text('WalkGuide',
            style: GoogleFonts.outfit(
                fontSize: 16,
                fontWeight: FontWeight.w700,
                color: const Color(0xFF0F172A))),
        const SizedBox(width: 4),
        Container(
          padding:
              const EdgeInsets.symmetric(horizontal: 7, vertical: 2),
          decoration: BoxDecoration(
            color: const Color(0xFFEFF6FF),
            borderRadius: BorderRadius.circular(20),
          ),
          child: Text('Guardian',
              style: GoogleFonts.inter(
                  fontSize: 10,
                  color: const Color(0xFF1A56DB),
                  fontWeight: FontWeight.w600)),
        ),
        const Spacer(),
        // Live dot
        AnimatedBuilder(
          animation: _pulseAnim,
          builder: (_, __) => Row(children: [
            Container(
              width: 8,
              height: 8,
              decoration: BoxDecoration(
                shape: BoxShape.circle,
                color: _liveConnected
                    ? Color.fromRGBO(
                        22, 163, 74, _pulseAnim.value)
                    : const Color(0xFF94A3B8),
                boxShadow: _liveConnected
                    ? [
                        BoxShadow(
                          color: Color.fromRGBO(
                              22, 163, 74, _pulseAnim.value * 0.5),
                          blurRadius: 6,
                          spreadRadius: 2,
                        )
                      ]
                    : null,
              ),
            ),
            const SizedBox(width: 5),
            Text(
              _liveConnected ? 'Live' : 'Offline',
              style: GoogleFonts.inter(
                fontSize: 11,
                fontWeight: FontWeight.w600,
                color: _liveConnected
                    ? const Color(0xFF16A34A)
                    : const Color(0xFF94A3B8),
              ),
            ),
          ]),
        ),
        const SizedBox(width: 12),
        // Refresh
        RotationTransition(
          turns: _refreshCtrl,
          child: IconButton(
            onPressed: _refresh,
            icon: const Icon(Icons.refresh_rounded,
                size: 20, color: Color(0xFF64748B)),
            tooltip: 'Refresh',
          ),
        ),
        const SizedBox(width: 4),
        // Avatar
        CircleAvatar(
          radius: 16,
          backgroundColor: const Color(0xFF1A56DB),
          child: Text(
            _guardianName.isNotEmpty
                ? _guardianName[0].toUpperCase()
                : 'G',
            style: GoogleFonts.outfit(
                color: Colors.white,
                fontSize: 13,
                fontWeight: FontWeight.w700),
          ),
        ),
      ]),
    );
  }

  // ── SOS banner ──────────────────────────────────────────────────────────────
  Widget _buildSosBanner() {
    return AnimatedBuilder(
      animation: _sosCtrl,
      builder: (_, __) => Container(
        color: Color.lerp(const Color(0xFFDC2626),
            const Color(0xFFFF6B6B), _sosCtrl.value),
        padding:
            const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
        child: Row(children: [
          const Icon(Icons.warning_rounded,
              color: Colors.white, size: 18),
          const SizedBox(width: 10),
          Expanded(
            child: Text(
              '🚨 SOS AKTIF — User membutuhkan bantuan segera!',
              style: GoogleFonts.inter(
                  color: Colors.white,
                  fontWeight: FontWeight.w700,
                  fontSize: 13),
            ),
          ),
          TextButton(
            onPressed: () => context.go('/guardian/logs'),
            style: TextButton.styleFrom(
                foregroundColor: Colors.white),
            child: const Text('Tangani'),
          ),
          IconButton(
            onPressed: () {
              setState(() => _sosAlert = false);
              _sosCtrl.stop();
            },
            icon: const Icon(Icons.close,
                color: Colors.white, size: 16),
            padding: EdgeInsets.zero,
          ),
        ]),
      ),
    );
  }

  // ── Greeting row ────────────────────────────────────────────────────────────
  Widget _buildGreetingRow() {
    final hour = DateTime.now().hour;
    final greeting = hour < 12
        ? 'Selamat pagi'
        : hour < 17
            ? 'Selamat siang'
            : 'Selamat malam';
    return Row(
      children: [
        Expanded(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                '$greeting, $_guardianName',
                style: GoogleFonts.outfit(
                    fontSize: 20,
                    fontWeight: FontWeight.w700,
                    color: const Color(0xFF0F172A)),
              ),
              Text(
                _data?.isPaired == true
                    ? 'Memantau ${_data?.userName ?? "User"} secara real-time'
                    : 'Belum terhubung dengan User',
                style: GoogleFonts.inter(
                    fontSize: 12,
                    color: const Color(0xFF64748B)),
              ),
            ],
          ),
        ),
        if (_data?.unreadSos != null && _data!.unreadSos > 0)
          _SosBadge(count: _data!.unreadSos),
      ],
    );
  }

  // ── KPI strip ───────────────────────────────────────────────────────────────
  Widget _buildKpiStrip() {
    if (_data == null) return const SizedBox.shrink();
    final d = _data!;
    return Row(children: [
      Expanded(
          child: _KpiCard(
        label: 'Status',
        value: d.isPaired
            ? (d.userOnline ? 'Online' : 'Offline')
            : 'Belum Pair',
        valueColor: d.isPaired && d.userOnline
            ? const Color(0xFF16A34A)
            : const Color(0xFF94A3B8),
        icon: Icons.person_outline,
        sub: d.isPaired
            ? (d.userOnline ? 'Aktif berjalan' : _formatLastSeen(d.userLastSeen))
            : 'Buka menu Pairing',
      )),
      const SizedBox(width: 10),
      Expanded(
          child: _KpiCard(
        label: 'Baterai',
        value:
            d.battery != null ? '${d.battery}%' : '—',
        valueColor: d.battery != null && d.battery! < 20
            ? const Color(0xFFDC2626)
            : const Color(0xFF0F172A),
        icon: Icons.battery_std_outlined,
        sub: d.battery != null
            ? (d.battery! > 50
                ? 'Baterai cukup'
                : 'Baterai hampir habis')
            : 'Belum tersedia',
      )),
      const SizedBox(width: 10),
      Expanded(
          child: _KpiCard(
        label: 'Obstacle Hari Ini',
        value: '${d.obstaclesTotal}',
        valueColor: d.obstaclesTotal > 10
            ? const Color(0xFFD97706)
            : const Color(0xFF0F172A),
        icon: Icons.radar_outlined,
        sub: d.obstaclesTotal > 0
            ? 'AI deteksi aktif'
            : 'Belum ada deteksi',
      )),
      const SizedBox(width: 10),
      Expanded(
          child: _KpiCard(
        label: 'SOS Pending',
        value: '${d.unreadSos}',
        valueColor: d.unreadSos > 0
            ? const Color(0xFFDC2626)
            : const Color(0xFF16A34A),
        icon: Icons.sos_outlined,
        sub: d.unreadSos > 0
            ? 'Perlu perhatian!'
            : 'Aman',
        highlight: d.unreadSos > 0,
      )),
    ]);
  }

  // ── Main row: map + user card ────────────────────────────────────────────────
  Widget _buildMainRow() {
    return IntrinsicHeight(
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Expanded(flex: 3, child: _buildMapCard()),
          const SizedBox(width: 12),
          SizedBox(width: 180, child: _buildUserCard()),
        ],
      ),
    );
  }

  // ── Map card ─────────────────────────────────────────────────────────────────
  Widget _buildMapCard() {
    final pos = _liveLatLng ??
        (_data?.lastLat != null && _data?.lastLng != null
            ? LatLng(_data!.lastLat!, _data!.lastLng!)
            : null);

    return Container(
      height: 220,
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(16),
        border:
            Border.all(color: const Color(0xFFE2E8F0), width: 1),
        boxShadow: [
          BoxShadow(
              color: Colors.black.withValues(alpha: 0.04),
              blurRadius: 12,
              offset: const Offset(0, 2)),
        ],
      ),
      child: ClipRRect(
        borderRadius: BorderRadius.circular(16),
        child: Stack(children: [
          // Map or placeholder
          if (pos != null)
            FlutterMap(
              mapController: _mapController,
              options: MapOptions(
                  initialCenter: pos, initialZoom: 15),
              children: [
                TileLayer(
                  urlTemplate:
                      'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
                  userAgentPackageName: 'com.walkguide.app',
                ),
                MarkerLayer(markers: [
                  Marker(
                    point: pos,
                    width: 48,
                    height: 48,
                    child: AnimatedBuilder(
                      animation: _pulseAnim,
                      builder: (_, __) => Stack(
                        alignment: Alignment.center,
                        children: [
                          Container(
                            width: 32 * _pulseAnim.value,
                            height: 32 * _pulseAnim.value,
                            decoration: BoxDecoration(
                              shape: BoxShape.circle,
                              color: const Color(0xFF1A56DB)
                                  .withValues(alpha: 0.25 * _pulseAnim.value),
                            ),
                          ),
                          Container(
                            width: 16,
                            height: 16,
                            decoration: const BoxDecoration(
                              shape: BoxShape.circle,
                              color: Color(0xFF1A56DB),
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ]),
              ],
            )
          else
            Container(
              color: const Color(0xFFF1F5F9),
              child: Center(
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Icon(Icons.map_outlined,
                        size: 48,
                        color: const Color(0xFFCBD5E1)),
                    const SizedBox(height: 8),
                    Text(
                      _data?.isPaired == true
                          ? 'Belum ada lokasi terbaru'
                          : 'Pairing dulu untuk melihat peta',
                      style: GoogleFonts.inter(
                          fontSize: 12,
                          color: const Color(0xFF94A3B8)),
                    ),
                  ],
                ),
              ),
            ),

          // Header overlay
          Positioned(
            top: 10,
            left: 10,
            right: 10,
            child: Row(children: [
              Container(
                padding: const EdgeInsets.symmetric(
                    horizontal: 10, vertical: 5),
                decoration: BoxDecoration(
                  color: Colors.white.withValues(alpha: 0.92),
                  borderRadius: BorderRadius.circular(20),
                  boxShadow: [
                    BoxShadow(
                        color: Colors.black.withValues(alpha: 0.1),
                        blurRadius: 8),
                  ],
                ),
                child: Row(children: [
                  Container(
                    width: 7,
                    height: 7,
                    decoration: BoxDecoration(
                      shape: BoxShape.circle,
                      color: _liveConnected
                          ? const Color(0xFF16A34A)
                          : const Color(0xFF94A3B8),
                    ),
                  ),
                  const SizedBox(width: 5),
                  Text(
                    _liveConnected
                        ? 'Live Tracking'
                        : pos != null
                            ? 'Lokasi Terakhir'
                            : 'Menunggu GPS',
                    style: GoogleFonts.inter(
                        fontSize: 11,
                        fontWeight: FontWeight.w600,
                        color: const Color(0xFF0F172A)),
                  ),
                ]),
              ),
              const Spacer(),
              GestureDetector(
                onTap: () => context.go('/guardian/map'),
                child: Container(
                  padding: const EdgeInsets.symmetric(
                      horizontal: 10, vertical: 5),
                  decoration: BoxDecoration(
                    color:
                        const Color(0xFF1A56DB).withValues(alpha: 0.9),
                    borderRadius: BorderRadius.circular(20),
                  ),
                  child: Text('Buka Peta',
                      style: GoogleFonts.inter(
                          fontSize: 11,
                          color: Colors.white,
                          fontWeight: FontWeight.w600)),
                ),
              ),
            ]),
          ),

          // Coordinates footer
          if (pos != null)
            Positioned(
              bottom: 10,
              left: 10,
              child: Container(
                padding: const EdgeInsets.symmetric(
                    horizontal: 10, vertical: 6),
                decoration: BoxDecoration(
                  color: Colors.white.withValues(alpha: 0.92),
                  borderRadius: BorderRadius.circular(8),
                  boxShadow: [
                    BoxShadow(
                        color: Colors.black.withValues(alpha: 0.08),
                        blurRadius: 6),
                  ],
                ),
                child: Text(
                  '${pos.latitude.toStringAsFixed(5)}, ${pos.longitude.toStringAsFixed(5)}',
                  style: GoogleFonts.jetBrainsMono(
                      fontSize: 10,
                      color: const Color(0xFF0F172A),
                      fontWeight: FontWeight.w500),
                ),
              ),
            ),
        ]),
      ),
    );
  }

  // ── User card ─────────────────────────────────────────────────────────────────
  Widget _buildUserCard() {
    if (_data?.isPaired != true) {
      return _buildNoPairingCard();
    }
    final d = _data!;
    return Container(
      padding: const EdgeInsets.all(14),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(16),
        border: Border.all(color: const Color(0xFFE2E8F0)),
        boxShadow: [
          BoxShadow(
              color: Colors.black.withValues(alpha: 0.04),
              blurRadius: 12,
              offset: const Offset(0, 2)),
        ],
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          // Avatar + name
          Row(children: [
            CircleAvatar(
              radius: 20,
              backgroundColor:
                  const Color(0xFF1A56DB).withValues(alpha: 0.1),
              child: Text(
                d.userName.isNotEmpty
                    ? d.userName[0].toUpperCase()
                    : 'U',
                style: GoogleFonts.outfit(
                    fontSize: 16,
                    color: const Color(0xFF1A56DB),
                    fontWeight: FontWeight.w700),
              ),
            ),
            const SizedBox(width: 8),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(d.userName,
                      style: GoogleFonts.inter(
                          fontSize: 12,
                          fontWeight: FontWeight.w700,
                          color: const Color(0xFF0F172A)),
                      maxLines: 1,
                      overflow: TextOverflow.ellipsis),
                  Row(children: [
                    Container(
                      width: 6,
                      height: 6,
                      decoration: BoxDecoration(
                        shape: BoxShape.circle,
                        color: d.userOnline
                            ? const Color(0xFF16A34A)
                            : const Color(0xFF94A3B8),
                      ),
                    ),
                    const SizedBox(width: 4),
                    Text(
                        d.userOnline ? 'Online' : 'Offline',
                        style: GoogleFonts.inter(
                            fontSize: 10,
                            color: d.userOnline
                                ? const Color(0xFF16A34A)
                                : const Color(0xFF94A3B8))),
                  ]),
                ],
              ),
            ),
          ]),
          const SizedBox(height: 14),
          const Divider(height: 1, color: Color(0xFFF1F5F9)),
          const SizedBox(height: 12),

          // Stats grid
          _buildStatRow(
              Icons.battery_std_outlined,
              'Baterai',
              d.battery != null ? '${d.battery}%' : '—',
              d.battery != null && d.battery! < 20
                  ? const Color(0xFFDC2626)
                  : const Color(0xFF16A34A)),
          const SizedBox(height: 8),
          _buildStatRow(
              Icons.speed_outlined,
              'Kecepatan',
              d.speed != null
                  ? '${(d.speed! * 3.6).toStringAsFixed(1)} km/h'
                  : '—',
              const Color(0xFF1A56DB)),
          const SizedBox(height: 8),
          _buildStatRow(
              Icons.radar_outlined,
              'Obstacle',
              '${d.obstaclesTotal} hari ini',
              d.obstaclesTotal > 5
                  ? const Color(0xFFD97706)
                  : const Color(0xFF0F172A)),
          const SizedBox(height: 8),
          _buildStatRow(
              Icons.notifications_outlined,
              'Notif Belum Dibaca',
              '${d.unreadNotif}',
              d.unreadNotif > 0
                  ? const Color(0xFF7C3AED)
                  : const Color(0xFF0F172A)),

          const Spacer(),

          // Call button
          SizedBox(
            width: double.infinity,
            child: FilledButton.icon(
              onPressed: () => context.go('/user/call'),
              icon: const Icon(Icons.call, size: 14),
              label: const Text('Hubungi User'),
              style: FilledButton.styleFrom(
                backgroundColor: const Color(0xFF16A34A),
                padding: const EdgeInsets.symmetric(vertical: 8),
                textStyle: GoogleFonts.inter(
                    fontSize: 12, fontWeight: FontWeight.w600),
              ),
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildStatRow(
      IconData icon, String label, String value, Color valueColor) {
    return Row(children: [
      Icon(icon, size: 14, color: const Color(0xFF94A3B8)),
      const SizedBox(width: 6),
      Expanded(
        child: Text(label,
            style: GoogleFonts.inter(
                fontSize: 10, color: const Color(0xFF64748B))),
      ),
      Text(value,
          style: GoogleFonts.outfit(
              fontSize: 12,
              fontWeight: FontWeight.w700,
              color: valueColor)),
    ]);
  }

  Widget _buildNoPairingCard() {
    return Container(
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: const Color(0xFFFFFBEB),
        borderRadius: BorderRadius.circular(16),
        border: Border.all(color: const Color(0xFFFDE68A)),
      ),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const Icon(Icons.link_off,
              color: Color(0xFFD97706), size: 40),
          const SizedBox(height: 12),
          Text('Belum Pairing',
              style: GoogleFonts.outfit(
                  fontSize: 14,
                  fontWeight: FontWeight.w700,
                  color: const Color(0xFF92400E))),
          const SizedBox(height: 6),
          Text(
            'Masukkan Unique ID User untuk mulai memantau.',
            style: GoogleFonts.inter(
                fontSize: 11, color: const Color(0xFF92400E)),
            textAlign: TextAlign.center,
          ),
          const SizedBox(height: 14),
          SizedBox(
            width: double.infinity,
            child: FilledButton(
              onPressed: () => context.go('/guardian/pairing'),
              style: FilledButton.styleFrom(
                  backgroundColor: const Color(0xFFD97706),
                  padding: const EdgeInsets.symmetric(vertical: 8)),
              child: Text('Pair Sekarang',
                  style: GoogleFonts.inter(
                      fontSize: 12,
                      fontWeight: FontWeight.w600)),
            ),
          ),
        ],
      ),
    );
  }

  // ── Activity section ─────────────────────────────────────────────────────────
  Widget _buildActivitySection() {
    final items = _data?.recentActivity ?? const [];
    return Container(
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(16),
        border: Border.all(color: const Color(0xFFE2E8F0)),
        boxShadow: [
          BoxShadow(
              color: Colors.black.withValues(alpha: 0.04),
              blurRadius: 12,
              offset: const Offset(0, 2)),
        ],
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Padding(
            padding:
                const EdgeInsets.fromLTRB(16, 14, 12, 10),
            child: Row(children: [
              Text('Aktivitas Terkini',
                  style: GoogleFonts.outfit(
                      fontSize: 14,
                      fontWeight: FontWeight.w700,
                      color: const Color(0xFF0F172A))),
              const Spacer(),
              TextButton.icon(
                onPressed: () => context.go('/guardian/logs'),
                icon: const Icon(Icons.open_in_new, size: 13),
                label: Text('Semua',
                    style: GoogleFonts.inter(fontSize: 12)),
                style: TextButton.styleFrom(
                    foregroundColor: const Color(0xFF1A56DB),
                    padding: const EdgeInsets.symmetric(
                        horizontal: 8, vertical: 4)),
              ),
            ]),
          ),
          if (items.isEmpty)
            Padding(
              padding: const EdgeInsets.all(20),
              child: Center(
                child: Text(
                  _data?.isPaired == true
                      ? 'Belum ada aktivitas. Minta User start WalkGuide.'
                      : 'Aktivitas akan muncul setelah pairing.',
                  style: GoogleFonts.inter(
                      fontSize: 12,
                      color: const Color(0xFF94A3B8)),
                  textAlign: TextAlign.center,
                ),
              ),
            )
          else
            ...items.asMap().entries.map((entry) {
              final i = entry.key;
              final item = entry.value;
              return Column(children: [
                if (i == 0)
                  const Divider(
                      height: 1, color: Color(0xFFF1F5F9)),
                _ActivityTile(data: item),
              ]);
            }),
          const SizedBox(height: 4),
        ],
      ),
    );
  }

  // ── Quick actions ─────────────────────────────────────────────────────────────
  Widget _buildQuickActions() {
    final actions = [
      _ActionItem(
        icon: Icons.map_outlined,
        label: 'Live Map',
        sub: 'Lacak lokasi',
        color: const Color(0xFF1A56DB),
        onTap: () => context.go('/guardian/map'),
      ),
      _ActionItem(
        icon: Icons.send_outlined,
        label: 'Kirim Pesan',
        sub: 'Text / suara',
        color: const Color(0xFF7C3AED),
        onTap: () => context.go('/guardian/send-notif'),
      ),
      _ActionItem(
        icon: Icons.tune_outlined,
        label: 'AI Config',
        sub: 'Sesuaikan YOLO',
        color: const Color(0xFF0891B2),
        onTap: () => context.go('/guardian/ai-config'),
      ),
      _ActionItem(
        icon: Icons.record_voice_over_outlined,
        label: 'Voice Cmd',
        sub: 'Atur perintah',
        color: const Color(0xFF059669),
        onTap: () => context.go('/guardian/voice-cmd'),
      ),
      _ActionItem(
        icon: Icons.fence_outlined,
        label: 'Geofence',
        sub: 'Area aman',
        color: const Color(0xFFD97706),
        onTap: () => context.go('/guardian/geofence'),
      ),
      _ActionItem(
        icon: Icons.fact_check_outlined,
        label: 'Log Lengkap',
        sub: 'Semua aktivitas',
        color: const Color(0xFF64748B),
        onTap: () => context.go('/guardian/logs'),
      ),
    ];

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Padding(
          padding: const EdgeInsets.only(bottom: 10),
          child: Text('Aksi Cepat',
              style: GoogleFonts.outfit(
                  fontSize: 14,
                  fontWeight: FontWeight.w700,
                  color: const Color(0xFF0F172A))),
        ),
        GridView.count(
          crossAxisCount: 3,
          shrinkWrap: true,
          physics: const NeverScrollableScrollPhysics(),
          crossAxisSpacing: 10,
          mainAxisSpacing: 10,
          childAspectRatio: 1.4,
          children: actions
              .map((a) => _QuickActionCard(item: a))
              .toList(),
        ),
      ],
    );
  }

  // ── Loading skeleton ──────────────────────────────────────────────────────────
  Widget _buildSkeleton() {
    return SingleChildScrollView(
      padding: const EdgeInsets.all(16),
      child: Column(children: [
        _SkeletonBox(height: 32, width: double.infinity,
            borderRadius: 8),
        const SizedBox(height: 14),
        Row(children: List.generate(
            4,
            (i) => Expanded(
                  child: Padding(
                    padding: EdgeInsets.only(
                        right: i < 3 ? 10 : 0),
                    child: _SkeletonBox(
                        height: 80,
                        width: double.infinity,
                        borderRadius: 12),
                  ),
                ))),
        const SizedBox(height: 14),
        _SkeletonBox(
            height: 220, width: double.infinity, borderRadius: 16),
        const SizedBox(height: 14),
        _SkeletonBox(
            height: 160, width: double.infinity, borderRadius: 16),
      ]),
    );
  }

  // ── Error state ───────────────────────────────────────────────────────────────
  Widget _buildError() {
    return Center(
      child: Padding(
        padding: const EdgeInsets.all(32),
        child: Column(mainAxisSize: MainAxisSize.min, children: [
          const Icon(Icons.cloud_off_outlined,
              size: 64, color: Color(0xFF94A3B8)),
          const SizedBox(height: 16),
          Text(_error ?? 'Gagal memuat',
              textAlign: TextAlign.center,
              style: GoogleFonts.inter(
                  color: const Color(0xFF64748B), fontSize: 14)),
          const SizedBox(height: 20),
          FilledButton.icon(
            onPressed: _loadAll,
            icon: const Icon(Icons.refresh),
            label: const Text('Coba Lagi'),
          ),
        ]),
      ),
    );
  }

  String _formatLastSeen(String? iso) {
    if (iso == null) return 'Belum pernah aktif';
    final dt = DateTime.tryParse(iso)?.toLocal();
    if (dt == null) return 'Waktu tidak diketahui';
    final diff = DateTime.now().difference(dt);
    if (diff.inMinutes < 1) return 'Baru saja';
    if (diff.inMinutes < 60) return '${diff.inMinutes}m lalu';
    if (diff.inHours < 24) return '${diff.inHours}j lalu';
    return '${diff.inDays}h lalu';
  }
}

// ─────────────────────────────────────────────────────────────────────────────
//  DATA MODELS
// ─────────────────────────────────────────────────────────────────────────────

class _DashboardData {
  final String userName;
  final bool userOnline;
  final String? userLastSeen;
  final int? battery;
  final double? speed;
  final int obstaclesTotal;
  final int unreadNotif;
  final int unreadSos;
  final double? lastLat;
  final double? lastLng;
  final String? lastLocationTime;
  final List<Map<String, dynamic>> recentActivity;
  final bool isPaired;

  const _DashboardData({
    required this.userName,
    required this.userOnline,
    this.userLastSeen,
    this.battery,
    this.speed,
    required this.obstaclesTotal,
    required this.unreadNotif,
    required this.unreadSos,
    this.lastLat,
    this.lastLng,
    this.lastLocationTime,
    required this.recentActivity,
    required this.isPaired,
  });

  _DashboardData copyWith({int? unreadSos}) {
    return _DashboardData(
      userName: userName,
      userOnline: userOnline,
      userLastSeen: userLastSeen,
      battery: battery,
      speed: speed,
      obstaclesTotal: obstaclesTotal,
      unreadNotif: unreadNotif,
      unreadSos: unreadSos ?? this.unreadSos,
      lastLat: lastLat,
      lastLng: lastLng,
      lastLocationTime: lastLocationTime,
      recentActivity: recentActivity,
      isPaired: isPaired,
    );
  }
}

class _ActionItem {
  final IconData icon;
  final String label;
  final String sub;
  final Color color;
  final VoidCallback onTap;
  const _ActionItem({
    required this.icon,
    required this.label,
    required this.sub,
    required this.color,
    required this.onTap,
  });
}

// ─────────────────────────────────────────────────────────────────────────────
//  SUB-WIDGETS
// ─────────────────────────────────────────────────────────────────────────────

class _KpiCard extends StatelessWidget {
  final String label;
  final String value;
  final Color valueColor;
  final IconData icon;
  final String sub;
  final bool highlight;

  const _KpiCard({
    required this.label,
    required this.value,
    required this.valueColor,
    required this.icon,
    required this.sub,
    this.highlight = false,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(12),
      decoration: BoxDecoration(
        color:
            highlight ? const Color(0xFFFFF1F2) : Colors.white,
        borderRadius: BorderRadius.circular(12),
        border: Border.all(
            color: highlight
                ? const Color(0xFFFECACA)
                : const Color(0xFFE2E8F0),
            width: 1),
        boxShadow: [
          BoxShadow(
              color: Colors.black.withValues(alpha: 0.03),
              blurRadius: 8),
        ],
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(children: [
            Icon(icon, size: 13, color: valueColor),
            const SizedBox(width: 4),
            Expanded(
              child: Text(label,
                  style: GoogleFonts.inter(
                      fontSize: 10,
                      color: const Color(0xFF94A3B8),
                      letterSpacing: 0.02),
                  overflow: TextOverflow.ellipsis),
            ),
          ]),
          const SizedBox(height: 6),
          Text(value,
              style: GoogleFonts.outfit(
                  fontSize: 20,
                  fontWeight: FontWeight.w700,
                  color: valueColor)),
          const SizedBox(height: 2),
          Text(sub,
              style: GoogleFonts.inter(
                  fontSize: 10,
                  color: highlight
                      ? const Color(0xFFDC2626)
                      : const Color(0xFF64748B)),
              overflow: TextOverflow.ellipsis),
        ],
      ),
    );
  }
}

class _ActivityTile extends StatelessWidget {
  final Map<String, dynamic> data;
  const _ActivityTile({required this.data});

  @override
  Widget build(BuildContext context) {
    final logType = data['logType']?.toString() ?? '';
    final cfg = _activityConfig(logType);
    final created =
        DateTime.tryParse(data['createdAt']?.toString() ?? '')
            ?.toLocal();
    final timeStr = created == null
        ? ''
        : '${_two(created.hour)}:${_two(created.minute)}';
    final desc =
        data['description']?.toString() ?? logType;

    return Padding(
      padding:
          const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
      child: Row(children: [
        Container(
          width: 32,
          height: 32,
          decoration: BoxDecoration(
            color: cfg.color.withValues(alpha: 0.1),
            borderRadius: BorderRadius.circular(8),
          ),
          child: Icon(cfg.icon, size: 16, color: cfg.color),
        ),
        const SizedBox(width: 12),
        Expanded(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                cfg.label,
                style: GoogleFonts.inter(
                    fontSize: 12,
                    fontWeight: FontWeight.w600,
                    color: const Color(0xFF0F172A)),
              ),
              Text(
                desc,
                style: GoogleFonts.inter(
                    fontSize: 11,
                    color: const Color(0xFF64748B)),
                maxLines: 1,
                overflow: TextOverflow.ellipsis,
              ),
            ],
          ),
        ),
        if (timeStr.isNotEmpty)
          Text(timeStr,
              style: GoogleFonts.jetBrainsMono(
                  fontSize: 10, color: const Color(0xFF94A3B8))),
      ]),
    );
  }
}

class _QuickActionCard extends StatelessWidget {
  final _ActionItem item;
  const _QuickActionCard({required this.item});

  @override
  Widget build(BuildContext context) {
    return Material(
      color: Colors.white,
      borderRadius: BorderRadius.circular(12),
      child: InkWell(
        onTap: item.onTap,
        borderRadius: BorderRadius.circular(12),
        child: Container(
          padding: const EdgeInsets.all(10),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(12),
            border:
                Border.all(color: const Color(0xFFE2E8F0)),
          ),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Container(
                width: 28,
                height: 28,
                decoration: BoxDecoration(
                  color: item.color.withValues(alpha: 0.1),
                  borderRadius: BorderRadius.circular(7),
                ),
                child: Icon(item.icon,
                    size: 15, color: item.color),
              ),
              const SizedBox(height: 6),
              Text(item.label,
                  style: GoogleFonts.inter(
                      fontSize: 11,
                      fontWeight: FontWeight.w700,
                      color: const Color(0xFF0F172A)),
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis),
              Text(item.sub,
                  style: GoogleFonts.inter(
                      fontSize: 10,
                      color: const Color(0xFF94A3B8)),
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis),
            ],
          ),
        ),
      ),
    );
  }
}

class _SosBadge extends StatelessWidget {
  final int count;
  const _SosBadge({required this.count});

  @override
  Widget build(BuildContext context) {
    return Container(
      padding:
          const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
      decoration: BoxDecoration(
        color: const Color(0xFFDC2626),
        borderRadius: BorderRadius.circular(20),
        boxShadow: [
          BoxShadow(
              color: const Color(0xFFDC2626).withValues(alpha: 0.4),
              blurRadius: 8,
              spreadRadius: 1),
        ],
      ),
      child: Row(mainAxisSize: MainAxisSize.min, children: [
        const Icon(Icons.warning_rounded,
            color: Colors.white, size: 13),
        const SizedBox(width: 4),
        Text('$count SOS',
            style: GoogleFonts.inter(
                color: Colors.white,
                fontSize: 11,
                fontWeight: FontWeight.w700)),
      ]),
    );
  }
}

class _SkeletonBox extends StatefulWidget {
  final double height;
  final double width;
  final double borderRadius;
  const _SkeletonBox(
      {required this.height,
      required this.width,
      required this.borderRadius});

  @override
  State<_SkeletonBox> createState() => _SkeletonBoxState();
}

class _SkeletonBoxState extends State<_SkeletonBox>
    with SingleTickerProviderStateMixin {
  late final AnimationController _ctrl = AnimationController(
    vsync: this,
    duration: const Duration(milliseconds: 1200),
  )..repeat(reverse: true);

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

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _ctrl,
      builder: (_, __) => Container(
        height: widget.height,
        width: widget.width,
        decoration: BoxDecoration(
          borderRadius:
              BorderRadius.circular(widget.borderRadius),
          color: Color.lerp(const Color(0xFFE2E8F0),
              const Color(0xFFF8FAFC), _ctrl.value),
        ),
      ),
    );
  }
}

// ─────────────────────────────────────────────────────────────────────────────
//  HELPERS
// ─────────────────────────────────────────────────────────────────────────────

class _ActivityCfg {
  final IconData icon;
  final Color color;
  final String label;
  const _ActivityCfg(this.icon, this.color, this.label);
}

_ActivityCfg _activityConfig(String logType) {
  switch (logType.toUpperCase()) {
    case 'WALKGUIDE_START':
      return const _ActivityCfg(
          Icons.play_circle_outline, Color(0xFF16A34A), 'WalkGuide Dimulai');
    case 'WALKGUIDE_STOP':
      return const _ActivityCfg(
          Icons.stop_circle_outlined, Color(0xFF64748B), 'WalkGuide Berhenti');
    case 'OBSTACLE_DETECTED':
      return const _ActivityCfg(
          Icons.warning_amber_outlined, Color(0xFFD97706), 'Obstacle Terdeteksi');
    case 'SOS_TRIGGERED':
      return const _ActivityCfg(
          Icons.sos_outlined, Color(0xFFDC2626), 'SOS Dikirim');
    case 'SOS_ACKNOWLEDGED':
      return const _ActivityCfg(
          Icons.check_circle_outline, Color(0xFF16A34A), 'SOS Ditanggapi');
    case 'LOCATION_UPDATE':
      return const _ActivityCfg(
          Icons.location_on_outlined, Color(0xFF1A56DB), 'Update Lokasi');
    case 'GEOFENCE_EXIT':
      return const _ActivityCfg(
          Icons.fence_outlined, Color(0xFFDC2626), 'Keluar Geofence');
    case 'GEOFENCE_ENTER':
      return const _ActivityCfg(
          Icons.home_outlined, Color(0xFF16A34A), 'Masuk Geofence');
    case 'CALL_INITIATED':
      return const _ActivityCfg(
          Icons.call_outlined, Color(0xFF7C3AED), 'Panggilan Dimulai');
    case 'CALL_ENDED':
      return const _ActivityCfg(
          Icons.call_end_outlined, Color(0xFF94A3B8), 'Panggilan Selesai');
    case 'LOGIN':
      return const _ActivityCfg(
          Icons.login_outlined, Color(0xFF1A56DB), 'Login');
    case 'LOGOUT':
      return const _ActivityCfg(
          Icons.logout_outlined, Color(0xFF64748B), 'Logout');
    default:
      return const _ActivityCfg(
          Icons.circle_outlined, Color(0xFF94A3B8), 'Aktivitas');
  }
}

String _two(int v) => v.toString().padLeft(2, '0');
