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

using DXLib.UI.Control.Selector;

using DXLib.Data;
using DXLib.Data.Model;

using DXLib.Utils;

namespace DXLib.UI.Form.Control;

/*
 * A dropdown menu based form control that allows a single item to be selected from a list of items. The items can
 * be either from a resource string lookup table (LUT) or from a queried list of database objects. The dropdown menu
 * can optionally include a '+ Add New' footer for adding new objects.
 */
public class DXSelectorField : DXFormControl
{
    /* Events */

    // 'Add New' mode only
    public Action AddTapped { set => selector.AddTapped = value; }

    /* Properties */

    // LUT based
    public string Items { set => selector.LoadItems( value ); }
	public string SelectedItem { get => selector.SelectedKey; set => selector.SelectKey( value ); }

	public List<DXItem> ItemList { set => selector.LoadItems( value ); }

	// Query based
	public IList<DXModel> Objects { set => selector.LoadObjects( value ); }
	public DXModel SelectedObject { get => selector.GetSelectedObject(); set => selector.SelectObject( value ); }

	// Has a value been selected?
	public bool HasSelection => selector.HasSelection;

	// Optionally override HasClear
	public bool HideClear { get; set; }

	// 'Add New' mode only
	public string ObjectLabel { set => selector.ObjectLabel = value; }

	/* Fields */

	// Underlying control
	protected readonly DXSelector selector;

	// State
	private bool userOpened;

	/* Methods */
	public DXSelectorField( bool add = false )
	{
		// Create normal or 'Add New' control
		selector = add ? new DXAddSelector() : new DXSelector();

		selector.Padding = 0;
		selector.Margin = new Thickness( (LeftMargin - 2), 0, 0, 0 );
		
		// Register for events
		selector.DropdownOpened += OnOpened;
		selector.DropDownClosed += OnClosed;

		selector.SelectionChanged += OnSelectionChanged;
	}

	// Returns currently selected value as string
	public string GetString()
	{
		return GetObject() as string;
	}

	// Sets control specific colors
	public override void SetColor( Color color )
	{
		base.SetColor( color );

		selector.SetColor( color );
	}

	// Control specific enable/disable
	public override void SetDisabled( bool disabled )
	{
		// String list handled normally
		if ( selector.HasItems )
		{
			base.SetDisabled( disabled );
		}
		// Object list must have values to enable
		else
		{
			base.SetDisabled( disabled || !selector.HasObjects );
		}

		selector.SetDisabled( disabled );
	}

	// Clears current field entry (optionally hides)
	public void Clear( bool hide = false )
	{
		IsVisible = !hide;

		// Clear item/object
		if ( selector.HasItems )
		{
			selector.SelectKey( null );
		}
		else
		{
			selector.SelectObject( null );
		}
	}

	// Updates content clear button visibility and layout
	protected void UpdateClear()
	{
		if ( HasClear )
		{
			bool hasValue = HasValue();

			selector.Margin = new Thickness( LeftMargin, 0, (hasValue ? RightMargin : 0), 0 );
			clearBtn.IsVisible = hasValue;
		}
	}

	// Removes specified key from selector list (item based only)
	public void RemoveItem( string key )
    {
		selector.RemoveItem( key );
    }

	/* Abstracts */

	// Insert in parent layout
	public override void Init()
	{
		HasClear = !HideClear && !IsRequired;

		AddControl( selector );

		// MUST be last
		UpdateClear();
	}

	// Returns underlying text value
	public override object GetObject()
	{
		bool objectMode = selector.HasObjects;
		object item = selector.SelectedItem;

		return (item == null) ? null : (objectMode ? item : (item as DXItem)?.Key);
	}

	// Placeholder only visible when not focused with no value
	public override void SetPlaceholder( bool focused )
	{
		selector.Placeholder = ((focused || HasValue()) ? (DXDevice.IsIOS ? null : string.Empty) : Title)!;
	}

	// Has value if selection has been made
	public override bool HasValue()
	{
		return (selector.HasItems && (selector.GetSelectedItem() != null)) ||
			   (selector.HasObjects && (selector.GetSelectedObject() != null));
	}

	// Only valid if optional or value selected
	public override bool IsValid()
	{
		return !IsVisible || IsDisabled || !IsRequired || HasValue();
	}

	/* Event Callbacks */

	// User opened dropdown, gain focus
	private void OnOpened( object sender, EventArgs args )
	{
		userOpened = true;

		OnFocus();
	}

	// User closed dropdown, either by selecting an item or tapping away
	private void OnClosed( object sender, EventArgs args )
	{
		OnUnfocus();

		// MUST be both here and OnSelectionChanged
		UpdateClear();
	}

	// Selection done with change made
	private void OnSelectionChanged( object sender, Syncfusion.Maui.Inputs.SelectionChangedEventArgs args )
	{
		// Internal population does not count as change
		if ( userOpened && HasValue() )
		{
			OnChange();
		}

		OnDone();
		userOpened = false;

        // MUST be both here and OnClosed
        UpdateClear();
	}

	// User tapped clear button
	protected override void OnClearTapped()
	{
		base.OnClearTapped();

		// Clear selected item/object
		if ( selector.HasItems )
		{
			SelectedItem = null;
		}
		else if ( selector.HasObjects )
		{
			SelectedObject = null;
		}

		OnChange();

		if ( DXDevice.IsAndroid )
		{
			OnUnfocus();
		}
	}
}

//
