import 'dart:convert';
import 'package:flutter/foundation.dart' show FlutterError;
import 'package:flutter/services.dart' show rootBundle;
import 'package:http/http.dart' as http;

import 'mattermost_push_client.dart';

/// Mattermost 자동 로그인 + FCM 디바이스 토큰 서버 등록 서비스.
class MattermostAuthService {
  final MattermostPushClient _pushService;

  String? _serverUrl;
  String? _serverIdentifier;
  String? _authToken;
  String? _userId;
  String? _sessionId;

  String? get serverUrl => _serverUrl;
  bool get isLoggedIn => _authToken != null;

  MattermostAuthService(this._pushService);

  /// assets/mattermost_credentials.json 로드 → 로그인 → FCM 등록까지 자동 수행.
  Future<void> autoLoginAndRegister() async {
    final creds = await _loadCredentials();
    if (creds == null) {
      print(
        '[MattermostAuth] Credentials asset not found, skipping auto login.',
      );
      return;
    }
    _serverUrl = creds['serverUrl']!;
    _serverIdentifier = creds['serverId'];

    print('[MattermostAuth] Logging in to $_serverUrl ...');
    await _login(creds['loginId']!, creds['password']!);

    // FCM 토큰이 이미 있으면 바로 등록, 없으면 콜백으로 대기
    final existingToken = await _pushService.getDeviceToken();
    if (existingToken != null && existingToken.isNotEmpty) {
      print('[MattermostAuth] FCM token already available, registering ...');
      await _registerDeviceToken(existingToken);
    } else {
      print(
        '[MattermostAuth] FCM token not ready yet, waiting for callback ...',
      );
    }

    // FCM 토큰 발급/갱신 시 자동으로 서버에 등록
    _pushService.onDeviceTokenReady = (deviceToken) async {
      print('[MattermostAuth] FCM token ready, registering with server ...');
      await _registerDeviceToken(deviceToken);
    };

    print('[MattermostAuth] Auto login & FCM registration complete.');
  }

  Future<Map<String, String>?> _loadCredentials() async {
    final String jsonStr;
    try {
      jsonStr = await rootBundle.loadString(
        'assets/mattermost_credentials.json',
      );
    } on FlutterError {
      return null;
    }
    final map = json.decode(jsonStr) as Map<String, dynamic>;
    final serverId = (map['serverId'] ?? map['serverIdentifier']) as String?;
    return {
      'serverUrl': map['serverUrl'] as String,
      'loginId': map['loginId'] as String,
      'password': map['password'] as String,
      if (serverId != null && serverId.isNotEmpty) 'serverId': serverId,
    };
  }

  /// POST /api/v4/users/login → Token 헤더에서 인증 토큰 추출.
  Future<void> _login(String loginId, String password) async {
    final url = Uri.parse('$_serverUrl/api/v4/users/login');
    final response = await http.post(
      url,
      headers: {'Content-Type': 'application/json'},
      body: json.encode({'login_id': loginId, 'password': password}),
    );

    if (response.statusCode != 200) {
      throw Exception(
        '[MattermostAuth] Login failed (${response.statusCode}): ${response.body}',
      );
    }

    _authToken = response.headers['token'];
    if (_authToken == null) {
      throw Exception('[MattermostAuth] Login response missing Token header');
    }

    final body = json.decode(response.body) as Map<String, dynamic>;
    _userId = body['id'] as String?;
    _sessionId = body['session_id'] as String? ?? body['id'] as String?;

    print('[MattermostAuth] Login OK - userId=$_userId sessionId=$_sessionId');

    // 네이티브 측에 인증 토큰 저장 (ACK, 답장 등에 사용)
    await _pushService.setAuthToken(
      _serverUrl!,
      _authToken!,
      identifier: _serverIdentifier,
    );

    // 서버 config에서 signing key 가져와 네이티브에 저장
    await _fetchAndStoreSigningKey();
  }

  /// GET /api/v4/config/client?format=old → AsymmetricSigningPublicKey를 네이티브에 저장.
  Future<void> _fetchAndStoreSigningKey() async {
    try {
      final url = Uri.parse('$_serverUrl/api/v4/config/client?format=old');
      final response = await http.get(
        url,
        headers: {'Authorization': 'Bearer $_authToken'},
      );
      if (response.statusCode != 200) {
        print(
          '[MattermostAuth] Failed to fetch config (${response.statusCode})',
        );
        return;
      }
      final config = json.decode(response.body) as Map<String, dynamic>;
      final signingKey = config['AsymmetricSigningPublicKey'] as String?;
      if (signingKey != null && signingKey.isNotEmpty) {
        await _pushService.setSigningKey(_serverUrl!, signingKey);
        print('[MattermostAuth] Signing key stored.');
      } else {
        print('[MattermostAuth] No signing key in server config.');
      }
    } catch (e) {
      print('[MattermostAuth] Failed to fetch signing key: $e');
    }
  }

  /// PUT /api/v4/users/sessions/device → device_id 등록.
  Future<void> _registerDeviceToken(String deviceToken) async {
    final url = Uri.parse('$_serverUrl/api/v4/users/sessions/device');
    final response = await http.put(
      url,
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer $_authToken',
      },
      body: json.encode({'device_id': deviceToken}),
    );

    if (response.statusCode == 200) {
      print('[MattermostAuth] FCM device token registered successfully.');
    } else {
      print(
        '[MattermostAuth] FCM registration failed (${response.statusCode}): ${response.body}',
      );
    }
  }
}
