// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/

using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using Microsoft.JSInterop;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Threading.Tasks;

namespace BootstrapBlazor.Components
{
    /// <summary>
    /// Select 组件实现类
    /// </summary>
    /// <typeparam name="TValue"></typeparam>
    public partial class Select<TValue> : ISelect
    {
        private ElementReference SelectElement { get; set; }

        private JSInterop<Select<TValue>>? Interop { get; set; }

        /// <summary>
        /// 
        /// </summary>
        [Inject]
        [NotNull]
        private SwalService? SwalService { get; set; }

        /// <summary>
        /// 获得 样式集合
        /// </summary>
        private string? ClassName => CssBuilder.Default("select dropdown")
            .AddClass("disabled", IsDisabled)
            .AddClassFromAttributes(AdditionalAttributes)
            .Build();

        /// <summary>
        /// 获得 样式集合
        /// </summary>
        private string? InputClassName => CssBuilder.Default("form-select")
            .AddClass($"border-{Color.ToDescriptionString()}", Color != Color.None && !IsDisabled && !IsValid.HasValue)
            .AddClass($"border-success", IsValid.HasValue && IsValid.Value)
            .AddClass($"border-danger", IsValid.HasValue && !IsValid.Value)
            .AddClass(CssClass).AddClass(ValidCss)
            .Build();

        /// <summary>
        /// 获得 样式集合
        /// </summary>
        private string? AppendClassName => CssBuilder.Default("form-select-append")
            .AddClass($"text-{Color.ToDescriptionString()}", Color != Color.None && !IsDisabled && !IsValid.HasValue)
            .AddClass($"text-success", IsValid.HasValue && IsValid.Value)
            .AddClass($"text-danger", IsValid.HasValue && !IsValid.Value)
            .Build();

        /// <summary>
        /// 设置当前项是否 Active 方法
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        private string? ActiveItem(SelectedItem item) => CssBuilder.Default("dropdown-item")
            .AddClass("active", () => item.Value == CurrentValueAsString)
            .AddClass("disabled", item.IsDisabled)
            .Build();

        /// <summary>
        /// Razor 文件中 Options 模板子项
        /// </summary>
        [NotNull]
        private List<SelectedItem>? Childs { get; set; }

        /// <summary>
        /// 获得/设置 搜索文本发生变化时回调此方法
        /// </summary>
        [Parameter]
        [NotNull]
        public Func<string, IEnumerable<SelectedItem>>? OnSearchTextChanged { get; set; }

        /// <summary>
        /// 获得/设置 是否显示搜索框 默认为 false 不显示
        /// </summary>
        [Parameter]
        public bool ShowSearch { get; set; }

        /// <summary>
        /// 获得 PlaceHolder 属性
        /// </summary>
        [Parameter]
        public string? PlaceHolder { get; set; }

        /// <summary>
        /// 获得/设置 选项模板支持静态数据
        /// </summary>
        [Parameter]
        public RenderFragment? Options { get; set; }

        [Inject]
        [NotNull]
        private IStringLocalizer<Select<TValue>>? Localizer { get; set; }

        [NotNull]
        private List<SelectedItem>? DataSource { get; set; }

        /// <summary>
        /// 获得 input 组件 Id 方法
        /// </summary>
        /// <returns></returns>
        protected override string? RetrieveId() => InputId;

        /// <summary>
        /// 获得/设置 Select 内部 Input 组件 Id
        /// </summary>
        private string? InputId => string.IsNullOrEmpty(Id) ? null : $"{Id}_input";

        /// <summary>
        /// 获得/设置 搜索文字
        /// </summary>
        private string SearchText { get; set; } = "";

        /// <summary>
        /// OnInitialized 方法
        /// </summary>
        protected override void OnInitialized()
        {
            base.OnInitialized();

            if (OnSearchTextChanged == null)
            {
                OnSearchTextChanged = text => Items.Where(i => i.Text.Contains(text, StringComparison.OrdinalIgnoreCase));
            }

            Items ??= Enumerable.Empty<SelectedItem>();
            Childs = new List<SelectedItem>();
        }

        /// <summary>
        /// OnParametersSet 方法
        /// </summary>
        protected override void OnParametersSet()
        {
            base.OnParametersSet();

            if (NullableUnderlyingType != null)
            {
                if (string.IsNullOrEmpty(PlaceHolder))
                {
                    // 设置 placeholder
                    if (AdditionalAttributes != null && AdditionalAttributes.TryGetValue("placeholder", out var pl))
                    {
                        PlaceHolder = pl?.ToString();
                        AdditionalAttributes.Remove("placeholder");
                    }
                }
                PlaceHolder ??= Localizer[nameof(PlaceHolder)];
            }

            // 内置对枚举类型的支持
            var t = NullableUnderlyingType ?? typeof(TValue);
            if (!Items.Any() && t.IsEnum())
            {
                var item = NullableUnderlyingType == null ? "" : PlaceHolder;
                Items = typeof(TValue).ToSelectList(string.IsNullOrEmpty(item) ? null : new SelectedItem("", item));
            }
        }

        private void ResetSelectedItem()
        {
            // 合并 Items 与 Options 集合
            if (!Items.Any() && typeof(TValue).IsEnum())
            {
                Items = typeof(TValue).ToSelectList();
            }

            if (string.IsNullOrEmpty(SearchText))
            {
                DataSource = Items.ToList();
                DataSource.AddRange(Childs);
            }
            else
            {
                DataSource = OnSearchTextChanged(SearchText).ToList();
            }

            SelectedItem = DataSource.FirstOrDefault(i => i.Value.Equals(CurrentValueAsString, StringComparison.OrdinalIgnoreCase))
                ?? DataSource.FirstOrDefault(i => i.Active)
                ?? DataSource.FirstOrDefault();
        }

        /// <summary>
        /// OnAfterRenderAsync 方法
        /// </summary>
        /// <param name="firstRender"></param>
        /// <returns></returns>
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            await base.OnAfterRenderAsync(firstRender);

            if (firstRender)
            {
                if (Interop == null)
                {
                    Interop = new JSInterop<Select<TValue>>(JSRuntime);
                }
                await Interop.InvokeVoidAsync(this, SelectElement, "bb_select", nameof(ConfirmSelectedItem));

                // 选项值不为 null 后者 string.Empty 时触发一次 OnSelectedItemChanged 回调
                if (SelectedItem != null && OnSelectedItemChanged != null && !string.IsNullOrEmpty(SelectedItem.Value))
                {
                    await OnSelectedItemChanged.Invoke(SelectedItem);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        [JSInvokable]
        public async Task ConfirmSelectedItem(int index)
        {
            var ds = string.IsNullOrEmpty(SearchText)
                ? DataSource
                : OnSearchTextChanged.Invoke(SearchText);
            var item = ds.ElementAt(index);
            await OnItemClick(item);
            StateHasChanged();
        }

        /// <summary>
        /// 下拉框选项点击时调用此方法
        /// </summary>
        private async Task OnItemClick(SelectedItem item)
        {
            if (!IsDisabled && !item.IsDisabled)
            {
                var ret = true;
                if (OnBeforeSelectedItemChange != null)
                {
                    ret = await OnBeforeSelectedItemChange(item);
                    if (ret)
                    {
                        // 返回 True 弹窗提示
                        var option = new SwalOption()
                        {
                            Category = SwalCategory,
                            Title = SwalTitle,
                            Content = SwalContent,
                            IsConfirm = true
                        };
                        if (!string.IsNullOrEmpty(SwalFooter))
                        {
                            option.ShowFooter = true;
                            option.FooterTemplate = builder => builder.AddContent(0, SwalFooter);
                        }
                        ret = await SwalService.ShowModal(option);
                    }
                    else
                    {
                        // 返回 False 直接运行
                        ret = true;
                    }
                }
                if (ret)
                {
                    await ItemChanged(item);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private async Task ItemChanged(SelectedItem item)
        {
            item.Active = true;
            SelectedItem = item;
            CurrentValueAsString = item.Value;

            // 触发 SelectedItemChanged 事件
            if (OnSelectedItemChanged != null)
            {
                await OnSelectedItemChanged.Invoke(SelectedItem);
            }
        }

        /// <summary>
        /// 添加静态下拉项方法
        /// </summary>
        /// <param name="item"></param>
        public void Add(SelectedItem item) => Childs.Add(item);
    }
}
