import 'dart:convert';

import 'package:http/http.dart' as http;

import '../config/api_config.dart';
import 'auth_service.dart';

class PasswordResetRequest {
  const PasswordResetRequest({this.token});

  final String? token;

  bool get hasToken => token != null && token!.isNotEmpty;
}

class PasswordResetService {
  Future<PasswordResetRequest> forgotPassword(String email) async {
    try {
      final response = await _post('/forgot-password', body: {
        'email': email.trim(),
      });
      final payload = _decodeResponse(response);
      _throwIfUnsuccessful(response, payload);

      final token = _stringAt(payload, ['data', 'reset_token']);
      return PasswordResetRequest(token: token.isEmpty ? null : token);
    } on AuthException {
      rethrow;
    } catch (_) {
      throw const AuthException(
        'Tidak bisa terhubung ke server. Silakan coba lagi.',
      );
    }
  }

  Future<void> resetPassword({
    required String email,
    required String token,
    required String password,
    required String passwordConfirmation,
  }) async {
    if (password != passwordConfirmation) {
      throw const AuthException('Konfirmasi password tidak sesuai.');
    }

    try {
      final response = await _post('/reset-password', body: {
        'email': email.trim(),
        'token': token.trim(),
        'password': password,
        'password_confirmation': passwordConfirmation,
      });
      final payload = _decodeResponse(response);
      _throwIfUnsuccessful(response, payload);
    } on AuthException {
      rethrow;
    } catch (_) {
      throw const AuthException(
        'Tidak bisa terhubung ke server. Silakan coba lagi.',
      );
    }
  }

  Future<http.Response> _post(
    String path, {
    required Map<String, dynamic> body,
  }) {
    return http
        .post(
          ApiConfig.apiUri(path),
          headers: const {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
          },
          body: jsonEncode(body),
        )
        .timeout(const Duration(seconds: 15));
  }

  Map<String, dynamic> _decodeResponse(http.Response response) {
    if (response.body.trim().isEmpty) return <String, dynamic>{};

    final decoded = jsonDecode(response.body);
    if (decoded is Map<String, dynamic>) return decoded;

    throw const AuthException('Format response server tidak valid.');
  }

  void _throwIfUnsuccessful(
    http.Response response,
    Map<String, dynamic> payload,
  ) {
    if (response.statusCode >= 200 && response.statusCode < 300) return;

    throw AuthException(_messageFromPayload(payload));
  }

  String _messageFromPayload(Map<String, dynamic> payload) {
    final errors = payload['errors'];
    if (errors is Map && errors.isNotEmpty) {
      final firstValue = errors.values.first;
      if (firstValue is List && firstValue.isNotEmpty) {
        return _localizeMessage(firstValue.first.toString());
      }
      return _localizeMessage(firstValue.toString());
    }

    final message = payload['message']?.toString().trim();
    if (message != null && message.isNotEmpty && message != 'Success') {
      return _localizeMessage(message);
    }

    return 'Permintaan gagal diproses. Silakan coba lagi.';
  }

  String _localizeMessage(String message) {
    final text = message.trim();
    final normalized = text.toLowerCase();

    if (normalized.contains('email field is required') ||
        normalized.contains('email is required')) {
      return 'Email wajib diisi.';
    }

    if (normalized.contains('selected email is invalid') ||
        normalized.contains('email tidak valid') ||
        normalized.contains('exists')) {
      return 'Akun dengan email tersebut tidak ditemukan.';
    }

    if (normalized.contains('password field is required') ||
        normalized.contains('password is required')) {
      return 'Password wajib diisi.';
    }

    if (normalized.contains('password confirmation') ||
        normalized.contains('password konfirmasi')) {
      return 'Konfirmasi password tidak sesuai.';
    }

    return text;
  }

  String _stringAt(Map<String, dynamic> payload, List<String> path) {
    Object? current = payload;
    for (final key in path) {
      if (current is! Map<String, dynamic>) return '';
      current = current[key];
    }
    return current?.toString().trim() ?? '';
  }
}
