import 'dart:async';
import 'dart:convert';

import 'package:flutter/foundation.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:http/http.dart' as http;

import '../../../core/config/app_environment_provider.dart';
import '../../../core/network/http_client_provider.dart';
import '../../auth/data/auth_session_store.dart';
import '../domain/employee.dart';

class ProfileImageApiClient {
  ProfileImageApiClient({
    required this.httpClient,
    required this.baseUri,
    required this.sessionStore,
    this.timeout = const Duration(seconds: 5),
    this.cacheTtl = const Duration(minutes: 10),
  });

  static final Map<String, _ProfileImageCacheEntry> _cache = {};
  static final RegExp _uuidPattern = RegExp(
    r'^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$',
    caseSensitive: false,
  );

  final http.Client httpClient;
  final Uri baseUri;
  final AuthSessionStore sessionStore;
  final Duration timeout;
  final Duration cacheTtl;

  Future<String?> resolveImageUrl(Employee employee) async {
    final explicitUrl = employee.profileImageUrl?.trim() ?? '';
    if (explicitUrl.isNotEmpty) {
      return explicitUrl;
    }

    final uuidFallbackUrl = _uuidFallbackUrl(employee.id);

    final email = employee.email?.trim().toLowerCase() ?? '';
    if (email.isEmpty) {
      _debug(
        'skip auth lookup: employee=${employee.name}, id=${employee.id}, email missing, uuidFallback=${uuidFallbackUrl != null}',
      );
      return uuidFallbackUrl;
    }

    final session = await sessionStore.load();
    if (session == null || session.isExpired || session.token.trim().isEmpty) {
      _debug(
        'skip auth lookup: employee=${employee.name}, email=$email, session unavailable, uuidFallback=${uuidFallbackUrl != null}',
      );
      return uuidFallbackUrl;
    }

    final companyCode = _resolveCompanyCode(employee, email: email);
    final cacheKey = '${companyCode ?? ''}|$email';
    final now = DateTime.now().toUtc();
    final cached = _cache[cacheKey];
    if (cached != null && cached.expiresAt.isAfter(now)) {
      final resolved = await cached.future;
      return resolved ?? uuidFallbackUrl;
    }

    final future = _fetchImageUrl(
      companyCode: companyCode,
      email: email,
      accessToken: session.token.trim(),
    );
    _cache[cacheKey] = _ProfileImageCacheEntry(
      future: future,
      expiresAt: now.add(cacheTtl),
    );
    try {
      final resolved = await future;
      if (resolved == null && uuidFallbackUrl != null) {
        _debug(
          'auth lookup empty: employee=${employee.name}, email=$email, fallback to uuid url',
        );
      }
      return resolved ?? uuidFallbackUrl;
    } catch (_) {
      if (identical(_cache[cacheKey]?.future, future)) {
        _cache.remove(cacheKey);
      }
      if (uuidFallbackUrl != null) {
        _debug(
          'auth lookup failed: employee=${employee.name}, email=$email, fallback to uuid url',
        );
      }
      return uuidFallbackUrl;
    }
  }

  Future<String?> _fetchImageUrl({
    required String? companyCode,
    required String email,
    required String accessToken,
  }) async {
    final appSessionToken = accessToken.trim();
    final queryParameters = <String, String>{'email': email};
    if (companyCode != null && companyCode.isNotEmpty) {
      queryParameters['comp'] = companyCode;
    }

    _debug(
      'request profile image: email=$email, comp=${companyCode ?? ''}, base=${baseUri.toString()}',
    );

    final response = await httpClient
        .get(
          _resolve('/api/v1/profile-image', queryParameters: queryParameters),
          headers: {
            'accept': 'application/json',
            if (appSessionToken.isNotEmpty)
              'Authorization': 'Bearer $appSessionToken',
            if (appSessionToken.isNotEmpty) 'X-App-Session': appSessionToken,
          },
        )
        .timeout(timeout);

    if (response.statusCode < 200 || response.statusCode >= 300) {
      _debug(
        'profile image response not ok: email=$email, status=${response.statusCode}',
      );
      return null;
    }

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

    final found = decoded['found'] as bool? ?? false;
    final imageUrl = decoded['imageUrl'] as String? ?? '';
    if (!found || imageUrl.trim().isEmpty) {
      _debug('profile image not found: email=$email');
      return null;
    }
    _debug('profile image resolved: email=$email, url=${imageUrl.trim()}');
    return imageUrl.trim();
  }

  Uri _resolve(
    String path, {
    Map<String, String> queryParameters = const {},
  }) {
    final normalizedBase = baseUri.path.endsWith('/')
        ? baseUri
        : baseUri.replace(path: '${baseUri.path}/');
    final resolved = normalizedBase.resolve(path.replaceFirst(RegExp(r'^/'), ''));
    return resolved.replace(queryParameters: queryParameters);
  }

  String? _uuidFallbackUrl(String employeeId) {
    final normalized = employeeId.trim();
    if (!_uuidPattern.hasMatch(normalized)) {
      return null;
    }
    return 'https://baroncs.co.kr/employee_img/$normalized.jpg';
  }

  static void _debug(String message) {
    if (kDebugMode) {
      debugPrint('[ProfileImageApiClient] $message');
    }
  }
}

String? _resolveCompanyCode(Employee employee, {required String email}) {
  final tenantSlug = employee.tenantSlug.trim().toLowerCase();
  final tenantName = employee.tenantName.trim().toLowerCase();

  if (tenantSlug.contains('saman') || tenantName.contains('삼안')) {
    return 'SAMAN';
  }
  if (tenantSlug.contains('hanmac') || tenantName.contains('한맥')) {
    return 'HANMAC';
  }
  if (tenantSlug == 'ptc' || tenantName == 'ptc') {
    return 'PTC';
  }
  if (tenantSlug == 'tdc' || tenantName == 'tdc') {
    return 'TDC';
  }

  if (email.endsWith('@samaneng.com')) {
    return 'SAMAN';
  }
  if (email.endsWith('@hanmaceng.co.kr')) {
    return 'HANMAC';
  }

  return null;
}

class _ProfileImageCacheEntry {
  const _ProfileImageCacheEntry({
    required this.future,
    required this.expiresAt,
  });

  final Future<String?> future;
  final DateTime expiresAt;
}

final profileImageApiClientProvider = Provider<ProfileImageApiClient>((ref) {
  final environment = ref.watch(appEnvironmentProvider);
  return ProfileImageApiClient(
    httpClient: ref.watch(httpClientProvider),
    baseUri: Uri.parse(environment.authApiBaseUrl),
    sessionStore: ref.watch(authSessionStoreProvider),
  );
});
