import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../core/api/api_client_provider.dart';
import '../../../core/auth/auth_notifier.dart';

/// One row in the Chat Tab > Selesai sub-tab.
///
/// Closed-session details that survive into history: who, when, how long,
/// what closing message was left. The factory tolerates the same number /
/// string ambiguity bestieHistoryProvider already handles (postgres.js
/// stringifies bigint counts).
class SelesaiHistoryItem {
  final String sessionId;
  final String? mitraId;
  final String mitraName;
  final DateTime? endedAt;
  final int? durationMinutes;
  final String mode;
  final String? mitraClosureMessage;
  final String? customerClosureMessage;
  final int sessionsCount;
  final bool mitraIsOnline;

  const SelesaiHistoryItem({
    required this.sessionId,
    required this.mitraId,
    required this.mitraName,
    required this.endedAt,
    required this.durationMinutes,
    required this.mode,
    required this.mitraClosureMessage,
    required this.customerClosureMessage,
    required this.sessionsCount,
    required this.mitraIsOnline,
  });

  factory SelesaiHistoryItem.fromJson(Map<String, dynamic> json) {
    final endedAtRaw = json['ended_at'];
    final createdAtRaw = json['created_at'];
    return SelesaiHistoryItem(
      sessionId: json['id'] as String,
      mitraId: json['mitra_id'] as String?,
      mitraName: json['mitra_display_name'] as String? ?? 'Bestie',
      endedAt: endedAtRaw is String
          ? DateTime.tryParse(endedAtRaw)?.toLocal()
          : (createdAtRaw is String
              ? DateTime.tryParse(createdAtRaw)?.toLocal()
              : null),
      durationMinutes: switch (json['duration_minutes']) {
        num n => n.toInt(),
        String s => int.tryParse(s),
        _ => null,
      },
      mode: json['mode'] as String? ?? 'chat',
      mitraClosureMessage: json['mitra_closure_message'] as String?,
      customerClosureMessage: json['customer_closure_message'] as String?,
      sessionsCount: switch (json['sessions_count']) {
        num n => n.toInt(),
        String s => int.tryParse(s) ?? 1,
        _ => 1,
      },
      mitraIsOnline: json['mitra_is_online'] as bool? ?? false,
    );
  }

  /// Preview shown in the row: prefer the mitra's closing message (closer to
  /// the partner's voice), fall back to the customer's, then to a generic
  /// "selesai" placeholder so empty rows still render.
  String get previewText =>
      (mitraClosureMessage?.trim().isNotEmpty == true
          ? mitraClosureMessage
          : (customerClosureMessage?.trim().isNotEmpty == true
              ? customerClosureMessage
              : 'sesi selesai'))!;
}

/// Persistent paginated state — accumulated items + cursor + flags.
class SelesaiHistoryState {
  final List<SelesaiHistoryItem> items;
  final String? nextCursor;
  final bool hasMore;
  final bool loadingMore;

  const SelesaiHistoryState({
    this.items = const [],
    this.nextCursor,
    this.hasMore = false,
    this.loadingMore = false,
  });

  SelesaiHistoryState copyWith({
    List<SelesaiHistoryItem>? items,
    String? nextCursor,
    bool? hasMore,
    bool? loadingMore,
    bool clearCursor = false,
  }) =>
      SelesaiHistoryState(
        items: items ?? this.items,
        nextCursor: clearCursor ? null : (nextCursor ?? this.nextCursor),
        hasMore: hasMore ?? this.hasMore,
        loadingMore: loadingMore ?? this.loadingMore,
      );
}

/// Cursor-paginated Selesai history. First fetch returns the freshest 20 rows;
/// `loadMore` appends the next page. Customer-scoped — switching account
/// resets the list automatically because the build re-runs.
class SelesaiHistoryNotifier
    extends AsyncNotifier<SelesaiHistoryState> {
  static const _pageLimit = 20;

  @override
  Future<SelesaiHistoryState> build() async {
    final customerId = ref.watch(authProvider.select((s) {
      final data = s.valueOrNull;
      return switch (data) {
        AuthAuthenticatedData d => d.profile['id'] as String?,
        AuthAnonymousData d => d.customerId,
        _ => null,
      };
    }));
    if (customerId == null) return const SelesaiHistoryState();
    return await _fetchPage(cursor: null);
  }

  Future<SelesaiHistoryState> _fetchPage({String? cursor}) async {
    final api = ref.read(apiClientProvider);
    final url = cursor == null
        ? '/api/client/chat/history?limit=$_pageLimit'
        : '/api/client/chat/history?limit=$_pageLimit&cursor=${Uri.encodeQueryComponent(cursor)}';
    final response = await api.get(url);
    final data = response['data'] as Map<String, dynamic>? ?? const {};
    final items = (data['items'] as List<dynamic>? ?? [])
        .cast<Map<String, dynamic>>()
        .map(SelesaiHistoryItem.fromJson)
        .toList();
    final existing = cursor == null ? <SelesaiHistoryItem>[] : (state.valueOrNull?.items ?? const []);
    return SelesaiHistoryState(
      items: [...existing, ...items],
      nextCursor: data['next_cursor'] as String?,
      hasMore: data['has_more'] as bool? ?? false,
    );
  }

  /// Append the next page if any. No-op when already loading or no cursor.
  Future<void> loadMore() async {
    final current = state.valueOrNull;
    if (current == null || !current.hasMore || current.loadingMore) return;
    state = AsyncData(current.copyWith(loadingMore: true));
    try {
      final next = await _fetchPage(cursor: current.nextCursor);
      state = AsyncData(next);
    } catch (e, st) {
      state = AsyncError(e, st);
    }
  }

  /// Pull-to-refresh: drop the cursor and re-fetch from the top.
  Future<void> refresh() async {
    state = const AsyncLoading();
    try {
      state = AsyncData(await _fetchPage(cursor: null));
    } catch (e, st) {
      state = AsyncError(e, st);
    }
  }
}

final selesaiHistoryProvider =
    AsyncNotifierProvider<SelesaiHistoryNotifier, SelesaiHistoryState>(
  SelesaiHistoryNotifier.new,
);
