using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace LSFE.MobApp.Services
{
    public interface IDeviceInfoService
    {
        Task<string> GetDeviceIdentifierAsync();
        Task<Infrastructure.Model.Admin.DeviceInfo> GetDeviceInfoAsync();
        string GetDeviceModel();
        string GetDevicePlatform();
        string GetDeviceVersion();
    }

    public class DeviceInfoService : IDeviceInfoService
    {
        /// <summary>
        /// Gets a unique device identifier that combines multiple device properties
        /// This is more reliable than IMEI alone and works across platforms
        /// </summary>
        public async Task<string> GetDeviceIdentifierAsync()
        {
            try
            {
                // Get device ID from platform-specific implementation
                var deviceId = await GetPlatformDeviceIdAsync();

                // Create a hash of the device ID for security
                var hashedId = CreateHashedIdentifier(deviceId);

                return hashedId;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Error getting device identifier: {ex.Message}");
                // Fallback to a generated ID stored in preferences
                return await GetOrCreateStoredDeviceIdAsync();
            }
        }

        /// <summary>
        /// Gets comprehensive device information
        /// </summary>
        public async Task<Infrastructure.Model.Admin.DeviceInfo> GetDeviceInfoAsync()
        {
            var deviceId = await GetDeviceIdentifierAsync();

            return new Infrastructure.Model.Admin.DeviceInfo
            {
                DeviceId = deviceId,
                DeviceModel = GetDeviceModel(),
                Platform = GetDevicePlatform(),
                Version = GetDeviceVersion(),
                Manufacturer = DeviceInfo.Current.Manufacturer,
                Name = DeviceInfo.Current.Name,
                DeviceType = DeviceInfo.Current.DeviceType.ToString(),
                VersionString = DeviceInfo.Current.VersionString
            };
        }
        public string GetDeviceModel()
        {
            return DeviceInfo.Current.Model;
        }
        public string GetDevicePlatform()
        {
            return DeviceInfo.Current.Platform.ToString();
        }
        public string GetDeviceVersion()
        {
            return DeviceInfo.Current.VersionString;
        }

        #region Private Methods
        private async Task<string> GetPlatformDeviceIdAsync()
        {
#if ANDROID
            return await GetAndroidDeviceIdAsync();
#elif IOS
            return GetIOSDeviceId();
#else
            return GetGenericDeviceId();
#endif
        }

#if ANDROID
        private async Task<string> GetAndroidDeviceIdAsync()
        {
            try
            {
                var context = Android.App.Application.Context;

                // Method 1: Try to get Android ID (most reliable, doesn't require permissions)
                var androidId = Android.Provider.Settings.Secure.GetString(
                    context.ContentResolver,
                    Android.Provider.Settings.Secure.AndroidId);

                if (!string.IsNullOrEmpty(androidId) && androidId != "9774d56d682e549c")
                {
                    return $"ANDROID_{androidId}";
                }

                // Method 2: Get IMEI (requires READ_PHONE_STATE permission)
                // Note: This is restricted in Android 10+ for privacy
                var imei = await TryGetImeiAsync(context);
                if (!string.IsNullOrEmpty(imei))
                {
                    return $"IMEI_{imei}";
                }

                // Method 3: Fallback to combination of identifiers
                var buildId = Android.OS.Build.Id;
                var serial = Android.OS.Build.Serial;
                var combined = $"{androidId}_{buildId}_{serial}";

                return $"ANDROID_COMBINED_{CreateHashedIdentifier(combined)}";
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"Android device ID error: {ex.Message}");
                return GetGenericDeviceId();
            }
        }

        private async Task<string> TryGetImeiAsync(Android.Content.Context context)
        {
            try
            {
                // Check if we have permission
                var permission = Android.Manifest.Permission.ReadPhoneState;
                var hasPermission = Android.Content.PM.Permission.Granted ==
                    AndroidX.Core.Content.ContextCompat.CheckSelfPermission(context, permission);

                if (!hasPermission)
                {
                    System.Diagnostics.Debug.WriteLine("READ_PHONE_STATE permission not granted");
                    return null;
                }

                // For Android 10+, IMEI access is restricted
                if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.Q)
                {
                    System.Diagnostics.Debug.WriteLine("IMEI access restricted on Android 10+");
                    return null;
                }

                var telephonyManager = context.GetSystemService(Android.Content.Context.TelephonyService)
                    as Android.Telephony.TelephonyManager;

                if (telephonyManager != null)
                {
#pragma warning disable CS0618 // Type or member is obsolete
                    var imei = telephonyManager.DeviceId;
#pragma warning restore CS0618
                    return imei;
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"IMEI retrieval error: {ex.Message}");
            }

            return null;
        }
#endif

#if IOS
        private string GetIOSDeviceId()
        {
            try
            {
                // iOS uses IdentifierForVendor which is unique per app installation
                var uuid = UIKit.UIDevice.CurrentDevice.IdentifierForVendor;
                if (uuid != null)
                {
                    return $"iOS_{uuid.AsString()}";
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine($"iOS device ID error: {ex.Message}");
            }

            return GetGenericDeviceId();
        }
#endif
        private string GetGenericDeviceId()
        {
            // Fallback: combination of available device info
            var model = DeviceInfo.Current.Model;
            var manufacturer = DeviceInfo.Current.Manufacturer;
            var name = DeviceInfo.Current.Name;
            var platform = DeviceInfo.Current.Platform.ToString();

            var combined = $"{platform}_{manufacturer}_{model}_{name}";
            return CreateHashedIdentifier(combined);
        }
        private async Task<string> GetOrCreateStoredDeviceIdAsync()
        {
            const string key = "device_unique_id";

            try
            {
                var storedId = await SecureStorage.GetAsync(key);

                if (string.IsNullOrEmpty(storedId))
                {
                    // Generate a new unique ID
                    storedId = Guid.NewGuid().ToString();
                    await SecureStorage.SetAsync(key, storedId);
                }

                return $"STORED_{storedId}";
            }
            catch
            {
                // If SecureStorage fails, use Preferences
                var storedId = Preferences.Get(key, string.Empty);

                if (string.IsNullOrEmpty(storedId))
                {
                    storedId = Guid.NewGuid().ToString();
                    Preferences.Set(key, storedId);
                }

                return $"PREF_{storedId}";
            }
        }
        private string CreateHashedIdentifier(string input)
        {
            using var sha256 = SHA256.Create();
            var bytes = Encoding.UTF8.GetBytes(input);
            var hash = sha256.ComputeHash(bytes);
            return Convert.ToBase64String(hash);
        }

        #endregion
    }
}