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

namespace MarcusLaw.OutlookAddin.UI.ViewModels
{
    /// <summary>
    /// Picks a single Case via the EspoCRM GlobalSearch API. Returns the
    /// chosen <see cref="EspoEntityRef"/> so the host can fetch full details
    /// (contacts, account, etc.) and populate the open MailItem.
    /// </summary>
    public sealed partial class ComposeFromCaseViewModel : ObservableObject
    {
        private readonly IEspoCrmClient _client;
        private readonly ILogger _logger;
        private CancellationTokenSource? _searchCts;

        [ObservableProperty]
        private string searchText = string.Empty;

        [ObservableProperty]
        private CaseEntity? selectedCase;

        [ObservableProperty]
        private string? statusMessage;

        public ObservableCollection<CaseEntity> Cases { get; } = new ObservableCollection<CaseEntity>();

        public EspoEntityRef? Result { get; private set; }

        public bool? DialogResult { get; private set; }

        public event EventHandler? RequestClose;

        public ComposeFromCaseViewModel(IEspoCrmClient client, ILogger logger)
        {
            _client = client ?? throw new ArgumentNullException(nameof(client));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

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

        partial void OnSelectedCaseChanged(CaseEntity? value)
        {
            SubmitCommand.NotifyCanExecuteChanged();
        }

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

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

                var search = await _client.GlobalSearchAsync(trimmed, ct).ConfigureAwait(true);
                ct.ThrowIfCancellationRequested();

                Cases.Clear();
                int kept = 0;
                foreach (var hit in search.List)
                {
                    if (!string.Equals(hit.EntityType, "Case", StringComparison.OrdinalIgnoreCase)) continue;
                    Cases.Add(new CaseEntity
                    {
                        Id = hit.Id,
                        Name = hit.Name,
                    });
                    kept++;
                }
                StatusMessage = kept == 0
                    ? "אין תוצאות מסוג תיק (Case)"
                    : $"נמצאו {kept} תיקים";
            }
            catch (OperationCanceledException) { /* superseded */ }
            catch (EspoCrmAuthorizationException)
            {
                StatusMessage = "מפתח ה-API נדחה — יש לעדכן בהגדרות";
            }
            catch (Exception ex)
            {
                _logger.Warning(ex, "ComposeFromCase search failed");
                StatusMessage = "שגיאת חיפוש: " + ex.Message;
            }
        }

        [RelayCommand(CanExecute = nameof(CanSubmit))]
        private void Submit()
        {
            if (SelectedCase == null) return;
            Result = new EspoEntityRef
            {
                Id = SelectedCase.Id,
                Name = SelectedCase.Name,
                EntityType = "Case"
            };
            DialogResult = true;
            RequestClose?.Invoke(this, EventArgs.Empty);
        }

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

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