using DataLayer;
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Windows.Forms;

namespace LibationWinForms.GridView;

public partial class MyRatingCellEditor : UserControl, IDataGridViewEditingControl
{
	private const string SOLID_STAR = "★";
	private const string HOLLOW_STAR = "☆";

	public Rating Rating
	{
		get => field;
		set
		{
			field = value;
			int rating = 0;
			foreach (NoBorderLabel star in panelOverall.Controls)
				star.Tag = star.Text = field.OverallRating > rating++ ? SOLID_STAR : HOLLOW_STAR;

			rating = 0;
			foreach (NoBorderLabel star in panelPerform.Controls)
				star.Tag = star.Text = field.PerformanceRating > rating++ ? SOLID_STAR : HOLLOW_STAR;

			rating = 0;
			foreach (NoBorderLabel star in panelStory.Controls)
				star.Tag = star.Text = field.StoryRating > rating++ ? SOLID_STAR : HOLLOW_STAR;
		}
	}

	public MyRatingCellEditor()
	{
		InitializeComponent();
		Rating = new Rating(0, 0, 0);
		this.FontChanged += MyRatingCellEditor_FontChanged;
	}

	private void MyRatingCellEditor_FontChanged(object? sender, EventArgs e)
	{
		var scale = Font.Size / 9;
		Scale(new SizeF(scale, scale));
	}

	private void Star_MouseEnter(object sender, EventArgs e)
	{
		var thisTbox = sender as NoBorderLabel;
		if (thisTbox?.Parent is not Panel panel)
			return;
		var star = SOLID_STAR;

		foreach (NoBorderLabel child in panel.Controls)
		{
			child.Text = star;
			if (child == thisTbox) star = HOLLOW_STAR;
		}
	}

	private void Star_MouseLeave(object sender, EventArgs e)
	{
		var thisTbox = sender as NoBorderLabel;
		if (thisTbox?.Parent is not Panel panel)
			return;

		//Artifically shrink rectangle to guarantee mouse is outside when exiting from the left (negative X)
		var clientPt = panel.PointToClient(MousePosition);
		var rect = new Rectangle(0, 0, panel.ClientRectangle.Width - 2, panel.ClientRectangle.Height);
		if (!rect.Contains(clientPt.X - 2, clientPt.Y))
		{
			//Restore defaults
			foreach (NoBorderLabel child in panel.Controls)
				child.Text = child.Tag as string;
		}
	}

	private void Star_MouseClick(object sender, MouseEventArgs e)
	{
		var overall = Rating.OverallRating;
		var perform = Rating.PerformanceRating;
		var story = Rating.StoryRating;

		var thisTbox = sender as NoBorderLabel;
		if (thisTbox?.Parent is not Panel panel)
			return;

		int newRatingValue = 0;
		foreach (var child in panel.Controls)
		{
			newRatingValue++;
			if (child == thisTbox) break;
		}

		if (panel == panelOverall)
			overall = newRatingValue;
		else if (panel == panelPerform)
			perform = newRatingValue;
		else if (panel == panelStory)
			story = newRatingValue;

		if (overall + perform + story == 0f) return;

		var newRating = new Rating(overall, perform, story);

		if (newRating == Rating) return;

		Rating = newRating;
		EditingControlValueChanged = true;
		EditingControlDataGridView?.NotifyCurrentCellDirty(true);
	}

	protected override void OnKeyDown(KeyEventArgs e)
	{
		if (e.KeyCode == Keys.Escape && EditingControlDataGridView is not null)
		{
			EditingControlDataGridView.RefreshEdit();
			EditingControlDataGridView.CancelEdit();
			EditingControlDataGridView.CurrentCell?.DetachEditingControl();
			EditingControlDataGridView.CurrentCell = null;

		}
		base.OnKeyDown(e);
	}

	#region IDataGridViewEditingControl

	public DataGridView? EditingControlDataGridView { get; set; }
	public int EditingControlRowIndex { get; set; }
	public bool EditingControlValueChanged { get; set; }
	[AllowNull]
	public object EditingControlFormattedValue { get => Rating; set { } }
	public Cursor EditingPanelCursor => Cursor;
	public bool RepositionEditingControlOnValueChange => false;

	public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
	{
		Font = dataGridViewCellStyle.Font;
		ForeColor = dataGridViewCellStyle.ForeColor;
		BackColor = dataGridViewCellStyle.BackColor;
	}

	public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey) => keyData == Keys.Escape;
	public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) => EditingControlFormattedValue;
	public void PrepareEditingControlForEdit(bool selectAll) { }

	#endregion
}

public class NoBorderLabel : Panel
{
	private string? _text;
	[Description("Label text"), Category("Data")]
	[Browsable(true)]
	[EditorBrowsable(EditorBrowsableState.Always)]
	[AllowNull]
	public override string Text
	{
		get => _text ?? string.Empty;
		set
		{
			_text = value;
			Invalidate();
		}
	}

	[Description("X and Y offset for text drawing position. May be negative."), Category("Layout")]
	[Browsable(true)]
	[EditorBrowsable(EditorBrowsableState.Always)]
	public Point LabelOffset { get; set; }
	protected override void OnPaint(PaintEventArgs e)
	{
		TextRenderer.DrawText(e, Text, this.Font, LabelOffset, this.ForeColor);
		base.OnPaint(e);
	}
}
