import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../../core/chat/chat_request_notifier.dart';
import '../../core/theme/halo_tokens.dart';
import '../../core/theme/widgets/halo_button.dart';
import '../../core/theme/widgets/halo_orb.dart';

/// Single source of truth for which Undangan sub-tab is currently selected.
/// 0 = Curhat Baru, 1 = Perpanjang Curhat. Home tiles write this before
/// switching to the Chat tab; UndanganScreen reads it on init to position
/// its TabController.
final undanganTabProvider = StateProvider<int>((_) => 0);

/// Undangan (Invitations) screen for the Chat tab of the Bestie shell.
///
/// Mirrors `figma-bestie/project/screens/v4.jsx::BestieInvites` for the
/// Curhat Baru tab and `figma-bestie/project/screens/v5.jsx::BestieInvitesExtend`
/// for the Perpanjang Curhat tab.
///
/// The Curhat Baru tab is wired to `chatRequestProvider` and lists every
/// pending invitation (the popup overlay shows ONE — this screen shows ALL).
/// Accept / Tolak buttons share the same notifier methods as the popup so
/// both surfaces stay in sync.
///
/// The Perpanjang tab is an empty-state placeholder until the backend
/// exposes a queryable stream of pending extension invitations.
///
/// `BestieTabBar` is rendered by the parent `ShellScreen`; this widget
/// only owns its own header + tabs + content area.
class UndanganScreen extends ConsumerStatefulWidget {
  const UndanganScreen({super.key});

  @override
  ConsumerState<UndanganScreen> createState() => _UndanganScreenState();
}

class _UndanganScreenState extends ConsumerState<UndanganScreen>
    with SingleTickerProviderStateMixin {
  late final TabController _tabController;

  @override
  void initState() {
    super.initState();
    // Use `ref.read` (not watch) — initState runs once, we don't want a rebuild.
    // Home tiles set this provider before calling `goBranch(1)` so the tab
    // controller lands on the correct sub-tab from the very first frame.
    final initialIndex = ref.read(undanganTabProvider);
    _tabController = TabController(
      length: 2,
      vsync: this,
      initialIndex: initialIndex,
    );
  }

  @override
  void dispose() {
    // TabController doesn't touch ref — safe to dispose here.
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    // If we're already mounted on this screen and a Home tile re-selects a
    // sub-tab, animate to it. (Initial position is handled by initState.)
    ref.listen<int>(undanganTabProvider, (prev, next) {
      if (next != _tabController.index) {
        _tabController.animateTo(next);
      }
    });

    // Watch so the list rebuilds on every state change (new request, accept,
    // decline, queue advance). The actual list is read via the notifier getter
    // so we don't tie the rebuild to one specific state subtype.
    ref.watch(chatRequestProvider);
    final invites = ref.read(chatRequestProvider.notifier).pendingInvites;

    return Scaffold(
      backgroundColor: HaloTokens.bg,
      body: SafeArea(
        child: Column(
          children: [
            const _UndanganHeader(),
            _UndanganTabBar(
              controller: _tabController,
              newCount: invites.length,
              extendCount: 0,
            ),
            Expanded(
              child: TabBarView(
                controller: _tabController,
                children: [
                  _CurhatBaruTab(invites: invites),
                  const _PerpanjangTab(),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}

// ─── Header ────────────────────────────────────────────────────────────────

class _UndanganHeader extends StatelessWidget {
  const _UndanganHeader();

  @override
  Widget build(BuildContext context) {
    return const Padding(
      padding: EdgeInsets.fromLTRB(20, 20, 20, 8),
      child: Align(
        alignment: Alignment.centerLeft,
        child: Text(
          'Undangan',
          style: TextStyle(
            fontFamily: HaloTokens.fontDisplay,
            fontSize: 20,
            fontWeight: FontWeight.w700,
            color: HaloTokens.ink,
          ),
        ),
      ),
    );
  }
}

// ─── Tab bar ───────────────────────────────────────────────────────────────

class _UndanganTabBar extends StatelessWidget {
  final TabController controller;
  final int newCount;
  final int extendCount;

  const _UndanganTabBar({
    required this.controller,
    required this.newCount,
    required this.extendCount,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: const BoxDecoration(
        border: Border(
          bottom: BorderSide(color: HaloTokens.border, width: 1),
        ),
      ),
      padding: const EdgeInsets.symmetric(horizontal: 12),
      child: TabBar(
        controller: controller,
        labelColor: HaloTokens.brand,
        unselectedLabelColor: HaloTokens.inkSoft,
        indicatorColor: HaloTokens.brand,
        indicatorWeight: 2,
        labelStyle: const TextStyle(
          fontFamily: HaloTokens.fontBody,
          fontSize: 13.5,
          fontWeight: FontWeight.w700,
        ),
        unselectedLabelStyle: const TextStyle(
          fontFamily: HaloTokens.fontBody,
          fontSize: 13.5,
          fontWeight: FontWeight.w500,
        ),
        tabs: [
          _TabLabel(label: 'Curhat Baru', count: newCount),
          _TabLabel(
            label: 'Perpanjang Curhat',
            count: extendCount,
            accent: HaloTokens.accentAmber,
          ),
        ],
      ),
    );
  }
}

class _TabLabel extends StatelessWidget {
  final String label;
  final int count;
  final Color? accent;

  const _TabLabel({required this.label, required this.count, this.accent});

  @override
  Widget build(BuildContext context) {
    return Tab(
      height: 44,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        mainAxisSize: MainAxisSize.min,
        children: [
          Text(label),
          if (count > 0) ...[
            const SizedBox(width: 6),
            Container(
              width: 16,
              height: 16,
              alignment: Alignment.center,
              decoration: BoxDecoration(
                color: accent ?? const Color(0xFFFF4D6A),
                shape: BoxShape.circle,
              ),
              child: Text(
                count > 9 ? '9+' : '$count',
                style: const TextStyle(
                  fontFamily: HaloTokens.fontBody,
                  fontSize: 9,
                  fontWeight: FontWeight.w700,
                  color: Colors.white,
                ),
              ),
            ),
          ],
        ],
      ),
    );
  }
}

// ─── Curhat Baru tab ──────────────────────────────────────────────────────

class _CurhatBaruTab extends ConsumerWidget {
  final List<PendingInvite> invites;
  const _CurhatBaruTab({required this.invites});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    if (invites.isEmpty) {
      return const _EmptyState(
        message: 'Belum ada undangan masuk 💛',
      );
    }

    return ListView.builder(
      padding: const EdgeInsets.fromLTRB(16, 14, 16, 20),
      itemCount: invites.length,
      itemBuilder: (_, i) {
        final invite = invites[i];
        return Padding(
          padding: EdgeInsets.only(bottom: i == invites.length - 1 ? 0 : 12),
          child: _InviteCard(
            invite: invite,
            variant: _InviteCardVariant.curhatBaru,
            onAccept: () => _accept(context, invite),
            onReject: () => _reject(ref, invite),
          ),
        );
      },
    );
  }

  Future<void> _accept(
    BuildContext context,
    PendingInvite invite,
  ) async {
    // Call the same notifier method as the popup overlay's Terima button.
    // Navigation to `/chat/session/:id` is handled by `ChatRequestOverlay`
    // (mounted at the app root in `main.dart`) when the state transitions
    // to `ChatRequestAcceptedData` — so we deliberately do NOT push the route
    // here. If we did, the overlay's `ref.listen` would push it again.
    //
    // Capture the container before any await so a widget rebuild between the
    // Accepting + Accepted states can't invalidate our ref.
    final container = ProviderScope.containerOf(context, listen: false);
    await container
        .read(chatRequestProvider.notifier)
        .accept(invite.sessionId);
  }

  void _reject(WidgetRef ref, PendingInvite invite) {
    // `decline` posts to the backend then advances the internal queue —
    // identical to the popup-overlay reject button.
    ref.read(chatRequestProvider.notifier).decline(invite.sessionId);
  }
}

// ─── Perpanjang tab (placeholder) ─────────────────────────────────────────

class _PerpanjangTab extends StatelessWidget {
  const _PerpanjangTab();

  @override
  Widget build(BuildContext context) {
    // TODO(stage-3): wire to a pendingExtensionsProvider once backend exposes
    // a queryable list of pending extension invitations.
    return Container(
      color: HaloTokens.accentAmberBg,
      child: const _EmptyState(
        message: 'Belum ada permintaan perpanjangan 💛',
      ),
    );
  }
}

// ─── Empty state ──────────────────────────────────────────────────────────

class _EmptyState extends StatelessWidget {
  final String message;
  const _EmptyState({required this.message});

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 32),
        child: Text(
          message,
          textAlign: TextAlign.center,
          style: const TextStyle(
            fontFamily: HaloTokens.fontBody,
            fontSize: 14,
            color: HaloTokens.inkSoft,
            height: 1.5,
          ),
        ),
      ),
    );
  }
}

// ─── Invite card ──────────────────────────────────────────────────────────

enum _InviteCardVariant { curhatBaru, perpanjang }

class _InviteCard extends StatelessWidget {
  final PendingInvite invite;
  final _InviteCardVariant variant;
  final VoidCallback onAccept;
  final VoidCallback onReject;

  const _InviteCard({
    required this.invite,
    required this.variant,
    required this.onAccept,
    required this.onReject,
  });

  @override
  Widget build(BuildContext context) {
    final isExtend = variant == _InviteCardVariant.perpanjang;
    final borderColor =
        isExtend ? const Color(0xFFF5C97A) : HaloTokens.brandSoft;
    final bg = isExtend ? const Color(0xFFFFF8EB) : HaloTokens.brandSofter;

    // Stable orb color from the session id so repeat visits look consistent.
    final orbSeed = invite.sessionId.hashCode;

    return Container(
      padding: const EdgeInsets.all(14),
      decoration: BoxDecoration(
        color: bg,
        borderRadius: HaloRadius.lg,
        border: Border.all(color: borderColor, width: 1.5),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              HaloOrb(size: 40, seed: orbSeed),
              const SizedBox(width: 12),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Row(
                      children: [
                        Flexible(
                          child: Text(
                            _displayName(invite),
                            overflow: TextOverflow.ellipsis,
                            style: const TextStyle(
                              fontFamily: HaloTokens.fontBody,
                              fontSize: 15,
                              fontWeight: FontWeight.w700,
                              color: HaloTokens.ink,
                            ),
                          ),
                        ),
                        const SizedBox(width: 8),
                        _ModeBadge(invite: invite, isExtend: isExtend),
                      ],
                    ),
                    const SizedBox(height: 4),
                    Text(
                      _expirySubtitle(invite, isExtend),
                      style: const TextStyle(
                        fontFamily: HaloTokens.fontBody,
                        fontSize: 12,
                        color: HaloTokens.inkSoft,
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
          const SizedBox(height: 12),
          Row(
            children: [
              Expanded(
                flex: 1,
                child: HaloButton(
                  label: 'Tolak',
                  onPressed: onReject,
                  variant: HaloButtonVariant.soft,
                  size: HaloButtonSize.sm,
                  fullWidth: true,
                ),
              ),
              const SizedBox(width: 8),
              Expanded(
                flex: 2,
                child: isExtend
                    ? _PrimaryAmberButton(
                        label: 'Terima Perpanjangan →',
                        onPressed: onAccept,
                      )
                    : HaloButton(
                        label: 'Terima →',
                        onPressed: onAccept,
                        variant: HaloButtonVariant.primary,
                        size: HaloButtonSize.sm,
                        fullWidth: true,
                      ),
              ),
            ],
          ),
        ],
      ),
    );
  }

  String _displayName(PendingInvite invite) {
    // The chat-request notifier doesn't carry the customer display_name; the
    // popup shows generic copy too ("Ada permintaan chat baru!"). Until that
    // payload is enriched on the backend, fall back to a short, neutral
    // placeholder rather than leaking the session id.
    return 'Customer';
  }

  String _expirySubtitle(PendingInvite invite, bool isExtend) {
    final duration = invite.durationMinutes;
    if (isExtend) {
      // Per v5.jsx: "klien lama · expired <HH:mm> · tersisa ~N mnt"
      return duration != null ? 'klien lama · +$duration menit' : 'klien lama';
    }
    if (invite.isFreeTrial == true) return 'Free Trial';
    return duration != null ? 'Durasi: $duration menit' : '';
  }
}

class _ModeBadge extends StatelessWidget {
  final PendingInvite invite;
  final bool isExtend;
  const _ModeBadge({required this.invite, required this.isExtend});

  @override
  Widget build(BuildContext context) {
    // The chat-request payload doesn't carry SessionMode today — popup shows
    // generic copy. Default to chat (💬). The extend variant shows "+N mnt".
    final showAddMins = isExtend && invite.durationMinutes != null;
    final label = showAddMins ? '+${invite.durationMinutes} mnt' : '💬 Chat';
    final bg =
        isExtend ? HaloTokens.accentAmberSoft : HaloTokens.surface;
    final fg = isExtend ? const Color(0xFF7A4A0E) : HaloTokens.brandDark;

    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
      decoration: BoxDecoration(
        color: bg,
        borderRadius: HaloRadius.pill,
      ),
      child: Text(
        label,
        style: TextStyle(
          fontFamily: HaloTokens.fontBody,
          fontSize: 11,
          fontWeight: isExtend ? FontWeight.w700 : FontWeight.w600,
          color: fg,
        ),
      ),
    );
  }
}

/// Amber-tinted primary button used for "Terima Perpanjangan". HaloButton
/// hard-codes the brand pink for `primary`, so we render an inline
/// ElevatedButton that matches the variant's geometry but with the amber
/// accent from the Figma extend palette.
class _PrimaryAmberButton extends StatelessWidget {
  final String label;
  final VoidCallback? onPressed;
  const _PrimaryAmberButton({required this.label, required this.onPressed});

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: double.infinity,
      child: ElevatedButton(
        onPressed: onPressed,
        style: ElevatedButton.styleFrom(
          backgroundColor: HaloTokens.accentAmber,
          foregroundColor: Colors.white,
          elevation: 0,
          padding: const EdgeInsets.symmetric(
            horizontal: HaloSpacing.s16,
            vertical: HaloSpacing.s8,
          ),
          shape: const RoundedRectangleBorder(borderRadius: HaloRadius.pill),
          textStyle: const TextStyle(
            fontFamily: HaloTokens.fontBody,
            fontSize: 13,
            fontWeight: FontWeight.w700,
          ),
        ),
        child: Text(label),
      ),
    );
  }
}
