using MediatR;
using Microsoft.AspNetCore.Components.Forms;
using Netina.Domain.Entities.Brands;

namespace Netina.AdminPanel.PWA.Dialogs;

public class FastProductCreateDialogBoxViewModel(ISnackbar snackbar, IRestWrapper restWrapper, IUserUtility userUtility, IDialogService dialogService, MudDialogInstance dialogInstance)
    : BaseViewModel<ProductLDto>(userUtility)
{
    public HashSet<ProductCategorySDto> Categories { get; set; } = new();
    public bool FormEnable = false;
    private ProductCategorySDto? _selectedCategory;
    public ProductCategorySDto? SelectedCategory
    {
        get => _selectedCategory;
        set
        {
            _selectedCategory = value;
            FormEnable = _selectedCategory != null;
        }
    }

    public BrandSDto? SelectedBrand { get; set; }
    public override async Task InitializeAsync()
    {
        var categories = await restWrapper.ProductCategoryRestApi.ReadAll(true);
        categories.ForEach(c => Categories.Add(c));
        PageDto.Stock = 10;
        await base.InitializeAsync();
    }

    public async Task<HashSet<ProductCategorySDto>> LoadCategories(ProductCategorySDto arg)
    {
        return arg.Children.ToHashSet();
    }

    private readonly List<IBrowserFile> Files = new();
    public readonly List<string> FileNames = new();
    private const string DefaultDragClass = "relative rounded-lg border-2 border-dashed pa-4 mt-4 mud-width-full mud-height-full z-10";
    public string DragClass = DefaultDragClass;
    public void SetDragClass()
        => DragClass = $"{DefaultDragClass} mud-border-primary";
    public void ClearDragClass()
        => DragClass = DefaultDragClass;

    public void OnInputFileChanged(InputFileChangeEventArgs e)
    {
        ClearDragClass();
        var files = e.GetMultipleFiles();
        foreach (var file in files)
        {
            FileNames.Add(file.Name);
            Files.Add(file);
        }


    }
    private List<BrandSDto> brands = new();
    public async Task<IEnumerable<BrandSDto>> SearchBrand(string brand)
    {
        try
        {
            if (brands.Count == 0)
                brands = await restWrapper.BrandRestApi.ReadAll();
            if (brand.IsNullOrEmpty().Not())
                return brands.Where(b => b.PersianName.Trim().ToUpper().Contains(brand.Trim().ToUpper()));
            return brands;
        }
        catch (ApiException ex)
        {
            var exe = await ex.GetContentAsAsync<ApiResult>();
            snackbar.Add(exe != null ? exe.Message : ex.Content, Severity.Error);
            return brands;
        }
        catch (Exception e)
        {
            snackbar.Add(e.Message, Severity.Error);
            return brands;
        }
    }

    public void AddBrand(string brandName)
    {
        if (brandName.IsNullOrEmpty())
            return;
        var brand = new BrandSDto { PersianName = brandName };
        brands.Add(brand);
        SelectedBrand = brand;
        Task.Run(async () =>
        {
            var token = await userUtility.GetBearerTokenAsync();
            if (token == null)
                return;
            var command = brand.Adapt<CreateBrandCommand>() with { Files = new() };
            var response = await restWrapper.CrudApiRest<Brand, Guid>(Address.BrandController)
                .Create(command, token);
            brand.Id = response;
            snackbar.Add($"افزودن برند {brand.PersianName} با موفقیت انجام شد");
        });
    }
    public void SubmitCreateProduct()
    {
        try
        {
            if (SelectedCategory == null)
                throw new Exception("دسته بندی انتخاب نشده است");
            if (SelectedBrand == null || SelectedBrand.Id == default)
                throw new Exception("برند انتخاب نشده است");
            if (PageDto.PersianName.IsNullOrEmpty())
                throw new Exception("نام فارسی را وارد کنید");
            var product = PageDto.Clone();
            var brand = SelectedBrand.Clone();
            var browserFiles = Files.ToList();
            var specifications = Specifications.ToList();
            Task.Run(async () =>
            {
                try
                {
                    var token = await userUtility.GetBearerTokenAsync();
                    if (token == null)
                        throw new Exception("Token is null");
                    var files = new List<StorageFileSDto>();
                    foreach (var file in browserFiles)
                    {
                        using var memoryStream = new MemoryStream();
                        var stream = file.OpenReadStream();
                        await stream.CopyToAsync(memoryStream);
                        var fileUpload = new FileUploadRequest
                        {
                            ContentType = file.ContentType,
                            FileName = file.Name,
                            FileUploadType = FileUploadType.Image,
                            StringBaseFile = Convert.ToBase64String(memoryStream.ToArray())
                        };
                        var rest = await restWrapper.FileRestApi.UploadFileAsync(fileUpload, token);
                        files.Add(new StorageFileSDto
                        {
                            FileLocation = rest.FileLocation,
                            FileName = rest.FileName,
                            FileType = StorageFileType.Image
                        });
                    }

                    product.Cost *= 10;
                    var command = new CreateProductCommand(product.PersianName, product.EnglishName, product.Summery,
                        product.ExpertCheck,
                        product.Tags,
                        product.Warranty,
                        true,
                        product.Cost,
                        product.PackingCost,
                        product.Stock,
                        product.HasExpressDelivery,
                        product.MaxOrderCount,
                        product.IsSpecialOffer,
                        brand.Id,
                        SelectedCategory.Id,
                        null,
                        specifications,
                        files,
                        new Dictionary<string, string>(),
                        new Dictionary<string, string>());
                    await restWrapper.CrudApiRest<Product, Guid>(Address.ProductController).Create<CreateProductCommand>(command, token);
                }
                catch (ApiException ex)
                {
                    if (ex.StatusCode != HttpStatusCode.OK)
                        snackbar.Add(ex.Message, Severity.Error);
                }
                catch (Exception e)
                {
                    snackbar.Add(e.Message, Severity.Error);
                }

            });
            PageDto = new ProductLDto { Stock = 10 };
            FileNames.Clear();
            //Specifications.Clear();
            Files.Clear();
        }
        catch (Exception e)
        {
            snackbar.Add(e.Message, Severity.Error);
        }
    }


    public string SpecificationTitle = string.Empty;
    public string SpecificationValue = string.Empty;
    public readonly ObservableCollection<SpecificationSDto> Specifications = new ObservableCollection<SpecificationSDto>();

    public void AddSpecification()
    {
        try
        {
            if (SpecificationTitle.IsNullOrEmpty())
                throw new AppException("عنوان ویژگی مورد نظر را وارد کنید");
            if (SpecificationValue.IsNullOrEmpty())
                throw new AppException("مقدار ویژگی مورد نظر را وارد کنید");
            Specifications.Add(new SpecificationSDto { Title = SpecificationTitle.ToString(), Value = SpecificationValue.ToString() });

            SpecificationTitle = string.Empty;
            SpecificationValue = string.Empty;
        }
        catch (Exception e)
        {
            snackbar.Add(e.Message, Severity.Error);
        }
    }

    public void RemoveSpecification(SpecificationSDto specification)
    {
        var spec = Specifications.FirstOrDefault(s => s.Value == specification.Value && s.Title == specification.Title);
        if (spec != null)
            Specifications.Remove(spec);
    }
}