@using System.Threading
@using AyCode.Blazor.Components.Components.Grids
@using AyCode.Core.Helpers
@using AyCode.Core.Loggers
@using AyCode.Utils.Extensions
@using DevExpress.Internal.About
@using FruitBank.Common
@using FruitBank.Common.Dtos
@using FruitBank.Common.Models
@using FruitBankHybrid.Shared.Components.Grids.GenericAttributes
@using FruitBankHybrid.Shared.Components.Grids.Products
@using FruitBankHybrid.Shared.Databases
@using FruitBankHybrid.Shared.Services.Loggers
@using FruitBankHybrid.Shared.Services.SignalRs

@inject LoggedInModel LoggedInModel;
@inject IEnumerable<IAcLogWriterClientBase> LogWriters
@inject FruitBankSignalRClient FruitBankSignalRClient

<MgGridWithInfoPanel ShowInfoPanel="@IsMasterGrid">
	<GridContent>
		<GridProductDto @ref="Grid" DataSource="ProductDtos" CssClass="@GridCss" AutoSaveLayoutName="GridProductDtoTemplate"
						Logger="_logger" SignalRClient="FruitBankSignalRClient" Caption="Termék(ek)">
			<Columns>
				<MgGridDataColumn FieldName="Id" SortIndex="0" SortOrder="GridColumnSortOrder.Ascending"
								  UrlLink=@(FruitBankConstClient.BaseUrl + "/Admin/Product/Edit/{Id}") />
				<DxGridDataColumn FieldName="Name" />
				<DxGridDataColumn FieldName="Price" />
				<DxGridDataColumn FieldName="AvailableQuantity" ReadOnly="true" />
				<DxGridDataColumn FieldName="StockQuantity" />
				<DxGridDataColumn FieldName="IncomingQuantity" ReadOnly="true" />
				<DxGridDataColumn FieldName="NetWeight" ReadOnly="true" />
				<DxGridDataColumn FieldName="IsMeasurable" />
				<DxGridDataColumn FieldName="Tare" Caption="Tára súly" ReadOnly="true" />
				<DxGridDataColumn FieldName="AverageWeight" ReadOnly="true" />
				<DxGridDataColumn FieldName="AverageWeightTreshold" ReadOnly="true" />
				<DxGridCommandColumn Visible="!IsMasterGrid" Width="120"></DxGridCommandColumn>
			</Columns>
			<DetailRowTemplate>
				@if (IsMasterGrid)
				{
					var productDto = ((ProductDto)(context.DataItem));
					var productId = productDto.Id;


					<DxTabs ActiveTabIndexChanged="(i) => OnActiveTabChanged(i, productId)">
						<DxTabPage Text="Készlet mennyiség változások" Visible="@LoggedInModel.IsAdministrator">
							@{
								var contextIds = new[] { (object)productDto.Id };
								<GridStockQuantityHistoryDtoTemplate ContextIds="@(contextIds)" ParentDataItem="@productDto" />
							}
						</DxTabPage>
						<DxTabPage Text="Rendelések melyben megtalálható" Visible="@LoggedInModel.IsAdministrator">
							@{
								//GetOrderDtosFromDbAsync(productId).Forget();
								//var orderDtos = _orderDtos?.Where(o => o.OrderItemDtos.Any(oi => oi.ProductId == productId)).ToList() ?? [];
								<GridDetailOrderDto OrderDtos="_currentOrderDtos" IsMasterGrid="false"></GridDetailOrderDto>
							}
						</DxTabPage>
						<DxTabPage Text="Rendelés tételek" Visible="@LoggedInModel.IsAdministrator">
							@{
								//GetOrderItemDtosFromDbAsync(productId).Forget();
								//var orderItemDtos = _orderItemDtos?.Where(oi => oi.ProductId == productId).ToList() ?? [];
								<GridDetailOrderItemDto OrderItemDtos="_currentOrderItemDtos" IsMasterGrid="false" />
							}
						</DxTabPage>
						<DxTabPage Text="Speciális jellemzők" Visible="@LoggedInModel.IsDeveloper">
							@{
								var genericAttributeDtos = new AcObservableCollection<GenericAttributeDto>(productDto.GenericAttributes);
								<GridGenericAttribute ParentDataItem="@productDto" GenericAttributes="@genericAttributeDtos" />
							}
						</DxTabPage>
					</DxTabs>
				}
			</DetailRowTemplate>
			<ToolbarTemplate>
				@if (IsMasterGrid)
				{
					<MgGridToolbarTemplate Grid="Grid" OnReloadDataClick="() => ReloadDataFromDb(true)" />
				}
			</ToolbarTemplate>
		</GridProductDto>
	</GridContent>
</MgGridWithInfoPanel>

@code {
	[Inject] public required DatabaseClient Database { get; set; }

	private LoggerClient<GridShippingDocument> _logger = null!;

	string GridCss => !IsMasterGrid ? "hide-toolbar" : string.Empty;

	private int _activeTabIndex;

	private List<OrderDto>? _currentOrderDtos;
	private List<OrderItemDto>? _currentOrderItemDtos;

	private readonly SemaphoreSlim _lockOrderDtosByProductId = new(1);
	private readonly SemaphoreSlim _lockOrderItemDtosByProductId = new(1);

	private readonly Dictionary<int, List<OrderDto>> _orderDtosByProductId = new();
	private readonly Dictionary<int, List<OrderItemDto>> _orderItemDtosByProductId = new();

	public GridProductDto Grid { get; set; }

	[Parameter] public bool IsMasterGrid { get; set; } = false;

	[Parameter] public AcObservableCollection<ProductDto>? ProductDtos { get; set; }
	//[Parameter] public List<OrderDto>? OrderDtos { get; set; }
	//[Parameter] public List<OrderItemDto>? OrderItemDtos { get; set; }

	protected override async Task OnInitializedAsync()
	{
		_logger = new LoggerClient<GridShippingDocument>(LogWriters.ToArray());
		// if (IsMasterGrid)
		// {
		// 	using (await ObjectLock.GetSemaphore<ProductDto>().UseWaitAsync())
		// 	{
		// 		ProductDtos ??= await Database.ProductDtoTable.LoadDataAsync(true);
		// 	}
		// 	//ProductDtos ??= await FruitBankSignalRClient.GetProductDtos();

		// 	// if (ProductDtos is { Count: > 0 })
		// 	// 	_currentOrderDtos = await GetOrderDtosFromDbAsync(ProductDtos[0].Id);
		// }

		await ReloadDataFromDb(false);
	}

	public async Task ReloadDataFromDb(bool forceReload)
	{
		if (!IsMasterGrid) return;

		LoadingPanelVisibility.Visible = true;
		//using (await ObjectLock.GetSemaphore<ProductDto>().UseWaitAsync())
		{
			if (ProductDtos == null || !ProductDtos.Any() || forceReload)
				ProductDtos = new AcObservableCollection<ProductDto>(await Database.ProductDtoTable.LoadDataAsync(!forceReload));
		}

		_orderDtosByProductId.Clear();
		_orderItemDtosByProductId.Clear();

		// if (forceReload)
		// 	Grid?.Reload();

		LoadingPanelVisibility.Visible = false;
	}

	private async Task<List<OrderDto>> GetOrderDtosFromDbAsync(int productId)
	{
		using (await _lockOrderDtosByProductId.UseWaitAsync())
		{
			if (_orderDtosByProductId.TryGetValue(productId, out var orderDtos)) return orderDtos;

			orderDtos = await FruitBankSignalRClient.GetAllOrderDtoByProductId(productId) ?? [];
			_orderDtosByProductId[productId] = orderDtos;

			return _currentOrderDtos = orderDtos;
		}
	}

	private async Task<List<OrderItemDto>> GetOrderItemDtosFromDbAsync(int productId)
	{
		using (await _lockOrderItemDtosByProductId.UseWaitAsync())
		{
			if (_orderItemDtosByProductId.TryGetValue(productId, out var orderItemDtos)) return orderItemDtos;

			orderItemDtos = await FruitBankSignalRClient.GetAllOrderItemDtoByProductId(productId) ?? [];
			_orderItemDtosByProductId[productId] = orderItemDtos;

			return _currentOrderItemDtos = orderItemDtos;
		}
	}

	protected async Task OnFocusedRowChanged(GridFocusedRowChangedEventArgs e)
	{
		if (!LoggedInModel.IsAdministrator) return;

		var productDto = (ProductDto)e.DataItem;

		// if (e.Grid.IsDetailRowExpanded(e.VisibleIndex))
		// {
		// 	_currentOrderDtos = null;
		// 	_currentOrderDtos = productDto != null ? await GetOrderDtosFromDbAsync(productDto.Id) : [];
		// }
	}

	protected async Task OnActiveTabChanged(int activeTabIndex, int productId)
	{
		_activeTabIndex = activeTabIndex;

		switch (_activeTabIndex)
		{
			case 1:
				_currentOrderDtos = null;
				_currentOrderDtos = await GetOrderDtosFromDbAsync(productId);
				break;
			case 2:
				_currentOrderItemDtos = null;
				_currentOrderItemDtos = await GetOrderItemDtosFromDbAsync(productId);
				break;
		}
	}
}