import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:real_estate_mobile/features/agents/data/agents_repository.dart';
import 'package:real_estate_mobile/features/agents/data/models/agent_profile.dart';
import 'package:real_estate_mobile/features/agents/presentation/providers/agents_provider.dart';

class AgentDetailState {
  final AgentProfile? agent;
  final List<AgentFieldValue> fieldValues;
  final List<Map<String, dynamic>> testimonials;
  final Map<String, dynamic>? connectionStatus;
  final bool isLoading;
  final String? error;

  const AgentDetailState({
    this.agent,
    this.fieldValues = const [],
    this.testimonials = const [],
    this.connectionStatus,
    this.isLoading = true,
    this.error,
  });

  AgentDetailState copyWith({
    AgentProfile? agent,
    List<AgentFieldValue>? fieldValues,
    List<Map<String, dynamic>>? testimonials,
    Map<String, dynamic>? connectionStatus,
    bool? isLoading,
    String? error,
    bool clearError = false,
    bool clearConnection = false,
  }) {
    return AgentDetailState(
      agent: agent ?? this.agent,
      fieldValues: fieldValues ?? this.fieldValues,
      testimonials: testimonials ?? this.testimonials,
      connectionStatus:
          clearConnection ? null : (connectionStatus ?? this.connectionStatus),
      isLoading: isLoading ?? this.isLoading,
      error: clearError ? null : (error ?? this.error),
    );
  }

  // ── Mapped data helpers (matching web profileDataMapper.ts) ──

  /// Get field value by slug
  dynamic _getFieldValue(String slug) {
    for (final fv in fieldValues) {
      if (fv.fieldSlug == slug) {
        if (fv.jsonValue != null) return fv.jsonValue;
        if (fv.textValue != null) return fv.textValue;
        if (fv.numberValue != null) return fv.numberValue;
        return null;
      }
    }
    return null;
  }

  // ── Experience data ──

  String get yearsInExperience {
    final val = _getFieldValue('years_in_business');
    if (val == null) return '-';
    const mapping = {
      '<2': 'Less than 2 years',
      '2+': '2+ years',
      '5+': '5+ years',
      '10+': '10+ years',
    };
    return mapping[val.toString()] ?? val.toString();
  }

  String get contractsClosed {
    final val = _getFieldValue('contracts_completed');
    if (val == null) return '-';
    final str = val.toString();
    // Parse leading integer from value (handles "10-20", "50+", "<3", etc.)
    final match = RegExp(r'\d+').firstMatch(str);
    if (match == null) return '-';
    final num = int.tryParse(match.group(0)!) ?? -1;
    if (num < 0) return '-';
    if (num >= 100) return '100+ Contracts';
    if (num >= 50) return '50+ Contracts';
    if (num >= 20) return '20+ Contracts';
    if (num >= 10) return '10+ Contracts';
    if (num >= 5) return '5+ Contracts';
    return '$num Contract${num != 1 ? 's' : ''}';
  }

  List<String> get licensingAreas {
    final val = _getFieldValue('licensed_areas');
    if (val is List) return val.map((e) => titleCase(e.toString())).toList();
    return [];
  }

  List<Map<String, String>> get expertiseYears {
    final val = _getFieldValue('expertise_areas');
    if (val is! List) return [];
    return val.map((item) {
      final str = item.toString();
      final match = RegExp(r'^(.+?)\s*[-–]\s*(\d+)\s*(yrs?|years?)$', caseSensitive: false)
          .firstMatch(str);
      if (match != null) {
        return {'area': match.group(1)!.trim(), 'years': '${match.group(2)} yrs'};
      }
      return {'area': str.trim(), 'years': ''};
    }).toList();
  }

  List<Map<String, String>> get certifications {
    final val = _getFieldValue('certification_entries');
    if (val is! List) return [];
    return val
        .where((e) => e is Map && e['certification_name'] != null)
        .map((e) => {
              'name': (e['certification_name'] ?? '').toString(),
              'org': (e['issuing_organization'] ?? '').toString(),
            })
        .toList();
  }

  // ── Expertise tags (matching web mapFieldValuesToProfileCard) ──

  List<String> get expertiseTags {
    const slugs = [
      'about_me_expertise',
      'expertise_areas',
      'specializations',
      'areas_of_expertise',
      'expertise',
      'specialization',
    ];
    for (final slug in slugs) {
      final val = _getFieldValue(slug);
      if (val is List && val.isNotEmpty) {
        return val.map((v) => titleCase(v.toString())).toList();
      }
    }
    // Fallback to agent model specializations
    if (agent != null) {
      final tags = agent!.specializations;
      if (tags.isNotEmpty) return tags;
    }
    return [];
  }

  // ── Description / Bio (from fieldValues first, then agent model) ──

  String get descriptionText {
    // Check detail fieldValues for 'description' slug
    for (final fv in fieldValues) {
      if (fv.fieldSlug == 'description' &&
          fv.textValue != null &&
          fv.textValue!.isNotEmpty) {
        return fv.textValue!;
      }
    }
    // Fallback to agent model bio
    return agent?.bio ?? '';
  }

  // ── Location (from fieldValues, matching web profileDataMapper) ──

  /// All location parts as individual items (for "+N more" display).
  /// Sources: detail fieldValues city/state arrays → agent model → serviceAreas
  List<String> get locationParts {
    final parts = <String>[];

    // 1. Extract from detail fieldValues (full arrays, not just first item)
    List<String>? fvCities;
    List<String>? fvStates;
    for (final fv in fieldValues) {
      final slug = fv.fieldSlug.toLowerCase();
      if (slug == 'city' || slug == 'city_name') {
        fvCities = _extractAllValuesAsList(fv);
      } else if (slug == 'state' || slug == 'state_name') {
        fvStates = _extractAllValuesAsList(fv);
      }
    }
    if (fvCities != null) parts.addAll(fvCities);
    if (fvStates != null) {
      for (final s in fvStates) {
        if (!parts.any((p) => p.toLowerCase() == s.toLowerCase())) {
          parts.add(s);
        }
      }
    }

    // 2. Fallback: agent model direct city/state
    if (parts.isEmpty && agent != null) {
      if (agent!.city != null && agent!.city!.isNotEmpty) {
        parts.add(agent!.city!);
      }
      if (agent!.state != null && agent!.state!.isNotEmpty) {
        parts.add(agent!.state!);
      }
    }

    // 3. Fallback: serviceAreas
    if (parts.isEmpty && agent != null) {
      for (final area in agent!.serviceAreas) {
        final trimmed = area.trim();
        if (trimmed.isNotEmpty) parts.add(trimmed);
      }
    }

    return parts;
  }

  /// Combined location text for single-line display.
  String get locationText {
    final parts = locationParts;
    if (parts.isEmpty) return '';
    return parts.join(', ');
  }

  /// Extract all values from a field as a list of title-cased strings.
  static List<String>? _extractAllValuesAsList(AgentFieldValue fv) {
    if (fv.jsonValue is List && (fv.jsonValue as List).isNotEmpty) {
      return (fv.jsonValue as List)
          .map((v) => titleCase(v.toString()))
          .toList();
    }
    if (fv.textValue != null && fv.textValue!.isNotEmpty) {
      return [titleCase(fv.textValue!)];
    }
    return null;
  }

  /// Extract all values from a field (array or string), title-cased.
  static String? _extractAllValues(AgentFieldValue fv) {
    if (fv.jsonValue is List && (fv.jsonValue as List).isNotEmpty) {
      return (fv.jsonValue as List)
          .map((v) => titleCase(v.toString()))
          .join(', ');
    }
    if (fv.textValue != null && fv.textValue!.isNotEmpty) {
      return titleCase(fv.textValue!);
    }
    return null;
  }

  // ── Contact info (masked) ──

  String? get contactEmail {
    final val = _getFieldValue('email') ??
        _getFieldValue('email_address') ??
        agent?.email ??
        agent?.user?.email;
    return val?.toString();
  }

  String? get contactPhone {
    final val = _getFieldValue('phone_number') ??
        _getFieldValue('phone') ??
        _getFieldValue('cell_number') ??
        _getFieldValue('office_number') ??
        agent?.phone;
    return val?.toString();
  }

  String maskEmail(String email) {
    final parts = email.split('@');
    if (parts.length != 2) return email;
    final prefix = parts[0].length > 2 ? parts[0].substring(0, 2) : parts[0];
    return '$prefix********@${parts[1]}';
  }

  String maskPhone(String phone) {
    final digits = phone.replaceAll(RegExp(r'[^\d]'), '');
    if (digits.length <= 4) return '****$digits';
    return '${'*' * (digits.length - 4)}${digits.substring(digits.length - 4)}';
  }

  // ── Availability ──

  String get availabilityType {
    final val = _getFieldValue('availability');
    if (val is! List || val.isEmpty) return '';
    final values = val.map((e) => e.toString()).toList();
    if (values.contains('full_time') ||
        values.contains('mf_9_5') ||
        values.contains('mf_8_6')) return 'Full-time';
    if (values.contains('part_time')) return 'Part-time';
    if (values.contains('flexible')) return 'Flexible';
    return 'Available';
  }

  List<String> get availabilitySchedule {
    final val = _getFieldValue('availability');
    if (val is! List) return [];
    const labels = {
      'mf_9_5': 'Monday - Friday, 9 AM - 5 PM',
      'mf_8_6': 'Monday - Friday, 8 AM - 6 PM',
      'weekends': 'Weekends',
      'evenings': 'Evenings',
      'flexible': 'Flexible Schedule',
      'full_time': 'Full-time',
      'part_time': 'Part-time',
      '24_7': '24/7 Available',
      'by_appointment': 'By Appointment Only',
      'monday': 'Monday',
      'tuesday': 'Tuesday',
      'wednesday': 'Wednesday',
      'thursday': 'Thursday',
      'friday': 'Friday',
      'saturday': 'Saturday',
      'sunday': 'Sunday',
    };
    return val.map((v) => labels[v.toString()] ?? titleCase(v.toString())).toList();
  }

  // ── Specialization fields ──

  List<SpecializationCard> get specializationCards {
    final cards = <SpecializationCard>[];
    for (final fv in fieldValues) {
      final section = (fv.sectionSlug ?? '').toLowerCase();
      if (!section.contains('specialization')) continue;
      if (fv.fieldSlug.isEmpty || fv.fieldName.isEmpty) continue;

      final values = <String>[];
      if (fv.jsonValue is List) {
        for (final v in (fv.jsonValue as List)) {
          final s = v.toString().trim();
          if (s.isNotEmpty) values.add(s);
        }
      } else if (fv.textValue != null && fv.textValue!.trim().isNotEmpty) {
        values.add(fv.textValue!);
      }
      if (values.isEmpty) continue;
      cards.add(SpecializationCard(
        slug: fv.fieldSlug,
        name: fv.fieldName,
        values: values,
      ));
    }
    return cards;
  }

  // ── Connection status helpers ──

  String get connectionState {
    if (connectionStatus == null) return 'none';
    final status = connectionStatus!['status']?.toString().toUpperCase();
    if (status == 'PENDING') return 'pending';
    if (status == 'ACCEPTED') return 'accepted';
    return 'none';
  }

  String? get connectionRequestId => connectionStatus?['id']?.toString();

  static String titleCase(String s) {
    return s
        .split('_')
        .map((w) => w.isNotEmpty
            ? '${w[0].toUpperCase()}${w.substring(1).toLowerCase()}'
            : '')
        .join(' ');
  }
}

class SpecializationCard {
  final String slug;
  final String name;
  final List<String> values;

  const SpecializationCard({
    required this.slug,
    required this.name,
    required this.values,
  });
}

class AgentDetailNotifier extends StateNotifier<AgentDetailState> {
  final AgentsRepository _repo;
  final String agentId;

  AgentDetailNotifier(this._repo, this.agentId)
      : super(const AgentDetailState()) {
    _load();
  }

  Future<void> _load() async {
    try {
      final results = await Future.wait([
        _repo.getAgentById(agentId),
        _repo.getFieldValues(agentId),
        _repo.getTestimonials(agentId),
      ]);
      state = state.copyWith(
        agent: results[0] as AgentProfile,
        fieldValues: results[1] as List<AgentFieldValue>,
        testimonials: results[2] as List<Map<String, dynamic>>,
        isLoading: false,
      );
    } catch (e) {
      state = state.copyWith(isLoading: false, error: e.toString());
    }
  }

  Future<void> refresh() async {
    try {
      final results = await Future.wait([
        _repo.getAgentById(agentId),
        _repo.getFieldValues(agentId),
        _repo.getTestimonials(agentId),
      ]);
      state = state.copyWith(
        agent: results[0] as AgentProfile,
        fieldValues: results[1] as List<AgentFieldValue>,
        testimonials: results[2] as List<Map<String, dynamic>>,
        isLoading: false,
      );
      // Also refresh connection status
      await loadConnectionStatus();
    } catch (_) {}
  }

  Future<void> loadConnectionStatus() async {
    final status = await _repo.getConnectionStatus(agentId);
    state = state.copyWith(connectionStatus: status);
  }

  Future<bool> connect({String? message}) async {
    final success =
        await _repo.createConnectionRequest(agentId, message: message);
    if (success) {
      state = state.copyWith(
        connectionStatus: {'status': 'PENDING'},
      );
    }
    return success;
  }

  void updateAvailability(bool isAvailable) {
    if (state.agent == null) return;
    state = state.copyWith(
      agent: state.agent!.copyWith(isAvailable: isAvailable),
    );
  }

  Future<bool> cancelConnection() async {
    final requestId = state.connectionRequestId;
    if (requestId == null) return false;
    final success = await _repo.cancelConnectionRequest(requestId);
    if (success) {
      state = state.copyWith(clearConnection: true);
    }
    return success;
  }
}

final agentDetailProvider = StateNotifierProvider.autoDispose
    .family<AgentDetailNotifier, AgentDetailState, String>((ref, agentId) {
  final repo = ref.read(agentsRepositoryProvider);
  return AgentDetailNotifier(repo, agentId);
});
