/*
 * Copyright (c)2009-2025 DemiVision, LLC. All Rights Reserved. The information
 * herein is the CONFIDENTIAL and PROPRIETARY information of DemiVision, LLC.
 */

using CommunityToolkit.Maui.Core;
using CommunityToolkit.Maui.Behaviors;

#if ANDROID
	using Android.OS;
	using Android.App;
	using Android.Views;
	
	using Android.Content.PM;
	using Android.Content.Res;

	using Microsoft.Maui.Platform;
#endif

namespace DXLib.Utils;

// Size breakpoints for pre-defined layouts (outside class for shorthand access)
public enum LayoutType
{
	Landscape,
	Portrait,

	WideLandscape,
	WidePortrait,

	MobileLandscape,
	MobilePortrait
};

/*
 * Provides utility methods related to native device information. Platform specific code is used where needed.
 */
public static class DXDevice
{
	/* Constants */

	// Platform keys
	public const string IosKey = "ios";
	public const string AndroidKey = "droid";
	public const string GoogleKey = "Google";

	/* Properties */

	// Does this iOS device require safe area padding?
	public static bool HasSafeArea { get; private set; }

    // Android or iOS?
    public static bool IsIOS { get; private set; }
    public static bool IsAndroid { get; private set; }
	public static bool IsGoogle { get; private set; }


	// Mobile or Tablet?
	public static bool IsMobile { get; private set; }
	public static bool IsTablet { get; private set; }
	public static bool IsTabletWide { get; private set; }

	// Running on simulator/emulator?
	public static bool IsSimulator { get; private set; }

	// Screen DPI scale
	public static double Scale { get; private set; }

	// Android virtual soft key bar
	public static double NavBarHt { get; private set; }

	// Direct properties of the device and OS
	public static string PlatformOS => DeviceInfo.Platform.ToString();
	public static string PlatformOSKey => IsIOS ? IosKey : AndroidKey;

	public static string Idiom => DeviceInfo.Idiom.ToString();
	public static string Model => DeviceInfo.Model;
	public static string Manufacturer => DeviceInfo.Manufacturer;
	public static string Name => DeviceInfo.Name;

	public static Version Version => DeviceInfo.Version;
	public static string VersionString => DeviceInfo.VersionString;

    /* Methods */

    // Must be called at app launch
    public static void Init()
	{
		// Pseudo constants
		IsAndroid = DeviceInfo.Platform == DevicePlatform.Android;
		IsIOS = DeviceInfo.Platform == DevicePlatform.iOS;
		IsGoogle = DeviceInfo.Current.Manufacturer == GoogleKey;

        IsMobile = DeviceInfo.Idiom == DeviceIdiom.Phone;
		IsTablet = DeviceInfo.Idiom == DeviceIdiom.Tablet;
		IsTabletWide = IsTablet && IsWidescreen();

		IsSimulator = DeviceInfo.DeviceType == DeviceType.Virtual;

		Scale = DeviceDisplay.MainDisplayInfo.Density;
		NavBarHt = GetNavBarHt();

		// MUST be last
		HasSafeArea = CheckForSafeArea();
	}

    /* Styling */

    // Sets color of native status bar 
    public static void SetStatusBarColor( ContentPage page, Color color )
    {
	    page.Behaviors.Add( new StatusBarBehavior
	    {
		    StatusBarColor = color,
		    StatusBarStyle = StatusBarStyle.LightContent
	    });
    }
    
	/* Orientation */

	// Is device currently in portrait orientation?
	public static bool IsPortrait()
	{
		return (DeviceDisplay.MainDisplayInfo.Orientation == DisplayOrientation.Portrait);
	}

	// Portrait orientation on mobile often requires special handling
	public static bool IsMobilePortrait()
	{
		return (GetLayoutType() == LayoutType.MobilePortrait);
	}

	// Landscape orientation on mobile sometimes requires special handling
	public static bool IsMobileLandscape()
	{
		return (GetLayoutType() == LayoutType.MobileLandscape);
	}

	// Is device currently in landscape orientation (either left or right)?
	public static bool IsLandscape()
	{
		return (DeviceDisplay.MainDisplayInfo.Orientation == DisplayOrientation.Landscape);
	}

	// Is device currently rotated with top (notch) to the left?
	public static bool IsLandscapeLeft()
	{
		return (DeviceDisplay.MainDisplayInfo.Rotation == DisplayRotation.Rotation90);
	}

	// Is device currently rotated with top (notch) to the right?
	public static bool IsLandscapeRight()
	{
		return (DeviceDisplay.MainDisplayInfo.Rotation == DisplayRotation.Rotation270);
	}

	/* Size */

	// Determines if device display is widescreen aspect ratio
	public static bool IsWidescreen()
	{
		double wd = GetScreenWd();
		double ht = GetScreenHt();

		double min = Math.Min( wd, ht );
		double max = Math.Max( wd, ht );

		// Anything greater than 3:2 aspect ratio is widesreen
		return (max / min) > 1.50;
	}

	// Determines if display is widescreen and in landscape orientation
	public static bool IsWideLandscape()
	{
		return IsTabletWide && IsLandscape();
	}

	// Determines if device is tablet or iPhone X, N-Plus size
	public static bool IsPlusSize()
	{
		return IsTablet || (IsLandscape() && (GetScreenWd() > 700)) || (IsPortrait() && (GetScreenHt() > 700));
	}

	// Determines if device is an extra large tablet (iPad Pro)
	public static bool IsLargeTablet()
	{
		return IsTablet && (GetLandscapeWd() > 1080);
	}

	// Returns width of screen adjusted for density (device independent pixels)
	public static double GetScreenWd( bool native = true )
	{
        DisplayInfo info = DeviceDisplay.MainDisplayInfo;

		// Use Essentials
		double wd = info.Width;
		double density = info.Density;

		return (wd / density);
	}

	// Returns height of screen adjusted for density (device independent pixels)
	public static double GetScreenHt( bool native = true )
	{
		DisplayInfo info = DeviceDisplay.MainDisplayInfo;

        // Use Essentials
        double ht = info.Height;
		double density = info.Density;

		return (ht / density);
	}

	// Returns screen size based on longest dimension (width or height)
	public static double GetScreenDim()
	{
		return Math.Max( GetScreenWd(), GetScreenHt() );
	}

	// Returns screen width when in landscape orientation
	public static double GetLandscapeWd()
	{
		return Math.Max( GetScreenWd(), GetScreenHt() );
	}

	// Returns screen width when in portrait dimension
	public static double GetPortraitWd()
	{
		return Math.Min( GetScreenWd(), GetScreenHt() );
	}

	/* Safe Area */

	// Used internally to determine if iOS device has protected safe area (notch)
	private static bool CheckForSafeArea()
	{
		bool safeArea = false;

		// All current safe area models
		if ( IsIOS )
		{
			string model = DeviceInfo.Model;

			if ( model.Contains( "iPhone10,3" ) ||    // iPhone X
			     model.Contains( "iPhone10,6" ) ||    // iPhone X GSM

			     model.Contains( "iPhone11" ) ||      // iPhone XS, XR

			     model.Contains( "iPhone12,1" ) ||    // iPhone 11
			     model.Contains( "iPhone12,3" ) ||    // iPhone 11 Pro
			     model.Contains( "iPhone12,5" ) ||    // iPhone 11 Pro Max

			     model.Contains( "iPhone13,2" ) ||    // iPhone 12
			     model.Contains( "iPhone13,3" ) ||    // iPhone 12 Pro
			     model.Contains( "iPhone13,4" ) ||    // iPhone 12 Pro Max

			     model.Contains( "iPhone14,5" ) ||    // iPhone 13
			     model.Contains( "iPhone14,2" ) ||    // iPhone 13 Pro
			     model.Contains( "iPhone14,3" ) ||    // iPhone 13 Pro Max

			     model.Contains( "iPhone14,7" ) ||    // iPhone 14
			     model.Contains( "iPhone14,8" ) ||    // iPhone 14 Plus
			     model.Contains( "iPhone15,2" ) ||    // iPhone 14 Pro
			     model.Contains( "iPhone15,3" ) ||    // iPhone 14 Pro Max

			     model.Contains( "iPhone15,4" ) ||    // iPhone 15
			     model.Contains( "iPhone15,5" ) ||    // iPhone 15 Plus
			     model.Contains( "iPhone16,1" ) ||    // iPhone 15 Pro
			     model.Contains( "iPhone16,2" ) ||    // iPhone 15 Pro Max

			     model.Contains( "iPhone17" )   ||    // iPhone 16, 16e, 16 Plus, 16 Pro, 16 Pro Max
			     
			     model.Contains( "iPad8" )  ||		  // iPad Pro 11" (1st, 2nd) 12.9" (3rd, 4th)
			     model.Contains( "iPad13" ) ||        // iPad Pro 11" (3rd) 12.9" (5th), iPad (10th), iPad Air (4th, 5th)
			     model.Contains( "iPad14" ) || 		  // iPad Mini (6th), iPad Air 11" (6th) 13" (6th)
			     model.Contains( "iPad16" ) ) 		  // iPad Pro 11" (5th) 13" (7th)
			{
				safeArea = true;
			}
		}

		return safeArea;
	}
	
	// Returns protected area height for status bar and notch based on device type (assumes portrait orientation)
	public static double GetSafeTop()
	{
		// iOS
		if ( IsIOS )
		{
			// iPad
			if ( IsTablet )
			{
				return 20;
			}
			
			string model = DeviceInfo.Model;

			// iPhone X, 11
			if ( model.Contains( "iPhone10" ) || model.Contains( "iPhone11" ) || model.Contains( "iPhone12" ) )
			{
				return 44;
			}

			// iPhone 12, 13, (base 14)
			if ( model.Contains( "iPhone13" ) || model.Contains( "iPhone14" ) )
			{
				return 47;
			}

			// iPhone 14 Pro, 15, 16
			if ( model.Contains( "iPhone15" ) || model.Contains( "iPhone16" ) || model.Contains( "iPhone17" ) )
			{
				return 59;
			}

			// Older iPhones
			return 20;
		}
		
		// Android
		return GetNativeStatusBarHt();
	}

	// Returns protected bottom area based on device type and orientation
	public static double GetSafeBottom()
	{
		// Bottom home bar
		if ( HasSafeArea )
		{
			return IsTablet ? 20 : 21;
		}

		// Older iOS or Android
		return IsIOS ? 0 : 20;
	}
	
	// Return thickness of safe area, if any, on all four sides of screen
	public static Thickness SafeArea()
	{
		double safeTop = GetSafeTop();
		double safeBottom = GetSafeBottom();
		
		// Tablet
		if ( IsTablet )
		{
			return new Thickness( 0, safeTop, 0, safeBottom );
		}

		// Mobile- portrait
		if ( IsPortrait() )
		{
			return new Thickness( 0, safeTop, 0, safeBottom );
		}

		double safeTopLandscape = IsIOS ? 0 : safeTop;
		
		// Mobile- landscape
		return IsLandscapeLeft() ? new Thickness( safeTop, safeTopLandscape, 0, safeBottom ) 
								 : new Thickness( 0, safeTopLandscape, safeTop, safeBottom );
	}

	// Returns full screen bounds minus notch safe area
	public static Rect SafeBounds()
	{
		Thickness safeArea = SafeArea();

		double x = safeArea.Left;
		double y = safeArea.Top;

		double wd = GetScreenWd() - safeArea.HorizontalThickness;
		double ht = GetScreenHt() - safeArea.VerticalThickness;

		return new Rect( x, y, wd, ht );
	}

	// Returns safe area plus additional area for screens with rounded corners
	public static Thickness ExtraSafeArea()
	{
		Thickness safeArea = SafeArea();
		double corner = CornerArea();

		// Only applicable for landscape
		if ( IsLandscape() )
		{
			return IsLandscapeLeft() ? new Thickness( safeArea.Left, safeArea.Top, corner, safeArea.Bottom ) 
									 : new Thickness( corner, safeArea.Top, safeArea.Right, safeArea.Bottom );
		}

		return safeArea;
	}

	// Defines corner padding for devices with rounded screens
	public static double CornerArea()
	{
		return (HasSafeArea || IsAndroid) ? 35 : 0;
	}

	// Returns safe area on bottom plus left/right
	public static Thickness SafeAreaLRB()
	{
		Thickness safeArea = SafeArea();

		return new Thickness( safeArea.Left, 0, safeArea.Right, safeArea.Bottom );
	}

	// Returns safe area on top plus left/right
	public static Thickness SafeAreaLTR()
	{
		Thickness safeArea = SafeArea();

		return new Thickness( safeArea.Left, safeArea.Top, safeArea.Right, 0 );
	}
	
	// Returns safe area on left/right only
	public static Thickness SafeAreaLR()
	{
		Thickness safeArea = SafeArea();

		return new Thickness( safeArea.Left, 0, safeArea.Right, 0 );
	}
	
	// Returns safe area on top only
	public static Thickness SafeAreaT()
	{
		Thickness safeArea = SafeArea();

		return new Thickness( 0, safeArea.Top, 0, 0 );
	}

	/* Layout */

	// Determines current layout template based on device type/orientation
	public static LayoutType GetLayoutType( bool wide = false )
	{
		if ( IsTablet )
		{
			// Optionally special case widescreen
			if ( wide && IsTabletWide )
			{
				return IsLandscape() ? LayoutType.WideLandscape : LayoutType.WidePortrait;
			}

			return IsLandscape() ? LayoutType.Landscape : LayoutType.Portrait;
		}

		return IsLandscape() ? LayoutType.MobileLandscape : LayoutType.MobilePortrait;
	}
	
	/* Device Specific */

	// Returns height of native status bar
	private static double GetNativeStatusBarHt()
	{
		// Portrait
		if ( IsPortrait() )
		{
			#if IOS
				return 0;
			#elif ANDROID
				double statusHt = 0;
			
				Resources res = Platform.CurrentActivity?.ApplicationContext?.Resources;

				// Use native resource to access start bar height
				if ( res != null )
				{
					int resId = res.GetIdentifier( "status_bar_height", "dimen", "android" );
	
					double ht = res.GetDimensionPixelSize( resId );
					double density = 1;
	
					if ( res.DisplayMetrics != null )
					{
						density = res.DisplayMetrics.Density;
					}
	
					statusHt = ((ht / density) - 10);
				}

				return statusHt;
			#endif
		}
		
		// Landscape
		return IsIOS ? 0 : 20;
	}

	// Returns height of native navigation bar
	private static double GetNavBarHt()
	{
		#if IOS
			return 0;
		#elif ANDROID
			Resources res = Android.App.Application.Context.Resources;

			bool hasNavBar = false;

			// Determine if has nav bar
			if ( res != null )
			{
				int resId = res.GetIdentifier( "config_showNavigationBar", "bool", "android" );
 
				hasNavBar = (resId > 0) && res.GetBoolean( resId );
			}
		
			// Must access via resource
			if ( hasNavBar )
			{
				if ( res != null )
				{
					int resId = res.GetIdentifier( "navigation_bar_height", "dimen", "android" );
	
					return res.GetDimensionPixelSize( resId );
				}
			}
	
			return 0;
		#endif
	}

	// Sets native soft key nav bar color (NA for iOS)
	public static void SetNavBarColor( Color color )
	{
		#if ANDROID 
			Android.Views.Window window = Platform.CurrentActivity?.Window;

			window?.SetNavigationBarColor( color.ToPlatform() );
		#endif
	}

	// Locks device orientation, ignores user rotation
	public static void LockOrientation( bool locked )
	{
		#if ANDROID
			Activity activity = Platform.CurrentActivity;

			activity?.RequestedOrientation = locked ? ScreenOrientation.Portrait : ScreenOrientation.Sensor;
		#endif
	}

	// Determines if this is an Android R or newer device (which requires special screen size handling)
	public static bool IsAndroidR()
	{
		#if ANDROID
			return (Build.VERSION.SdkInt >= BuildVersionCodes.R);
        #else
			return false;
		#endif
    }
}

//
