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

class AuthProxyService {
  static String _envOrDefault(String key, String fallback) {
    if (!dotenv.isInitialized) {
      return fallback;
    }
    return dotenv.env[key] ?? fallback;
  }

  static String get _baseUrl => _envOrDefault('BACKEND_URL', 'https://sso.hmac.kr');

  static Future<Map<String, dynamic>> fetchPasswordPolicy() async {
    final url = Uri.parse('$_baseUrl/api/v1/auth/password/policy');
    final response = await http.get(url);
    if (response.statusCode == 200) {
      return jsonDecode(response.body);
    } else {
      throw Exception('Failed to fetch password policy');
    }
  }

  static Future<Map<String, dynamic>> initEnchantedLink(String loginId, {String? method}) async {
    final url = Uri.parse('$_baseUrl/api/v1/auth/enchanted-link/init');
    final userfrontUrl = _envOrDefault('USERFRONT_URL', 'http://sso.hmac.kr');
    
    final body = {
      'loginId': loginId,
      'uri': userfrontUrl,
    };
    if (method != null) {
      body['method'] = method;
    }
    
    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode(body),
    );

    if (response.statusCode == 200) {
      return jsonDecode(response.body);
    } else {
      throw Exception('Failed to init login: ${response.body}');
    }
  }

  static Future<Map<String, dynamic>> pollEnchantedLink(String pendingRef) async {
    final url = Uri.parse('$_baseUrl/api/v1/auth/enchanted-link/poll');
    
    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({
        'pendingRef': pendingRef,
      }),
    );

    if (response.statusCode == 200) {
      return jsonDecode(response.body);
    } else {
      throw Exception('Polling failed: ${response.body}');
    }
  }

  static Future<Map<String, dynamic>> verifyMagicLink(String token) async {
    final url = Uri.parse('$_baseUrl/api/v1/auth/magic-link/verify');
    
    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({
        'token': token,
      }),
    );

    if (response.statusCode == 200) {
      return jsonDecode(response.body);
    } else {
      throw Exception('Verification failed: ${response.body}');
    }
  }

  static Future<Map<String, dynamic>> loginWithPassword(String loginId, String password) async {
    final url = Uri.parse('$_baseUrl/api/v1/auth/password/login');
    
    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({
        'loginId': loginId,
        'password': password,
      }),
    );

    if (response.statusCode == 200) {
      return jsonDecode(response.body);
    } else {
      final errorBody = jsonDecode(response.body);
      throw Exception(errorBody['error'] ?? 'Failed to login');
    }
  }

  static Future<Map<String, dynamic>> initiatePasswordReset(String loginId) async {
    final url = Uri.parse('$_baseUrl/api/v1/auth/password/reset/initiate');
    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({'loginId': loginId}),
    );

    if (response.statusCode == 200) {
      return jsonDecode(response.body);
    } else {
      final errorBody = jsonDecode(response.body);
      throw Exception(errorBody['error'] ?? 'Failed to initiate password reset');
    }
  }

  static Future<Map<String, dynamic>> completePasswordReset({
    String? loginId,
    String? token,
    required String newPassword,
  }) async {
    final query = <String, String>{};
    if (loginId != null && loginId.isNotEmpty) {
      query['loginId'] = loginId;
    }
    if (token != null && token.isNotEmpty) {
      query['token'] = token;
    }
    final url = Uri.parse('$_baseUrl/api/v1/auth/password/reset/complete').replace(queryParameters: query);
    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({'newPassword': newPassword}),
    );

    if (response.statusCode == 200) {
      return jsonDecode(response.body);
    } else {
      final errorBody = jsonDecode(response.body);
      throw Exception(errorBody['error'] ?? 'Failed to complete password reset');
    }
  }

  static Future<void> sendSms(String phoneNumber) async {
    final url = Uri.parse('$_baseUrl/api/v1/auth/sms');
    
    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({
        'phoneNumber': phoneNumber,
      }),
    );

    if (response.statusCode != 200) {
      throw Exception('Failed to send SMS: ${response.body}');
    }
  }

  static Future<Map<String, dynamic>> verifySmsCode(String phoneNumber, String code) async {
    final url = Uri.parse('$_baseUrl/api/v1/auth/verify-sms');
    
    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({
        'phoneNumber': phoneNumber,
        'code': code,
      }),
    );

    if (response.statusCode == 200) {
      return jsonDecode(response.body);
    } else {
      throw Exception('Failed to verify code: ${response.body}');
    }
  }

  static Future<Map<String, dynamic>> initQrLogin() async {
    final url = Uri.parse('$_baseUrl/api/v1/auth/qr/init');
    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
    );

    if (response.statusCode == 200) {
      return jsonDecode(response.body);
    } else {
      throw Exception('Failed to init QR login: ${response.body}');
    }
  }

  static Future<Map<String, dynamic>> pollQrStatus(String pendingRef) async {
    final url = Uri.parse('$_baseUrl/api/v1/auth/qr/poll');
    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({'pendingRef': pendingRef}),
    );

    if (response.statusCode == 200) {
      return jsonDecode(response.body);
    } else {
      throw Exception('QR Polling failed: ${response.body}');
    }
  }

  static Future<void> approveQrLogin(String pendingRef, String token) async {
    final url = Uri.parse('$_baseUrl/api/v1/auth/qr/approve'); // Mapping to ScanQRLogin on backend
    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({
        'pendingRef': pendingRef,
        'token': token,
      }),
    );

    if (response.statusCode != 200) {
      throw Exception('QR Approval failed: ${response.body}');
    }
  }

  static Future<bool> checkAdminAuth(String adminPassword) async {
    final url = Uri.parse('$_baseUrl/api/v1/admin/check');
    try {
      final response = await http.get(
        url,
        headers: {
          'Content-Type': 'application/json',
          'X-Admin-Password': adminPassword,
        },
      );
      return response.statusCode == 200;
    } catch (_) {
      return false;
    }
  }

  static Future<void> createUser({
    required String loginId,
    required String adminPassword,
    String? email,
    String? phone,
    String? displayName,
  }) async {
    final url = Uri.parse('$_baseUrl/api/v1/admin/users');
    
    final response = await http.post(
      url,
      headers: {
        'Content-Type': 'application/json',
        'X-Admin-Password': adminPassword,
      },
      body: jsonEncode({
        'loginId': loginId,
        'email': email,
        'phone': phone,
        'displayName': displayName,
      }),
    );

    if (response.statusCode != 200) {
      throw Exception('Failed to create user: ${response.body}');
    }
  }

  static Future<List<dynamic>> listUsers(String adminPassword, {String? query}) async {
    var uri = Uri.parse('$_baseUrl/api/v1/admin/users');
    if (query != null && query.isNotEmpty) {
      uri = uri.replace(queryParameters: {'text': query});
    }

    final response = await http.get(
      uri,
      headers: {
        'Content-Type': 'application/json',
        'X-Admin-Password': adminPassword,
      },
    );

    if (response.statusCode == 200) {
      final data = jsonDecode(response.body);
      return data['users'] ?? [];
    } else {
      throw Exception('Failed to list users: ${response.body}');
    }
  }

  static Future<void> deleteUser(String adminPassword, String loginId) async {
    final encodedId = Uri.encodeComponent(loginId);
    final url = Uri.parse('$_baseUrl/api/v1/admin/users/$encodedId');
    
    final response = await http.delete(
      url,
      headers: {
        'Content-Type': 'application/json',
        'X-Admin-Password': adminPassword,
      },
    );

    if (response.statusCode != 200) {
      throw Exception('Failed to delete user: ${response.body}');
    }
  }

  static Future<void> updateUserStatus(String adminPassword, String loginId, String status) async {
    final encodedId = Uri.encodeComponent(loginId);
    final url = Uri.parse('$_baseUrl/api/v1/admin/users/$encodedId/status');
    
    final response = await http.patch(
      url,
      headers: {
        'Content-Type': 'application/json',
        'X-Admin-Password': adminPassword,
      },
      body: jsonEncode({'status': status}),
    );

    if (response.statusCode != 200) {
      throw Exception('Failed to update status: ${response.body}');
    }
  }

  static Future<void> updateUserDetails({
    required String adminPassword,
    required String loginId,
    String? email,
    String? phone,
    String? displayName,
  }) async {
    final encodedId = Uri.encodeComponent(loginId);
    final url = Uri.parse('$_baseUrl/api/v1/admin/users/$encodedId');
    
    final body = <String, dynamic>{};
    if (email != null) body['email'] = email;
    if (phone != null) body['phone'] = phone;
    if (displayName != null) body['displayName'] = displayName;

    final response = await http.patch(
      url,
      headers: {
        'Content-Type': 'application/json',
        'X-Admin-Password': adminPassword,
      },
      body: jsonEncode(body),
    );

    if (response.statusCode != 200) {
      throw Exception('Failed to update user: ${response.body}');
    }
  }

  static Future<void> sendLog(String level, String message, {Map<String, dynamic>? data}) async {
    final url = Uri.parse('$_baseUrl/api/v1/client-log');
    try {
      await http.post(
        url,
        headers: {'Content-Type': 'application/json'},
        body: jsonEncode({
          'level': level,
          'message': message,
          if (data != null) 'data': data,
        }),
      );
    } catch (_) {
      // Ignore logging errors to prevent loops
    }
  }

  static Future<void> logError(String message, {dynamic error, StackTrace? stackTrace}) async {
    final data = <String, dynamic>{};
    if (error != null) data['error'] = error.toString();
    if (stackTrace != null) data['stack'] = stackTrace.toString();
    
    await sendLog('ERROR', message, data: data);
  }

  // --- Signup Methods ---

  static Future<bool> checkEmailAvailability(String email) async {
    final url = Uri.parse('$_baseUrl/api/v1/auth/signup/check-email');
    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({'email': email}),
    );

    if (response.statusCode == 200) {
      final data = jsonDecode(response.body);
      return data['available'] ?? false;
    }
    return false;
  }

  static Future<void> sendSignupCode(String target, String type) async {
    final path = type == 'email' ? 'send-email-code' : 'send-sms-code';
    final url = Uri.parse('$_baseUrl/api/v1/auth/signup/$path');
    
    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({'target': target}),
    );

    if (response.statusCode != 200) {
      throw Exception('Failed to send code: ${response.body}');
    }
  }

  static Future<bool> verifySignupCode(String target, String type, String code) async {
    final url = Uri.parse('$_baseUrl/api/v1/auth/signup/verify-code');
    
    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({
        'target': target,
        'type': type,
        'code': code,
      }),
    );

    if (response.statusCode == 200) {
      final data = jsonDecode(response.body);
      return data['success'] ?? false;
    }
    return false;
  }

  static Future<void> signup({
    required String email,
    required String password,
    required String name,
    required String phone,
    required String affiliationType,
    String? companyCode,
    required String department,
    required bool termsAccepted,
  }) async {
    final url = Uri.parse('$_baseUrl/api/v1/auth/signup');
    
    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({
        'email': email,
        'password': password,
        'name': name,
        'phone': phone,
        'affiliationType': affiliationType,
        if (companyCode != null) 'companyCode': companyCode,
        'department': department,
        'termsAccepted': termsAccepted,
      }),
    );

    if (response.statusCode != 200) {
      final error = jsonDecode(response.body)['error'] ?? 'Signup failed';
      throw Exception(error);
    }
  }
}
