import 'dart:convert';

import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../../../../core/services/auth_token_store.dart';
import '../../../../core/services/http_client.dart';
import '../../../../core/services/runtime_env.dart';
import 'package:userfront/i18n.dart';
import 'models.dart';

String get _baseUrl => runtimeBackendUrl();

Future<AuditPage> _fetchAuthTimelinePage({String? cursor}) async {
  final queryParameters = <String, String>{'limit': '20'};
  if (cursor != null && cursor.isNotEmpty) {
    queryParameters['cursor'] = cursor;
  }

  final url = Uri.parse(
    '$_baseUrl/api/v1/audit/auth/timeline',
  ).replace(queryParameters: queryParameters);
  final useCookie = AuthTokenStore.usesCookie();
  final token = AuthTokenStore.getToken();

  final client = createHttpClient(withCredentials: useCookie);
  final headers = <String, String>{'Content-Type': 'application/json'};
  if (!useCookie && token != null) {
    headers['Authorization'] = 'Bearer $token';
  }

  try {
    final response = await client.get(url, headers: headers);
    if (response.statusCode != 200) {
      throw Exception('Failed to load audit logs');
    }

    final body = jsonDecode(response.body) as Map<String, dynamic>;
    final items = (body['items'] as List?) ?? [];
    final nextCursor = body['next_cursor']?.toString();
    final logs = <AuditLogEntry>[];
    for (final item in items) {
      if (item is Map) {
        logs.add(AuditLogEntry.fromJson(Map<String, dynamic>.from(item)));
      }
    }

    return AuditPage(items: logs, nextCursor: nextCursor);
  } finally {
    client.close();
  }
}

typedef AuthTimelineFetcher = Future<AuditPage> Function({String? cursor});

final authTimelineFetcherProvider = Provider<AuthTimelineFetcher>((ref) {
  return _fetchAuthTimelinePage;
});

class AuthTimelineState {
  final List<AuditLogEntry> items;
  final String? nextCursor;
  final bool isLoading;
  final bool isLoadingMore;
  final String? error;

  const AuthTimelineState({
    required this.items,
    this.nextCursor,
    this.isLoading = false,
    this.isLoadingMore = false,
    this.error,
  });

  const AuthTimelineState.initial()
    : items = const [],
      nextCursor = null,
      isLoading = false,
      isLoadingMore = false,
      error = null;

  AuthTimelineState copyWith({
    List<AuditLogEntry>? items,
    String? nextCursor,
    bool? isLoading,
    bool? isLoadingMore,
    String? error,
  }) {
    return AuthTimelineState(
      items: items ?? this.items,
      nextCursor: nextCursor ?? this.nextCursor,
      isLoading: isLoading ?? this.isLoading,
      isLoadingMore: isLoadingMore ?? this.isLoadingMore,
      error: error,
    );
  }
}

class AuthTimelineNotifier extends Notifier<AuthTimelineState> {
  late final AuthTimelineFetcher _fetchPage;
  bool _hasLoaded = false;

  @override
  AuthTimelineState build() {
    _fetchPage = ref.watch(authTimelineFetcherProvider);
    if (!_hasLoaded) {
      _hasLoaded = true;
      Future.microtask(_loadInitial);
    }
    return const AuthTimelineState.initial();
  }

  Future<void> refresh() async {
    if (state.isLoading) {
      return;
    }
    state = state.copyWith(
      items: const [],
      nextCursor: null,
      isLoading: true,
      error: null,
    );
    await _loadPage(reset: true);
  }

  Future<void> loadMore() async {
    if (state.isLoading || state.isLoadingMore) {
      return;
    }
    final nextCursor = state.nextCursor;
    if (nextCursor == null || nextCursor.isEmpty) {
      return;
    }
    state = state.copyWith(isLoadingMore: true, error: null);
    await _loadPage(reset: false);
  }

  Future<void> _loadInitial() async {
    if (state.items.isNotEmpty || state.isLoading) {
      return;
    }
    state = state.copyWith(isLoading: true, error: null);
    await _loadPage(reset: true);
  }

  Future<void> _loadPage({required bool reset}) async {
    try {
      final page = await _fetchPage(cursor: reset ? null : state.nextCursor);
      if (reset) {
        state = state.copyWith(
          items: page.items,
          nextCursor: page.nextCursor,
          isLoading: false,
          isLoadingMore: false,
          error: null,
        );
      } else {
        state = state.copyWith(
          items: [...state.items, ...page.items],
          nextCursor: page.nextCursor,
          isLoading: false,
          isLoadingMore: false,
          error: null,
        );
      }
    } catch (e) {
      state = state.copyWith(
        isLoading: false,
        isLoadingMore: false,
        error: tr('msg.userfront.dashboard.timeline.load_error'),
      );
    }
  }
}

final authTimelineProvider =
    NotifierProvider<AuthTimelineNotifier, AuthTimelineState>(
      AuthTimelineNotifier.new,
    );
