import 'package:dio/dio.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../constants/auth_constants.dart';
import '../models/auth_session.dart';
import '../network/api_client.dart';
import '../storage/secure_storage.dart';

final authServiceProvider = Provider<AuthService>((ref) {
  return AuthService(
    apiClient: ref.read(apiClientProvider),
    secureStorage: ref.read(secureStorageProvider),
  );
});

class AuthService {
  AuthService({
    required Dio apiClient,
    required FlutterSecureStorage secureStorage,
  }) : _apiClient = apiClient,
       _secureStorage = secureStorage;

  final Dio _apiClient;
  final FlutterSecureStorage _secureStorage;

  Future<AuthSession?> restoreSession() async {
    final token = await _secureStorage.read(key: authTokenStorageKey);
    if (token == null || token.isEmpty) {
      return null;
    }

    return AuthSession(
      token: token,
      userRole: await _secureStorage.read(key: authUserRoleStorageKey),
      routeId: await _secureStorage.read(key: authRouteIdStorageKey),
    );
  }

  Future<AuthSession> register({
    required String email,
    required String phone,
    required String password,
  }) {
    return _authenticate(
      path: '/auth/register',
      payload: <String, dynamic>{
        'email': email,
        'phone': phone,
        'password': password,
      },
    );
  }

  Future<AuthSession> login({required String email, required String password}) {
    return _authenticate(
      path: '/auth/login',
      payload: <String, dynamic>{'email': email, 'password': password},
    );
  }

  Future<void> logout() {
    return Future.wait(<Future<void>>[
      _secureStorage.delete(key: authTokenStorageKey),
      _secureStorage.delete(key: authUserRoleStorageKey),
      _secureStorage.delete(key: authRouteIdStorageKey),
    ]).then((_) {});
  }

  Future<AuthSession> _authenticate({
    required String path,
    required Map<String, dynamic> payload,
  }) async {
    final response = await _apiClient.post<Map<String, dynamic>>(
      path,
      data: payload,
    );

    final session = _extractSession(response.data);
    if (session == null || session.token.isEmpty) {
      throw StateError('El backend no devolvió un JWT.');
    }

    await _secureStorage.write(key: authTokenStorageKey, value: session.token);
    await _writeOptionalString(authUserRoleStorageKey, session.userRole);
    await _writeOptionalString(authRouteIdStorageKey, session.routeId);
    return session;
  }

  Future<void> _writeOptionalString(String key, String? value) async {
    if (value == null || value.isEmpty) {
      await _secureStorage.delete(key: key);
      return;
    }

    await _secureStorage.write(key: key, value: value);
  }

  AuthSession? _extractSession(Map<String, dynamic>? data) {
    if (data == null) {
      return null;
    }

    final dataMap = data['data'] is Map<String, dynamic>
        ? data['data'] as Map<String, dynamic>
        : data;

    final token = _pickString(<dynamic>[
      dataMap['access_token'],
      dataMap['token'],
      dataMap['jwt'],
      data['access_token'],
      data['token'],
      data['jwt'],
    ]);

    if (token == null || token.isEmpty) {
      return null;
    }

    return AuthSession(
      token: token,
      userRole: _pickString(<dynamic>[
        dataMap['userRole'],
        dataMap['user_role'],
        dataMap['role'],
        data['userRole'],
        data['user_role'],
        data['role'],
      ]),
      routeId: _pickString(<dynamic>[
        dataMap['routeId'],
        dataMap['route_id'],
        data['routeId'],
        data['route_id'],
      ]),
    );
  }

  String? _pickString(Iterable<dynamic> candidates) {
    for (final candidate in candidates) {
      if (candidate is String && candidate.isNotEmpty) {
        return candidate;
      }
    }

    return null;
  }
}
