import 'dart:convert';

import 'package:hive_ce/hive.dart';

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

part 'user_model.g.dart';

/// User Model
///
/// Hive CE model for caching user data locally.
/// Maps to the 'users' table in the database.
///
/// Type ID: 0
@HiveType(typeId: HiveTypeIds.userModel)
class UserModel extends HiveObject {
  UserModel({
    required this.userId,
    required this.phoneNumber,
    this.passwordHash,
    required this.fullName,
    this.email,
    required this.role,
    required this.status,
    required this.loyaltyTier,
    required this.totalPoints,
    this.companyInfo,
    this.cccd,
    this.attachments,
    this.address,
    this.avatarUrl,
    this.referralCode,
    this.referredBy,
    this.erpnextCustomerId,
    required this.createdAt,
    this.updatedAt,
    this.lastLoginAt,
  });

  /// User ID (Primary Key)
  @HiveField(0)
  final String userId;

  /// Phone number (unique, used for login)
  @HiveField(1)
  final String phoneNumber;

  /// Password hash (stored encrypted)
  @HiveField(2)
  final String? passwordHash;

  /// Full name of the user
  @HiveField(3)
  final String fullName;

  /// Email address
  @HiveField(4)
  final String? email;

  /// User role (customer, distributor, admin, staff)
  @HiveField(5)
  final UserRole role;

  /// Account status (active, inactive, suspended, pending)
  @HiveField(6)
  final UserStatus status;

  /// Loyalty tier (bronze, silver, gold, platinum, diamond, titan)
  @HiveField(7)
  final LoyaltyTier loyaltyTier;

  /// Total accumulated loyalty points
  @HiveField(8)
  final int totalPoints;

  /// Company information (JSON encoded)
  /// Contains: company_name, tax_id, business_type, etc.
  @HiveField(9)
  final String? companyInfo;

  /// Citizen ID (CCCD/CMND)
  @HiveField(10)
  final String? cccd;

  /// Attachments (JSON encoded list)
  /// Contains: identity_card_images, business_license, etc.
  @HiveField(11)
  final String? attachments;

  /// Address
  @HiveField(12)
  final String? address;

  /// Avatar URL
  @HiveField(13)
  final String? avatarUrl;

  /// Referral code for this user
  @HiveField(14)
  final String? referralCode;

  /// ID of user who referred this user
  @HiveField(15)
  final String? referredBy;

  /// ERPNext customer ID for integration
  @HiveField(16)
  final String? erpnextCustomerId;

  /// Account creation timestamp
  @HiveField(17)
  final DateTime createdAt;

  /// Last update timestamp
  @HiveField(18)
  final DateTime? updatedAt;

  /// Last login timestamp
  @HiveField(19)
  final DateTime? lastLoginAt;

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

  /// Create UserModel from JSON
  factory UserModel.fromJson(Map<String, dynamic> json) {
    return UserModel(
      userId: json['user_id'] as String,
      phoneNumber: json['phone_number'] as String,
      passwordHash: json['password_hash'] as String?,
      fullName: json['full_name'] as String,
      email: json['email'] as String?,
      role: UserRole.values.firstWhere(
        (e) => e.name == (json['role'] as String),
        orElse: () => UserRole.customer,
      ),
      status: UserStatus.values.firstWhere(
        (e) => e.name == (json['status'] as String),
        orElse: () => UserStatus.pending,
      ),
      loyaltyTier: LoyaltyTier.values.firstWhere(
        (e) => e.name == (json['loyalty_tier'] as String),
        orElse: () => LoyaltyTier.bronze,
      ),
      totalPoints: json['total_points'] as int? ?? 0,
      companyInfo: json['company_info'] != null
          ? jsonEncode(json['company_info'])
          : null,
      cccd: json['cccd'] as String?,
      attachments: json['attachments'] != null
          ? jsonEncode(json['attachments'])
          : null,
      address: json['address'] as String?,
      avatarUrl: json['avatar_url'] as String?,
      referralCode: json['referral_code'] as String?,
      referredBy: json['referred_by'] as String?,
      erpnextCustomerId: json['erpnext_customer_id'] as String?,
      createdAt: DateTime.parse(json['created_at'] as String),
      updatedAt: json['updated_at'] != null
          ? DateTime.parse(json['updated_at'] as String)
          : null,
      lastLoginAt: json['last_login_at'] != null
          ? DateTime.parse(json['last_login_at'] as String)
          : null,
    );
  }

  /// Convert UserModel to JSON
  Map<String, dynamic> toJson() {
    return {
      'user_id': userId,
      'phone_number': phoneNumber,
      'password_hash': passwordHash,
      'full_name': fullName,
      'email': email,
      'role': role.name,
      'status': status.name,
      'loyalty_tier': loyaltyTier.name,
      'total_points': totalPoints,
      'company_info': companyInfo != null ? jsonDecode(companyInfo!) : null,
      'cccd': cccd,
      'attachments': attachments != null ? jsonDecode(attachments!) : null,
      'address': address,
      'avatar_url': avatarUrl,
      'referral_code': referralCode,
      'referred_by': referredBy,
      'erpnext_customer_id': erpnextCustomerId,
      'created_at': createdAt.toIso8601String(),
      'updated_at': updatedAt?.toIso8601String(),
      'last_login_at': lastLoginAt?.toIso8601String(),
    };
  }

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

  /// Get company info as Map
  Map<String, dynamic>? get companyInfoMap {
    if (companyInfo == null) return null;
    try {
      return jsonDecode(companyInfo!) as Map<String, dynamic>;
    } catch (e) {
      return null;
    }
  }

  /// Get attachments as List
  List<dynamic>? get attachmentsList {
    if (attachments == null) return null;
    try {
      return jsonDecode(attachments!) as List<dynamic>;
    } catch (e) {
      return null;
    }
  }

  /// Check if user is active
  bool get isActive => status == UserStatus.active;

  /// Check if user is admin or staff
  bool get isStaff => role == UserRole.admin || role == UserRole.staff;

  /// Get user initials for avatar
  String get initials {
    final parts = fullName.trim().split(' ');
    if (parts.length >= 2) {
      return '${parts.first[0]}${parts.last[0]}'.toUpperCase();
    }
    return fullName.isNotEmpty ? fullName[0].toUpperCase() : '?';
  }

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

  /// Create a copy with updated fields
  UserModel copyWith({
    String? userId,
    String? phoneNumber,
    String? passwordHash,
    String? fullName,
    String? email,
    UserRole? role,
    UserStatus? status,
    LoyaltyTier? loyaltyTier,
    int? totalPoints,
    String? companyInfo,
    String? cccd,
    String? attachments,
    String? address,
    String? avatarUrl,
    String? referralCode,
    String? referredBy,
    String? erpnextCustomerId,
    DateTime? createdAt,
    DateTime? updatedAt,
    DateTime? lastLoginAt,
  }) {
    return UserModel(
      userId: userId ?? this.userId,
      phoneNumber: phoneNumber ?? this.phoneNumber,
      passwordHash: passwordHash ?? this.passwordHash,
      fullName: fullName ?? this.fullName,
      email: email ?? this.email,
      role: role ?? this.role,
      status: status ?? this.status,
      loyaltyTier: loyaltyTier ?? this.loyaltyTier,
      totalPoints: totalPoints ?? this.totalPoints,
      companyInfo: companyInfo ?? this.companyInfo,
      cccd: cccd ?? this.cccd,
      attachments: attachments ?? this.attachments,
      address: address ?? this.address,
      avatarUrl: avatarUrl ?? this.avatarUrl,
      referralCode: referralCode ?? this.referralCode,
      referredBy: referredBy ?? this.referredBy,
      erpnextCustomerId: erpnextCustomerId ?? this.erpnextCustomerId,
      createdAt: createdAt ?? this.createdAt,
      updatedAt: updatedAt ?? this.updatedAt,
      lastLoginAt: lastLoginAt ?? this.lastLoginAt,
    );
  }

  @override
  String toString() {
    return 'UserModel(userId: $userId, fullName: $fullName, role: $role, tier: $loyaltyTier, points: $totalPoints)';
  }

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

    return other is UserModel && other.userId == userId;
  }

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