import 'package:hive_ce/hive.dart';

import 'package:worker/core/constants/storage_constants.dart';

part 'user_session_model.g.dart';

/// User Session Model
///
/// Hive CE model for caching user session data locally.
/// Maps to the 'user_sessions' table in the database.
///
/// Type ID: 1
@HiveType(typeId: HiveTypeIds.userSessionModel)
class UserSessionModel extends HiveObject {
  UserSessionModel({
    required this.sessionId,
    required this.userId,
    required this.deviceId,
    this.deviceType,
    this.deviceName,
    this.ipAddress,
    this.userAgent,
    this.refreshToken,
    required this.expiresAt,
    required this.createdAt,
    this.lastActivity,
  });

  /// Session ID (Primary Key)
  @HiveField(0)
  final String sessionId;

  /// User ID (Foreign Key to users)
  @HiveField(1)
  final String userId;

  /// Device ID (unique identifier for the device)
  @HiveField(2)
  final String deviceId;

  /// Device type (android, ios, web, etc.)
  @HiveField(3)
  final String? deviceType;

  /// Device name (e.g., "Samsung Galaxy S21")
  @HiveField(4)
  final String? deviceName;

  /// IP address of the device
  @HiveField(5)
  final String? ipAddress;

  /// User agent string
  @HiveField(6)
  final String? userAgent;

  /// Refresh token for session renewal
  @HiveField(7)
  final String? refreshToken;

  /// Session expiration timestamp
  @HiveField(8)
  final DateTime expiresAt;

  /// Session creation timestamp
  @HiveField(9)
  final DateTime createdAt;

  /// Last activity timestamp
  @HiveField(10)
  final DateTime? lastActivity;

  // =========================================================================
  // JSON SERIALIZATION
  // =========================================================================

  /// Create UserSessionModel from JSON
  factory UserSessionModel.fromJson(Map<String, dynamic> json) {
    return UserSessionModel(
      sessionId: json['session_id'] as String,
      userId: json['user_id'] as String,
      deviceId: json['device_id'] as String,
      deviceType: json['device_type'] as String?,
      deviceName: json['device_name'] as String?,
      ipAddress: json['ip_address'] as String?,
      userAgent: json['user_agent'] as String?,
      refreshToken: json['refresh_token'] as String?,
      expiresAt: DateTime.parse(json['expires_at'] as String),
      createdAt: DateTime.parse(json['created_at'] as String),
      lastActivity: json['last_activity'] != null
          ? DateTime.parse(json['last_activity'] as String)
          : null,
    );
  }

  /// Convert UserSessionModel to JSON
  Map<String, dynamic> toJson() {
    return {
      'session_id': sessionId,
      'user_id': userId,
      'device_id': deviceId,
      'device_type': deviceType,
      'device_name': deviceName,
      'ip_address': ipAddress,
      'user_agent': userAgent,
      'refresh_token': refreshToken,
      'expires_at': expiresAt.toIso8601String(),
      'created_at': createdAt.toIso8601String(),
      'last_activity': lastActivity?.toIso8601String(),
    };
  }

  // =========================================================================
  // HELPER METHODS
  // =========================================================================

  /// Check if session is expired
  bool get isExpired => DateTime.now().isAfter(expiresAt);

  /// Check if session is valid (not expired)
  bool get isValid => !isExpired;

  /// Get session duration
  Duration get duration => DateTime.now().difference(createdAt);

  /// Get time until expiration
  Duration get timeUntilExpiration => expiresAt.difference(DateTime.now());

  /// Get session age
  Duration get age => DateTime.now().difference(createdAt);

  /// Get time since last activity
  Duration? get timeSinceLastActivity {
    if (lastActivity == null) return null;
    return DateTime.now().difference(lastActivity!);
  }

  // =========================================================================
  // COPY WITH
  // =========================================================================

  /// Create a copy with updated fields
  UserSessionModel copyWith({
    String? sessionId,
    String? userId,
    String? deviceId,
    String? deviceType,
    String? deviceName,
    String? ipAddress,
    String? userAgent,
    String? refreshToken,
    DateTime? expiresAt,
    DateTime? createdAt,
    DateTime? lastActivity,
  }) {
    return UserSessionModel(
      sessionId: sessionId ?? this.sessionId,
      userId: userId ?? this.userId,
      deviceId: deviceId ?? this.deviceId,
      deviceType: deviceType ?? this.deviceType,
      deviceName: deviceName ?? this.deviceName,
      ipAddress: ipAddress ?? this.ipAddress,
      userAgent: userAgent ?? this.userAgent,
      refreshToken: refreshToken ?? this.refreshToken,
      expiresAt: expiresAt ?? this.expiresAt,
      createdAt: createdAt ?? this.createdAt,
      lastActivity: lastActivity ?? this.lastActivity,
    );
  }

  @override
  String toString() {
    return 'UserSessionModel(sessionId: $sessionId, userId: $userId, isValid: $isValid)';
  }

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;

    return other is UserSessionModel && other.sessionId == sessionId;
  }

  @override
  int get hashCode => sessionId.hashCode;
}
