import 'dart:async';
import 'dart:io';

import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
import 'package:krow_domain/krow_domain.dart';

/// Mixin to handle Data Layer errors and map them to Domain Failures.
///
/// Use this in Repositories to wrap remote calls.
/// It catches [SocketException], [FirebaseException], etc., and throws [AppException].
mixin DataErrorHandler {
  /// Executes a Future and maps low-level exceptions to [AppException].
  ///
  /// [timeout] defaults to 30 seconds.
  Future<T> executeProtected<T>(
    Future<T> Function() action, {
    Duration timeout = const Duration(seconds: 30),
  }) async {
    try {
      return await action().timeout(timeout);
    } on TimeoutException {
      throw ServiceUnavailableException(
          technicalMessage: 'Request timed out after ${timeout.inSeconds}s');
    } on SocketException catch (e) {
      throw NetworkException(technicalMessage: 'SocketException: ${e.message}');
    } on FirebaseException catch (e) {
      final String code = e.code.toLowerCase();
      final String msg = (e.message ?? '').toLowerCase();
      if (code == 'unavailable' ||
          code == 'network-request-failed' ||
          msg.contains('offline') ||
          msg.contains('network') ||
          msg.contains('connection failed')) {
        throw NetworkException(
            technicalMessage: 'Firebase ${e.code}: ${e.message}');
      }
      if (code == 'deadline-exceeded') {
        throw ServiceUnavailableException(
            technicalMessage: 'Firebase ${e.code}: ${e.message}');
      }
      // Fallback for other Firebase errors
      throw ServerException(
          technicalMessage: 'Firebase ${e.code}: ${e.message}');
    } catch (e) {
      final String errorStr = e.toString().toLowerCase();
      if (errorStr.contains('socketexception') ||
          errorStr.contains('network') ||
          errorStr.contains('offline') ||
          errorStr.contains('connection failed') ||
          errorStr.contains('unavailable') ||
          errorStr.contains('handshake') ||
          errorStr.contains('clientexception') ||
          errorStr.contains('failed host lookup') ||
          errorStr.contains('connection error') ||
          errorStr.contains('grpc error') ||
          errorStr.contains('terminated') ||
          errorStr.contains('connectexception')) {
        throw NetworkException(technicalMessage: e.toString());
      }
      
      // If it's already an AppException, rethrow it
      if (e is AppException) rethrow;

      // Debugging: Log unexpected errors
      debugPrint('DataErrorHandler: Unhandled exception caught: $e');
      
      throw UnknownException(technicalMessage: e.toString());
    }
  }
}
