using Eto.Mac.Forms.Controls;
using Eto.Shared;



namespace Eto.Mac.Forms.Cells
{
	public class CustomCellHandler : CellHandler<CustomCell, CustomCell.ICallback>, CustomCell.IHandler
	{
		public override void SetObjectValue(object dataItem, NSObject value)
		{
		}

		public override NSObject GetObjectValue(object dataItem)
		{
			return null;
		}

		Dictionary<string, Control> widthCells = new Dictionary<string, Eto.Forms.Control>();

		public override nfloat GetPreferredWidth(object value, CGSize cellSize, int row, object dataItem)
		{
			var column = -1;// TODO: lookup!
			var args = new MutableCellEventArgs(ColumnHandler?.DataViewHandler as Grid, Widget, row, column, dataItem, CellStates.None, null);
			var identifier = Callback.OnGetIdentifier(Widget, args) ?? string.Empty;
			Control widthCell;
			if (!widthCells.TryGetValue(identifier, out widthCell))
			{
				widthCell = Callback.OnCreateCell(Widget, args);
				if (widthCell == null)
					return Callback.OnGetPreferredWidth(Widget, args);
				widthCell.AttachNative();
				widthCells.Add(identifier, widthCell);
			}
			args.SetControl(widthCell);
			Callback.OnConfigureCell(Widget, args, widthCell);
			widthCell.GetMacControl()?.InvalidateMeasure();

			var result = widthCell.GetPreferredSize(SizeF.PositiveInfinity).Width;

			widthCell.DataContext = null;
			return result;
		}


		public class EtoCustomCellView : NSTableCellView
		{
			WeakReference _handler;
			public CustomCellHandler Handler
			{
				get => _handler?.Target as CustomCellHandler;
				set => _handler = new WeakReference(value);
			}

			public MutableCellEventArgs Args { get; set; }

			public Control EtoControl => Args.Control;

			public bool DrawsBackground { get; set; }

			public NSColor BackgroundColor { get; set; }

			public override void DrawRect(CGRect dirtyRect)
			{
				if (DrawsBackground && BackgroundColor != null && BackgroundColor.AlphaComponent > 0)
				{
					BackgroundColor.Set();
					NSGraphics.RectFill(Bounds);
				}
				base.DrawRect(dirtyRect);
			}

			static Color AlternateSelectedControlText = NSColor.AlternateSelectedControlText.ToEto();
			static Color ControlText = NSColor.ControlText.ToEto();

			public override NSBackgroundStyle BackgroundStyle
			{
				get { return base.BackgroundStyle; }
				set
				{
					base.BackgroundStyle = value;
					if (value == NSBackgroundStyle.Dark)
						Args.SetTextColor(AlternateSelectedControlText);
					else
						Args.SetTextColor(ControlText);
				}
			}

			public void Setup()
			{
				EtoControl.GotFocus += ControlGotFocus;
				EtoControl.LostFocus += ControlLostFocus;
			}

			bool losingFocus;

			private void ControlLostFocus(object sender, EventArgs e)
			{
				if (losingFocus)
					return;

				var h = Handler;
				if (h == null)
					return;

				losingFocus = true;
				var ee = MacConversions.CreateCellEventArgs(h.ColumnHandler.Widget, null, Args.Row, Args.Column, Args.Item);
				if (h.ColumnHandler.DataViewHandler?.IsCancellingEdit == false)
				{
					h.Callback.OnCommitEdit(h.Widget, Args);
					h.ColumnHandler.DataViewHandler?.OnCellEdited(ee);
				}
				else
				{
					h.Callback.OnCancelEdit(h.Widget, Args);
				}
				losingFocus = false;
			}

			private void ControlGotFocus(object sender, EventArgs e)
			{
				var h = Handler;
				if (h == null)
					return;
				h.Callback.OnBeginEdit(h.Widget, Args);
				var ee = MacConversions.CreateCellEventArgs(h.ColumnHandler.Widget, null, Args.Row, Args.Column, Args.Item);
				h.ColumnHandler.DataViewHandler?.OnCellEditing(ee);
			}

			public override void Layout()
			{
				base.Layout();
				var sv = Subviews;
				if (sv.Length > 0)
				{
					var view = sv[0];
					view.Frame = view.GetFrameForAlignmentRect(Bounds);
				}
			}

		}

		public override Color GetBackgroundColor(NSView view) => ((EtoCustomCellView)view).BackgroundColor.ToEto();

		public override void SetBackgroundColor(NSView view, Color color)
		{
			var field = ((EtoCustomCellView)view);
			field.BackgroundColor = color.ToNSUI();
			field.DrawsBackground = color.A > 0;
		}

		private void SetDefaults(EtoCustomCellView view)
		{
			view.DrawsBackground = false;
		}

		public override NSView GetViewForItem(NSTableView tableView, NSTableColumn tableColumn, int row, NSObject obj, Func<NSObject, int, object> getItem)
		{
			var item = getItem(obj, row);
			var state = CellStates.None;
			if (tableView.IsRowSelected(row))
				state |= CellStates.Selected;
			if (tableColumn.Editable)
				state |= CellStates.Editing;
			var column = -1; // TODO: get index or lookup when needed.
			var args = new MutableCellEventArgs(ColumnHandler.DataViewHandler as Grid, Widget, row, column, item, state, null);
			var identifier = tableColumn.Identifier;
			var id = Callback.OnGetIdentifier(Widget, args);
			if (!string.IsNullOrEmpty(id))
				identifier += "_" + id;

			var view = tableView.MakeView(identifier, tableView) as EtoCustomCellView;
			if (view == null)
			{
				var control = Callback.OnCreateCell(Widget, args);
				args.SetControl(control);

				view = new EtoCustomCellView
				{ 
					Handler = this,
					Args = args,
					Identifier = identifier,
					AutoresizingMask = NSViewResizingMask.HeightSizable | NSViewResizingMask.WidthSizable
				};
				if (control != null)
				{
					var childView = control.ToNative(true);
					view.AddSubview(childView);
					view.Setup();
				}
			}
			else
			{
				view.Args.SetEditable(args.IsEditing);
				view.Args.SetSelected(args.IsSelected);
				view.Args.SetItem(args.Item);
			}

			SetDefaults(view);
			var formatArgs = new MacCellFormatArgs(ColumnHandler.Widget, item, row, view);
			ColumnHandler.DataViewHandler.OnCellFormatting(formatArgs);
			Callback.OnConfigureCell(Widget, view.Args, view.EtoControl);
			return view;
		}

		public override void ViewRemoved(NSView view)
		{
			base.ViewRemoved(view);
			if (view is EtoCustomCellView etoView)
			{
				etoView.Args.SetItem(null);
				Callback.OnConfigureCell(Widget, etoView.Args, etoView.EtoControl);
			}
		}
	}
}

