using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections.ObjectModel;
using System.ComponentModel;
using VisionBuilder.UI.Common.Commands;
using VisionBuilder.UI.Common.Commands.Interfaces;
using VisionBuilder.UI.Common.Processing;
using VisionBuilder.UI.Common.Services;
using VisionBuilder.UI.Common.ViewModel;
using VisionBuilder.UI.Common.ViewModel.Classes;
using VisionBuilder.UI.Common.ViewModel.Interfaces.UI;

namespace VisionBuilder.UI.Common
{
    public partial class SingleCameraVM : ObservableObject, IEventHandler<ImageProcessedEvent>
    {
        public SynchronizationContext? SynchronizationContext { get; set; }

        private readonly UIConfiguration _uiConfiguration;
        private readonly IRecipeSelectionDialogService _recipeSelectionDialogService;
        private readonly IRecognitionControl _recognitionControl;

        public ErrorsVM ErrorsVm { get; private set; }
        public StatisticsVM StatisticsVm { get; private set; }
        public PreviewVM PreviewVm { get; private set; }

        public ObservableCollection<ButtonDefinition> DynamicButtons { get; } = new();

        public void AddButton(ButtonDefinition button)
        {
            DynamicButtons.Add(button);
        }

        public void SetButtonVisibility(string key, bool isVisible)
        {
            var button = DynamicButtons.FirstOrDefault(b => b.Key == key);
            if (button != null)
                button.IsVisible = isVisible;
        }

        public void RemoveButton(string key)
        {
            var button = DynamicButtons.FirstOrDefault(b => b.Key == key);
            if (button != null)
                DynamicButtons.Remove(button);
        }

        [ObservableProperty]
        private string _currentRecipeName = "Select recipe";

        [ObservableProperty]
        [NotifyPropertyChangedFor(nameof(CanStart))]
        [NotifyPropertyChangedFor(nameof(CanStop))]
        [NotifyPropertyChangedFor(nameof(CanPause))]
        [NotifyPropertyChangedFor(nameof(CanResume))]
        [NotifyPropertyChangedFor(nameof(CanHotReload))]
        [NotifyCanExecuteChangedFor(nameof(SelectRecipeCommand))]
        [NotifyCanExecuteChangedFor(nameof(StartCommand))]
        [NotifyCanExecuteChangedFor(nameof(StopCommand))]
        [NotifyCanExecuteChangedFor(nameof(HotReloadCommand))]
        private bool _isRunning;
        
        [ObservableProperty]
        [NotifyPropertyChangedFor(nameof(CameraLabelAndStatus))]
        private string _cameraLabel;

        public string CameraLabelAndStatus=>
            $"{CameraLabel}{(IsPaused ? "(PAUSED)" : "")}";

        [ObservableProperty]
        [NotifyPropertyChangedFor(nameof(CameraLabelAndStatus))]
        [NotifyPropertyChangedFor(nameof(IsResumed))]
        [NotifyPropertyChangedFor(nameof(CanPause))]
        [NotifyPropertyChangedFor(nameof(CanResume))]
        [NotifyCanExecuteChangedFor(nameof(ResumeCommand))]
        [NotifyCanExecuteChangedFor(nameof(PauseCommand))]
        private bool _isPaused;

        public bool IsResumed => !IsPaused;

        [ObservableProperty]
        [NotifyPropertyChangedFor(nameof(CanHotReload))]
        [NotifyCanExecuteChangedFor(nameof(HotReloadCommand))]
        private bool _isHotReloadAvailable;

        public bool CanHotReload => IsRunning && IsHotReloadAvailable;

        public bool CanStop => IsRunning;
        public bool CanStart => !IsRunning && SelectedRecipe!=null;
        public bool CanPause => (IsRunning && !IsPaused)&&_uiConfiguration.ShowPauseButton;
        public bool CanResume => (IsRunning && IsPaused) && _uiConfiguration.ShowPauseButton;
        
        

        public bool IsNotRunning => !IsRunning;
        private bool _handlingEnabled = true;

        public bool RecipeSelected => SelectedRecipe != null;
        public bool RecipeNotSelected => SelectedRecipe == null;


        [ObservableProperty]
        [NotifyPropertyChangedFor(nameof(CanStop))]
        [NotifyPropertyChangedFor(nameof(CanStart))]
        [NotifyCanExecuteChangedFor(nameof(SelectRecipeCommand))]
        [NotifyCanExecuteChangedFor(nameof(StartCommand))]
        [NotifyCanExecuteChangedFor(nameof(StopCommand))]
        [NotifyCanExecuteChangedFor(nameof(ResumeCommand))]
        [NotifyCanExecuteChangedFor(nameof(PauseCommand))]
        [NotifyPropertyChangedFor(nameof(RecipeSelected))]
        [NotifyPropertyChangedFor(nameof(RecipeNotSelected))]
        private RecipeData? _selectedRecipe;

        

        public SingleCameraVM(CameraSettings cameraSettings, UIConfiguration uiConfiguration, IRecipeSelectionDialogService recipeSelectionDialogService, IRecognitionControl recognitionControl, IImagePreviewService imagePreviewService, ILearningTool learningTool, IPasswordInputService passwordInputService)
        {
            _uiConfiguration = uiConfiguration;
            _recipeSelectionDialogService = recipeSelectionDialogService;
            
            _recognitionControl = recognitionControl;
            ErrorsVm = new ErrorsVM(uiConfiguration, imagePreviewService, learningTool, passwordInputService);
            StatisticsVm = new StatisticsVM();
            PreviewVm = new PreviewVM();

            CameraLabel = cameraSettings.CameraLabel;
            
            recognitionControl.ImageProcessed += Handle;

            recognitionControl.SessionStarted += StatisticsVm.Handle;
            recognitionControl.SessionStarted += ErrorsVm.Handle;

            recognitionControl.RecipeFileChanged += () =>
                SynchronizationContext?.Post(_ => IsHotReloadAvailable = true, null);

            
        }

       

        [RelayCommand(CanExecute = nameof(IsNotRunning))]
        public async Task SelectRecipe()
        {
            var vm = GetRecipeSelectionVm();
            if (!await _recipeSelectionDialogService.SelectRecipeAsync(vm))return;
            ProcessRecipeSelectionVm(vm);
        }

        public RecipeSelectionVM GetRecipeSelectionVm()
        {
            var vm= new RecipeSelectionVM();
            vm.Recipes = new ObservableCollection<RecipeData>(_recognitionControl.GetRecipesData());
            vm.SelectedRecipe = SelectedRecipe;
            return vm;
        }

        public void ProcessRecipeSelectionVm(RecipeSelectionVM vm)
        {
            if(!SelectRecipeCommand.CanExecute(null))return;
            SelectedRecipe = vm.SelectedRecipe;
            _recognitionControl.SetRecipe(SelectedRecipe!);
            CurrentRecipeName = SelectedRecipe?.RecipeName ?? "Select recipe";
        }

        

        [RelayCommand(CanExecute = nameof(CanStart))]
        public async Task Start()
        {
            
                IsRunning = true;
                await Task.Run(() => { _recognitionControl.Start(); });
                _handlingEnabled = true;
            
        }

        [RelayCommand(CanExecute = nameof(CanStop))]
        public async Task Stop()
        {
            _handlingEnabled = false;
            await Task.Run(() =>
            {
                _recognitionControl.Stop();
            });
            IsPaused = false;
            IsRunning = false;
            IsHotReloadAvailable = false;
        }

        [RelayCommand(CanExecute = nameof(CanHotReload))]
        public void HotReload()
        {
            _recognitionControl.HotReload();
            IsHotReloadAvailable = false;
        }

        [RelayCommand]
        public void Pause()
        {
            _recognitionControl.Pause();
            IsPaused = true;
        }

        [RelayCommand]
        public void Resume()
        {
            _recognitionControl.Resume();
            IsPaused = false;
        }




        public void Handle(ImageProcessedEvent @event)
        {
            if (!_handlingEnabled) return;
            try
            {
                PreviewVm.Handle(@event);
                StatisticsVm.Handle(@event);
                ErrorsVm.Handle(@event);
            }
            catch(Exception e)
            {

            }
        }
    }
}
