// Copyright © Selmo Technology GmbH. All Rights Reserved

using Microsoft.AspNetCore.Components;
using Novus.Connectivity.Common;
using SelmoStudio.Hmi.Plugin.Model.WellKnown;
using SelmoStudio.Hmi.Server.SelmoHmi.Group.Model.Ids;
using SelmoStudio.Hmi.Server.SelmoHmi.ManualControls.Components;
using SelmoStudio.Hmi.Server.SelmoHmi.Model.Dtos;
using SelmoStudio.Hmi.Server.SelmoHmi.Model.Ids;
using SelmoStudio.Hmi.Server.SelmoHmi.Parameter.Model.Dto;
using SelmoStudio.Hmi.Server.SelmoHmi.Plant.Model.Ids;
using SelmoStudio.Hmi.Server.SelmoHmi.Sequence.Model.Ids;
using SelmoStudio.Hmi.Server.SelmoHmi.Sequence.Parameters;
using SelmoStudio.Hmi.Server.SelmoHmi.Shared.Component;
using SelmoStudio.Hmi.Server.SelmoHmi.Shared.Service;
using SelmoStudio.Hmi.Server.SelmoHmi.Shared.WellKnownTypes;
using SelmoStudio.Hmi.Server.Shared.Resources;

namespace SelmoStudio.Hmi.Server.SelmoHmi.Sequence.Components
{
    public partial class SequenceControlGroupsComponent : IBaseProcessValueComponent, ISequenceParameterChangeNotifier
    {
        private bool _manualControlViewIsVisible;
        private bool _parameterViewIsVisible;

        private List<ParameterDto> _currentParams = new();
        private List<ZoneDto> _currentZones = new();

        private static GroupId _noExistingGroupSelected = new(new Guid("c464fb0b-3550-4cad-94b5-d3ff74c3dc88"));

        private GroupId _currentParamGroupId = _noExistingGroupSelected;
        private GroupId _currentZoneGroupId = _noExistingGroupSelected;

        [Inject]
        private IProjectService _projectService { get; set; }

        [Parameter]
        public SequenceId SequenceId { get; set; }

        [Parameter]
        public PlantId PlantId { get; set; }

        [Parameter]
        public HardwareZoneId HardwareZoneId { get; set; }

        [Parameter]
        public string Id { get; set; }

        [Parameter]
        public Dictionary<GroupId, string> UsedParameterGroups { get; set; } = new();

        [Parameter]
        public Dictionary<GroupId, string> UsedZonesGroups { get; set; } = new();

        [Parameter]
        public string Headline { get; set; }

        [Parameter]
        public bool ShowManualControls { get; set; }

        [Parameter]
        public bool ShowParameters { get; set; }

        [Parameter]
        public bool SingleViewMode { get; set; }

        [Parameter]
        public ContentInfoId? LastActiveContentInfoId { get; set; }

        [Parameter]
        public EventCallback<bool> BackToOverview { get; set; }

        [Parameter]
        public WellKnownParameterSource ParameterSource { get; set; }

        [Parameter]
        public EventCallback<SequenceParameterChangedEventArgs> OnParameterChanged { get; set; }

        #region Init/Lifecycle

        protected override async Task OnInitializedAsync()
        {
            _manualControlViewIsVisible = ShowManualControls;
            _parameterViewIsVisible = ShowParameters;

            InitGroups();
        }

        private bool _isRendered;

        public bool IsRendered
        {
            get
            {
                return _isRendered;
            }
        }

        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            if (firstRender)
            {
                AddSubComponents();
                SubscribeToAllSubPages();
            }
            await base.OnAfterRenderAsync(firstRender);
            _isRendered = true;
        }

        protected override Task OnParametersSetAsync()
        {
            HandleVisibleContentInfosView();
            AddSubComponents();
            SubscribeToAllSubPages();
            return base.OnParametersSetAsync();
        }

        #endregion Init/Lifecycle

        private void HandleVisibleContentInfosView()
        {
            if (SingleViewMode)
            {
                if (LastActiveContentInfoId == null)
                {
                    return;
                }

                if (LastActiveContentInfoId.Value.Guid.Equals(
                    WellKnownElementIds.SequenceContentComponent_ManualControlContentInfoId))
                {
                    _manualControlViewIsVisible = true;
                    _parameterViewIsVisible = false;
                }
                else if (LastActiveContentInfoId.Value.Guid.Equals(
                    WellKnownElementIds.SequenceContentComponent_ParameterContentInfoId))
                {
                    _manualControlViewIsVisible = false;
                    _parameterViewIsVisible = true;
                }
            }
            else
            {
                _manualControlViewIsVisible = ShowManualControls;
                _parameterViewIsVisible = ShowParameters;
            }
        }

        private string GetResponsiveClass()
        {
            return _manualControlViewIsVisible && _parameterViewIsVisible ? !SingleViewMode ?
                "col-sm-6" : "col-sm-12" : !SingleViewMode ? "col-sm-6" : "col-sm-12";
        }

        private string GetLeftVerticalSeparator()
        {
            return _parameterViewIsVisible && !SingleViewMode ?
                "left-vertical-separator" : "p-0";
        }

        public void InitGroups()
        {
            if (ParameterSource == WellKnownParameterSource.Sequence)
            {
                UsedParameterGroups = _projectService.GetUsedParameterGroups(PlantId, SequenceId);
                UsedZonesGroups = _projectService.GetUsedZonesGroups(PlantId, SequenceId);
            }
            else if (ParameterSource == WellKnownParameterSource.HardwareZone)
            {
                UsedParameterGroups = _projectService.GetUsedParameterGroups(PlantId, HardwareZoneId);
            }
            else if (ParameterSource == WellKnownParameterSource.Plant)
            {
                UsedParameterGroups = _projectService.GetUsedParameterGroups(PlantId);
            }
        }

        private async Task ChangeCurrentParamGroup(GroupId groupId)
        {
            _currentParamGroupId = groupId;
            GetCurrentParams();

            StateHasChanged();
            UpdateParameterChange();
        }

        private async Task ChangeCurrentZoneGroup(GroupId groupId)
        {
            _currentZoneGroupId = groupId;

            if (ParameterSource == WellKnownParameterSource.Sequence)
                _currentZones = _projectService.GetZones(PlantId, SequenceId, _currentZoneGroupId);

            StateHasChanged();
            UpdateParameterChange();
        }

        private void GetCurrentParams()
        {
            if (ParameterSource == WellKnownParameterSource.Sequence)
            {
                _currentParams = _projectService.GetParameters(PlantId, SequenceId, _currentParamGroupId);
            }
            else if (ParameterSource == WellKnownParameterSource.HardwareZone)
            {
                _currentParams = _projectService.GetParameters(PlantId, HardwareZoneId, _currentParamGroupId);
            }
            else if (ParameterSource == WellKnownParameterSource.Plant)
            {
                _currentParams = _projectService.GetParameters(PlantId, _currentParamGroupId);
            }
        }

        private async Task BackToParamGroups()
        {
            _currentParamGroupId = _noExistingGroupSelected;
        }

        private async Task BackToZoneGroups()
        {
            _currentZoneGroupId = _noExistingGroupSelected;
        }

        private async Task BackToOverviewClicked()
        {
            await BackToOverview.InvokeAsync(true);
        }

        private void UpdateParameterChange()
        {
            this.NotifyParameterChanged(nameof(ShowParameters), ShowParameters);
        }

        #region ComponentHandling

        private SequenceParameterComponent SequenceParameterComp;
        private ManualControlsComponent ManualControlsComp;

        private void AddSubComponents()
        {
            if (SubComponents != null)
                UnsubscribeToAllComponents();
            SubComponents = new();
            if (!_currentParamGroupId.Equals(_noExistingGroupSelected))
            {
                if (ShowParameters && SequenceParameterComp != null)
                    SubComponents.Add(SequenceParameterComp);
            }
            if (!_currentZoneGroupId.Equals(_noExistingGroupSelected))
            {
                if (ShowManualControls && ManualControlsComp != null)
                    SubComponents.Add(ManualControlsComp);
            }
        }

        private void SubscribeToAllSubPages()
        {
            foreach (var subComponent in SubComponents)
            {
                subComponent.ComponentChangeEvent += SubpageComponentEventTriggered;
            }
        }

        private List<IBaseProcessValueComponent> SubComponents = new();

        public event EventHandler<ComponentEventArgs> ComponentChangeEvent;

        public List<IProcessValueInfo> GetValueInfos()
        {
            var valueList = new List<IProcessValueInfo>();
            foreach (var subComponent in SubComponents)
            {
                if (subComponent.IsRendered)
                {
                    valueList.AddRange(subComponent.GetValueInfos());
                }
            }
            return valueList;
        }

        public void Update(IDictionary<ProcessValueId, IProcessValue> updatedValues)
        {
            if (!IsRendered)
                return;

            foreach (var subComponent in SubComponents)
            {
                if (subComponent.IsRendered)
                {
                    subComponent.Update(updatedValues);
                }
            }
        }

        private void UnsubscribeToAllComponents()
        {
            foreach (var subComponent in SubComponents)
            {
                subComponent.ComponentChangeEvent -= SubpageComponentEventTriggered;
            }
        }

        private void SubpageComponentEventTriggered(object? sender, ComponentEventArgs e)
        {
            ComponentChangeEvent?.Invoke(sender, e);
        }

        #endregion ComponentHandling

        private string GetParameterComponentHeadline()
        {
            var source = ParameterSource == WellKnownParameterSource.Plant ? HmiResource.PlantParameters
                : ParameterSource == WellKnownParameterSource.HardwareZone ? HmiResource.HardwareZoneParameters
                    : HmiResource.SequenceParameters;

            return $"{source} {HmiResource.Groups}";
        }

        private string GetManualControlsComponentHeadline()
        {
            return $"{HmiResource.ManualControls} {HmiResource.Groups}";
        }
    }
}