using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Data;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MarcusLaw.OutlookAddin.Core.Configuration;
using MarcusLaw.OutlookAddin.Core.Models;
using MarcusLaw.OutlookAddin.Core.Services;
using Serilog;

namespace MarcusLaw.OutlookAddin.UI.ViewModels
{
    public sealed partial class FileToCaseViewModel : ObservableObject
    {
        private readonly IEspoCrmClient _client;
        private readonly ILogger _logger;
        private CancellationTokenSource? _searchCts;

        [ObservableProperty]
        private string searchText = string.Empty;

        [ObservableProperty]
        private bool isBusy;

        [ObservableProperty]
        private EspoEntityRef? selectedTarget;

        [ObservableProperty]
        private string? senderEmail;

        [ObservableProperty]
        private string? senderName;

        [ObservableProperty]
        private string? statusMessage;

        public ObservableCollection<EspoEntityRef> Results { get; } = new ObservableCollection<EspoEntityRef>();

        public ObservableCollection<EspoEntityRef> RecentEntities { get; } = new ObservableCollection<EspoEntityRef>();

        public ICollectionView ResultsView { get; }

        public bool? DialogResult { get; private set; }

        public event EventHandler? RequestClose;

        public FileToCaseViewModel(IEspoCrmClient client, AppSettings settings, ILogger logger)
        {
            _client = client ?? throw new ArgumentNullException(nameof(client));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
            if (settings == null) throw new ArgumentNullException(nameof(settings));

            foreach (var r in settings.RecentEntities)
            {
                RecentEntities.Add(r);
            }

            ResultsView = CollectionViewSource.GetDefaultView(Results);
            ResultsView.GroupDescriptions.Add(new PropertyGroupDescription(nameof(EspoEntityRef.EntityType)));
        }

        partial void OnSearchTextChanged(string value)
        {
            _searchCts?.Cancel();
            _searchCts = new CancellationTokenSource();
            _ = SearchAsync(value, _searchCts.Token);
        }

        partial void OnSelectedTargetChanged(EspoEntityRef? value)
        {
            SubmitCommand.NotifyCanExecuteChanged();
        }

        partial void OnSenderEmailChanged(string? value)
        {
            CreateContactFromSenderCommand.NotifyCanExecuteChanged();
        }

        private async Task SearchAsync(string query, CancellationToken ct)
        {
            try
            {
                await Task.Delay(250, ct);

                var trimmed = (query ?? string.Empty).Trim();
                if (trimmed.Length < 2)
                {
                    Results.Clear();
                    StatusMessage = null;
                    return;
                }

                IsBusy = true;
                var result = await _client.GlobalSearchAsync(trimmed, ct);
                ct.ThrowIfCancellationRequested();

                Results.Clear();
                foreach (var r in result.List)
                {
                    Results.Add(r);
                }
                StatusMessage = $"נמצאו {result.Total} תוצאות";
            }
            catch (OperationCanceledException)
            {
            }
            catch (EspoCrmAuthorizationException)
            {
                StatusMessage = "מפתח ה-API נדחה — יש להזין מחדש";
            }
            catch (Exception ex)
            {
                _logger.Warning(ex, "GlobalSearch failed");
                StatusMessage = "שגיאת חיפוש: " + ex.Message;
            }
            finally
            {
                IsBusy = false;
            }
        }

        [RelayCommand(CanExecute = nameof(CanSubmit))]
        private void Submit()
        {
            DialogResult = true;
            RequestClose?.Invoke(this, EventArgs.Empty);
        }

        private bool CanSubmit() => SelectedTarget != null && !string.IsNullOrWhiteSpace(SelectedTarget.Id);

        [RelayCommand]
        private void Cancel()
        {
            DialogResult = false;
            RequestClose?.Invoke(this, EventArgs.Empty);
        }

        [RelayCommand(CanExecute = nameof(CanCreateContact))]
        private async Task CreateContactFromSenderAsync()
        {
            if (string.IsNullOrWhiteSpace(SenderEmail)) return;

            try
            {
                IsBusy = true;
                var name = !string.IsNullOrWhiteSpace(SenderName) ? SenderName! : SenderEmail!;
                var contact = await _client.CreateContactAsync(name, SenderEmail);
                var entry = new EspoEntityRef
                {
                    Id = contact.Id,
                    Name = contact.Name ?? name,
                    EntityType = "Contact"
                };
                Results.Insert(0, entry);
                SelectedTarget = entry;
                StatusMessage = "איש קשר נוצר: " + entry.Name;
            }
            catch (EspoCrmAuthorizationException)
            {
                StatusMessage = "מפתח ה-API נדחה — יש להזין מחדש";
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "CreateContact failed");
                StatusMessage = "יצירת איש קשר נכשלה: " + ex.Message;
            }
            finally
            {
                IsBusy = false;
            }
        }

        private bool CanCreateContact() => !string.IsNullOrWhiteSpace(SenderEmail);

        public FilingTarget? GetSelectedFilingTarget()
        {
            if (SelectedTarget == null || string.IsNullOrWhiteSpace(SelectedTarget.Id) ||
                string.IsNullOrWhiteSpace(SelectedTarget.EntityType))
            {
                return null;
            }
            return new FilingTarget(SelectedTarget.EntityType, SelectedTarget.Id, SelectedTarget.Name ?? string.Empty);
        }
    }
}
