import 'package:flutter/material.dart';
import '../theme/tokens.dart';

/// Beacon severity levels — controls pin color and alert priority
enum BeaconSeverity {
  low('low', 'Info', Color(0xFF4CAF50), Icons.info_outline),
  medium('medium', 'Caution', Color(0xFFFFC107), Icons.warning_amber),
  high('high', 'Danger', Color(0xFFFF5722), Icons.error_outline),
  critical('critical', 'Critical', SojornColors.destructive, Icons.dangerous);

  final String value;
  final String label;
  final Color color;
  final IconData icon;

  const BeaconSeverity(this.value, this.label, this.color, this.icon);

  static BeaconSeverity fromString(String value) {
    return BeaconSeverity.values.firstWhere(
      (s) => s.value == value,
      orElse: () => BeaconSeverity.medium,
    );
  }
}

/// Beacon incident lifecycle status
enum BeaconIncidentStatus {
  active('active', 'Active'),
  resolved('resolved', 'Resolved'),
  falseAlarm('false_alarm', 'False Alarm');

  final String value;
  final String label;

  const BeaconIncidentStatus(this.value, this.label);

  static BeaconIncidentStatus fromString(String value) {
    return BeaconIncidentStatus.values.firstWhere(
      (s) => s.value == value,
      orElse: () => BeaconIncidentStatus.active,
    );
  }
}

/// Two distinct beacon modes for routing to map vs board
enum BeaconMode { geoAlert, discussion }

/// Beacon type enum for different alert categories
/// Uses neutral naming for App Store compliance
enum BeaconType {
  // ── Geo-Alerts (rendered on the Map) ──────────────────────────────────
  suspiciousActivity('suspicious', 'Suspicious Activity', 'Report unusual behavior or people', Icons.visibility, Color(0xFFFF9800), BeaconMode.geoAlert),
  officialPresence('official_presence', 'Official Presence', 'General presence (patrols, checkpoints)', Icons.local_police, Color(0xFF2196F3), BeaconMode.geoAlert),
  checkpoint('checkpoint', 'Checkpoint / Stop', 'Report stationary stops, roadblocks, or inspection points.', Icons.stop_circle, Color(0xFF3F51B5), BeaconMode.geoAlert),
  taskForce('taskForce', 'Task Force / Operation', 'Report heavy coordinated activity or multiple units.', Icons.warning, Color(0xFFFF5722), BeaconMode.geoAlert),
  hazard('hazard', 'Road Hazard', 'Physical danger (Debris, Ice, Floods)', Icons.report_problem, Color(0xFFFFC107), BeaconMode.geoAlert),
  fire('fire', 'Fire', 'Report fires or smoke', Icons.local_fire_department, Color(0xFFF44336), BeaconMode.geoAlert),
  safety('safety', 'Safety Alert', 'Events (Fights, Gunshots, Active threats)', Icons.shield, Color(0xFFF44336), BeaconMode.geoAlert),

  // ── Discussion (rendered on the Neighborhood Board) ───────────────────
  community('community', 'Community Event', 'Helpful (Food drives, Meetups)', Icons.volunteer_activism, Color(0xFF009688), BeaconMode.discussion),
  lostPet('lost_pet', 'Lost Pet', 'Help find a missing pet', Icons.pets, Color(0xFF8D6E63), BeaconMode.discussion),
  question('question', 'General Question', 'Ask your neighborhood something', Icons.help_outline, Color(0xFF78909C), BeaconMode.discussion),
  event('event', 'Local Event', 'Share an upcoming event nearby', Icons.event, Color(0xFF7E57C2), BeaconMode.discussion),
  resource('resource', 'Resource Sharing', 'Offer or request items/help', Icons.handshake, Color(0xFF26A69A), BeaconMode.discussion);

  final String value;
  final String displayName;
  final String description;
  final IconData icon;
  final Color color;
  final BeaconMode mode;

  const BeaconType(this.value, this.displayName, this.description, this.icon, this.color, this.mode);

  /// Whether this type shows on the map
  bool get isGeoAlert => mode == BeaconMode.geoAlert;

  /// Whether this type shows on the neighborhood board
  bool get isDiscussion => mode == BeaconMode.discussion;

  static BeaconType fromString(String value) {
    return BeaconType.values.firstWhere(
      (type) => type.value == value,
      orElse: () => BeaconType.community,
    );
  }

  /// All types that belong to the map layer
  static List<BeaconType> get geoAlertTypes =>
      values.where((t) => t.isGeoAlert).toList();

  /// All types that belong to the neighborhood board
  static List<BeaconType> get discussionTypes =>
      values.where((t) => t.isDiscussion).toList();
  
  /// Get helper text for checkpoint and task force types
  String? get helperText {
    switch (this) {
      case BeaconType.checkpoint:
        return 'Report stationary stops, roadblocks, or inspection points.';
      case BeaconType.taskForce:
        return 'Report heavy coordinated activity or multiple units.';
      default:
        return null;
    }
  }
}

/// Beacon status color based on confidence score
enum BeaconStatus {
  green('green', 'Verified', 'High confidence - Community verified'),
  yellow('yellow', 'Caution', 'Pending verification'),
  red('red', 'Unverified', 'Low confidence - Needs verification');

  final String value;
  final String label;
  final String description;

  const BeaconStatus(this.value, this.label, this.description);

  static BeaconStatus fromConfidence(double score) {
    if (score > 0.7) {
      return BeaconStatus.green;
    } else if (score >= 0.3 && score <= 0.7) {
      return BeaconStatus.yellow;
    } else {
      return BeaconStatus.red;
    }
  }
}

/// Beacon model representing a location-based safety/community alert
class Beacon {
  final String id;
  final String body;
  final String authorId;
  final BeaconType beaconType;
  final double confidenceScore;
  final bool isActiveBeacon;
  final BeaconStatus status;
  final DateTime createdAt;
  final double distanceMeters;
  final String? imageUrl;

  // Location info
  final double? beaconLat;
  final double? beaconLong;

  // Author info
  final String? authorHandle;
  final String? authorDisplayName;
  final String? authorAvatarUrl;

  // Vote info
  final int? vouchCount;
  final int? reportCount;
  final String? userVote; // 'vouch', 'report', or null

  // Group association (neighborhood)
  final String? groupId;

  // Safety system fields
  final BeaconSeverity severity;
  final BeaconIncidentStatus incidentStatus;
  final int radius; // area of effect in meters
  final int verificationCount; // "I see this too" vouches

  Beacon({
    required this.id,
    required this.body,
    required this.authorId,
    required this.beaconType,
    required this.confidenceScore,
    required this.isActiveBeacon,
    required this.status,
    required this.createdAt,
    this.distanceMeters = 0,
    this.imageUrl,
    this.beaconLat,
    this.beaconLong,
    this.authorHandle,
    this.authorDisplayName,
    this.authorAvatarUrl,
    this.vouchCount,
    this.reportCount,
    this.userVote,
    this.groupId,
    this.severity = BeaconSeverity.medium,
    this.incidentStatus = BeaconIncidentStatus.active,
    this.radius = 500,
    this.verificationCount = 0,
  });

  /// Parse double from various types
  static double _parseDouble(dynamic value, {double fallback = 0.0}) {
    if (value is double) return value;
    if (value is int) return value.toDouble();
    if (value is num) return value.toDouble();
    return fallback;
  }

  /// Parse int from various types
  static int _parseInt(dynamic value) {
    if (value is int) return value;
    if (value is num) return value.toInt();
    return 0;
  }

  factory Beacon.fromJson(Map<String, dynamic> json) {
    final statusColor = json['status_color'] as String? ?? 'yellow';
    final status = _getStatusFromColor(statusColor);
    final beaconType = BeaconType.fromString(json['beacon_type'] as String? ?? 'community');

    return Beacon(
      id: json['id'] as String,
      body: json['body'] as String,
      authorId: json['author_id'] as String? ?? '',
      beaconType: beaconType,
      confidenceScore: _parseDouble(json['confidence_score']),
      isActiveBeacon: json['is_active_beacon'] as bool? ?? true,
      status: status,
      createdAt: DateTime.parse(json['created_at'] as String),
      distanceMeters: _parseDouble(json['distance_meters']),
      imageUrl: json['image_url'] as String?,
      beaconLat: json['beacon_lat'] != null ? _parseDouble(json['beacon_lat']) : null,
      beaconLong: json['beacon_long'] != null ? _parseDouble(json['beacon_long']) : null,
      authorHandle: json['author_handle'] as String?,
      authorDisplayName: json['author_display_name'] as String?,
      authorAvatarUrl: json['author_avatar_url'] as String?,
      vouchCount: _parseInt(json['vouch_count']),
      reportCount: _parseInt(json['report_count']),
      userVote: json['user_vote'] as String?,
      groupId: json['group_id'] as String?,
      severity: BeaconSeverity.fromString(json['severity'] as String? ?? 'medium'),
      incidentStatus: BeaconIncidentStatus.fromString(json['incident_status'] as String? ?? 'active'),
      radius: _parseInt(json['radius'] ?? 500),
      verificationCount: _parseInt(json['verification_count'] ?? 0),
    );
  }

  static BeaconStatus _getStatusFromColor(String color) {
    switch (color) {
      case 'green':
        return BeaconStatus.green;
      case 'yellow':
        return BeaconStatus.yellow;
      case 'red':
      default:
        return BeaconStatus.red;
    }
  }

  /// Get human-readable distance
  String getFormattedDistance() {
    if (distanceMeters < 1000) {
      return '${distanceMeters.round()}m';
    } else {
      final km = distanceMeters / 1000;
      return '${km.toStringAsFixed(1)}km';
    }
  }

  /// Get time ago string
  String getTimeAgo() {
    final now = DateTime.now();
    final difference = now.difference(createdAt);

    if (difference.inMinutes < 1) {
      return 'Just now';
    } else if (difference.inMinutes < 60) {
      return '${difference.inMinutes}m ago';
    } else if (difference.inHours < 24) {
      return '${difference.inHours}h ago';
    } else {
      return '${difference.inDays}d ago';
    }
  }

  /// Whether this beacon was reported in the last 30 minutes (for pulse animation)
  bool get isRecent => DateTime.now().difference(createdAt).inMinutes < 30;

  /// Color for the map pin based on severity
  Color get pinColor => severity.color;

  Map<String, dynamic> toJson() {
    return {
      'id': id,
      'body': body,
      'author_id': authorId,
      'beacon_type': beaconType.value,
      'confidence_score': confidenceScore,
      'is_active_beacon': isActiveBeacon,
      'status_color': status.value,
      'created_at': createdAt.toIso8601String(),
      'distance_meters': distanceMeters,
      'image_url': imageUrl,
      'beacon_lat': beaconLat,
      'beacon_long': beaconLong,
      'author_handle': authorHandle,
      'author_display_name': authorDisplayName,
      'author_avatar_url': authorAvatarUrl,
      'vouch_count': vouchCount,
      'report_count': reportCount,
      'user_vote': userVote,
      'severity': severity.value,
      'incident_status': incidentStatus.value,
      'radius': radius,
      'verification_count': verificationCount,
      if (groupId != null) 'group_id': groupId,
    };
  }
}

/// Beacon creation request
class CreateBeaconRequest {
  final double lat;
  final double long;
  final String title;
  final String description;
  final BeaconType type;
  final BeaconSeverity severity;
  final String? imageUrl;

  CreateBeaconRequest({
    required this.lat,
    required this.long,
    required this.title,
    required this.description,
    required this.type,
    this.severity = BeaconSeverity.medium,
    this.imageUrl,
  });

  Map<String, dynamic> toJson() {
    return {
      'lat': lat,
      'long': long,
      'title': title,
      'description': description,
      'type': type.value,
      'severity': severity.value,
      if (imageUrl != null) 'image_url': imageUrl,
    };
  }
}
