using System.Collections.ObjectModel;
using LSFE.MobApp.Contracts;
using LSFE.MobApp.Entities.Doctor;
using LSFE.MobApp.Entities.Location;
using LSFE.MobApp.Entities.Planning;
using LSFE.MobApp.Helpers;
using LSFE.MobApp.Services;
using LSFE.MobApp.ViewModels.Common;
using Microsoft.Extensions.Configuration;
using System.Windows.Input;
using LSFE.MobApp.Views.CoveragePlan;
using System.ComponentModel;
using LSFE.MobApp.Pages.CoveragePlan;
using System.Runtime.CompilerServices;

namespace LSFE.MobApp.ViewModels.Coverage;

public class DoctorsVM : BaseDoctorVM
{
    #region Api client
    private readonly IApiClient<Doctor> _doctorApiClient;
    private readonly IApiClient<Institution> _institutionApiClient;
    #endregion

    #region Local repository
    private readonly Repository<Institution> _institutionRepository;
    private readonly Repository<MRRawPlan> _mrRawPlanRepository;
    #endregion

    #region ObservableCollection & List
    private ObservableCollection<DoctorVM> _doctors;
    private ObservableCollection<DoctorVM> _filteredDoctors;
    public ObservableCollection<DoctorVM> Doctors
    {
        get => _doctors;
        set
        {
            _doctors = value;
            OnPropertyChanged();
        }
    }
    public ObservableCollection<DoctorVM> FilteredDoctors
    {
        get => _filteredDoctors;
        set
        {
            _filteredDoctors = value;
            OnPropertyChanged();
            OnPropertyChanged(nameof(IsEmpty));
            OnPropertyChanged(nameof(ResultsCountText));
        }
    }
    private CancellationTokenSource _searchCancellationTokenSource;
    private List<Institution> _institutions;
    #endregion

    #region Service & configuration
    private readonly ISyncService _syncService;
    private readonly IConfiguration _configuration;
    private readonly INavigationService _navigationService;
    private readonly AddressService _addressService;
    #endregion
    public DoctorsVM(
    IApiClientFactory apiClientFactory,
    ISyncService syncService,
    INavigationService navigationService,
    Repository<Doctor> doctorRepository,
    Repository<Institution> institutionRepository,
    Repository<MRRawPlan> mrRawPlanRepository,
    IConfiguration configuration,
    AddressService addressService)
    : base(doctorRepository, syncService, addressService, configuration)
    {
        _doctorApiClient = apiClientFactory.CreateClient<Doctor>("DoctorMgmt/GetMyDoctor");
        _institutionApiClient = apiClientFactory.CreateClient<Institution>("Maintenance/institutions");
        _syncService = syncService;
        _configuration = configuration;
        _addressService = addressService;
        _navigationService = navigationService;
        _institutionRepository = institutionRepository;
        _mrRawPlanRepository= mrRawPlanRepository;

        Doctors = new ObservableCollection<DoctorVM>();
        FilteredDoctors = new ObservableCollection<DoctorVM>();
        _institutions = new List<Institution>();

        StatusFilterOptions = new List<string> { "All Statuses", "Pending", "Started", "Completed", "Reschedule", "Missed" };
        InstitutionFilterOptions = new List<string> { "All Institutions" };

        _searchText = string.Empty;
        _selectedStatusFilter = "All Statuses";
        _selectedInstitutionFilter = "All Institutions";

        // Commands
        AddDoctorCommand = new Command(async () => await AddDoctor(), () => CanInteract);
        ViewDoctorCommand = new Command<DoctorVM>(async (doctor) => await ViewDoctor(doctor), (doctor) => CanInteract);
        EditDoctorCommand = new Command<DoctorVM>(async (doctor) => await EditDoctor(doctor), (doctor) => CanInteract);
        DeleteDoctorCommand = new Command<DoctorVM>(async (doctor) => await DeleteDoctor(doctor), (doctor) => CanInteract);
        CoverageCommand = new Command<DoctorVM>(async (doctor) => await Coverage(doctor), (doctor) => CanInteract);
        SignOutCommand = new Command(async (doctor) => await LogOut());

        RescheduleCommand = new Command<DoctorVM>(async doctor =>
        {
            await ShowReason.ShowReasonModal("Reschedule Reason", async reason =>
            {
                await Reschedule(doctor.Doctor.DoctorId, reason);
            });
        }, doctor => CanInteract);

        MissedCommand = new Command<DoctorVM>(async doctor =>
        {
            await ShowReason.ShowReasonModal("Missed Reason", async reason =>
            {
                await Missed(doctor.Doctor.DoctorId, reason);
            });
        }, doctor => CanInteract);

        ClearSearchCommand = new Command(() => SearchText = string.Empty);
    }

    private async Task LogOut()
    {
       await _navigationService.NavigateToLoginPageAsync();
    }
    #region Properties
    private bool _forAddressTranslation { get; set; }
    private string _searchText;
    private bool _isLoading;
    private bool _isRefreshing;
    private string _selectedStatusFilter = "All Statuses";
    private string _selectedInstitutionFilter = "All Institutions";
    private List<string> _institutionFilterOptions;

    public List<string> InstitutionFilterOptions
    {
        get => _institutionFilterOptions;
        set
        {
            _institutionFilterOptions = value;
            OnPropertyChanged();
        }
    }

    public string SelectedInstitutionFilter
    {
        get => _selectedInstitutionFilter;
        set
        {
            _selectedInstitutionFilter = value;
            OnPropertyChanged();
            ApplyFilters();
        }
    }

    private bool _isProcessing;
    public bool CanInteract => !IsLoading && !IsProcessing;
    public bool IsProcessing
    {
        get => _isProcessing;
        set
        {
            _isProcessing = value;
            OnPropertyChanged();
            OnPropertyChanged(nameof(CanInteract));
        }
    }

    private bool _isFiltering;
    public bool IsFiltering
    {
        get => _isFiltering;
        set
        {
            _isFiltering = value;
            OnPropertyChanged();
        }
    }
    public string SearchText
    {
        get => _searchText;
        set
        {
            _searchText = value;
            OnPropertyChanged();
            OnPropertyChanged(nameof(HasSearchText));

            _searchCancellationTokenSource?.Cancel();
            _searchCancellationTokenSource = new CancellationTokenSource();

            var token = _searchCancellationTokenSource.Token;
            Task.Run(async () =>
            {
                await Task.Delay(300, token);
                if (!token.IsCancellationRequested)
                {
                    MainThread.BeginInvokeOnMainThread(() => ApplyFilters());
                }
            }, token);
        }
    }
    public bool HasSearchText => !string.IsNullOrWhiteSpace(SearchText);
    public string SelectedStatusFilter
    {
        get => _selectedStatusFilter;
        set
        {
            _selectedStatusFilter = value;
            OnPropertyChanged();
            ApplyFilters();
        }
    }

    public List<string> StatusFilterOptions { get; }

    public bool IsLoading
    {
        get => _isLoading;
        set
        {
            _isLoading = value;
            OnPropertyChanged();
        }
    }

    public bool IsEmpty => !IsLoading && (FilteredDoctors == null || FilteredDoctors.Count == 0);
    public string ResultsCountText => $"Showing {FilteredDoctors?.Count ?? 0} of {Doctors?.Count ?? 0} doctors";
    #endregion

    #region Status Update Handler (from Base Class)
    /// <summary>
    /// Automatically called when any doctor status is updated anywhere in the app
    /// </summary>
    protected override async void OnDoctorStatusUpdated(int doctorId)
    {
        var doctorVM = Doctors.FirstOrDefault(d => d.DoctorId == doctorId);
        if (doctorVM != null)
        {
            var updated = await RefreshDoctorFromRepositoryAsync(doctorId);
            if (updated != null)
            {
                doctorVM.Doctor.Status = updated.Status;
                doctorVM.RefreshStatus();
            }
        }
    }
    #endregion

    #region Commands
    public ICommand RescheduleCommand { get; }
    public ICommand MissedCommand { get; }
    public ICommand AddDoctorCommand { get; }
    public ICommand ViewDoctorCommand { get; }
    public ICommand EditDoctorCommand { get; }
    public ICommand DeleteDoctorCommand { get; }
    public ICommand ClearSearchCommand { get; }
    public ICommand CoverageCommand { get; }
    public ICommand SignOutCommand { get; }
    #endregion

    #region Status Update Methods
    private async Task UpdateDoctorAndPlanAsync(int doctorId, byte status, string reason)
    {
        var today = DateTime.Today;
        var tomorrow = today.AddDays(1);

        try
        {
            var (locationResult, isReadableAddress) = await _addressService.GetCurrentLocationAsync();

            var doctor = await _doctorRepository.FirstOrDefaultAsync(d => d.DoctorId == doctorId);
            if (doctor == null)
            {
                await Application.Current.MainPage.DisplayAlert("Error", "Doctor not found.", "OK");
                return;
            }

            doctor.Status = status;
            await _doctorRepository.UpdateAsync(doctor);

            var plan = await _mrRawPlanRepository.FirstOrDefaultAsync(
                p => p.DoctorId == doctorId &&
                     p.CallDate >= today &&
                     p.CallDate < tomorrow);

            if (plan == null)
            {
                await Application.Current.MainPage.DisplayAlert("Error", "No plan found for today.", "OK");
                return;
            }

            string successMessage;

            if (status == 3) // Reschedule
            {
                plan.IsReschedule = true;
                plan.IsMissed = false;
                plan.RescheduleReason = reason;
                plan.MissedReason = null;
                successMessage = "Schedule has been successfully rescheduled.";
            }
            else // Missed
            {
                plan.IsMissed = true;
                plan.IsReschedule = false;
                plan.MissedReason = reason;
                plan.RescheduleReason = null;
                successMessage = "Schedule has been marked as missed.";
            }
            if (isReadableAddress)
                _forAddressTranslation = false;
            else
                _forAddressTranslation = true;

            plan.Latitude = locationResult.Latitude.ToString() ?? "0";
            plan.Longitude = locationResult.Longitude.ToString() ?? "0";
            plan.Location = locationResult.Address ?? "N/A";

            await _mrRawPlanRepository.UpdateAsync(plan);

            // BROADCAST the status update to ALL ViewModels
            DoctorStatusHelper.BroadcastStatusUpdate(doctorId);

            await Application.Current.MainPage.DisplayAlert("Success", successMessage, "OK");
        }
        catch (Exception ex)
        {
            await Application.Current.MainPage.DisplayAlert("Error", ex.Message, "OK");
        }
    }

    private async Task Reschedule(int doctorId, string reason)
    {
        if (await IsCompleted())
            return;
        await UpdateDoctorAndPlanAsync(doctorId, status: 3, reason);
    }

    private async Task Missed(int doctorId, string reason)
    {
        if (await IsCompleted())
            return;
        await UpdateDoctorAndPlanAsync(doctorId, status: 4, reason);
    }

    private async Task<bool> IsCompleted()
    {
        if (FilteredDoctors[0].StatusText == "Completed")
        {
            await UtilityVM.ShowAlert("Status Update",
                $"Action failed: Dr. {Doctors[0].FullName}'s status is already marked as Completed.");
            return true;
        }
        return false;
    }
    public void RefreshData()
    {
        // Guard: skip if already loading or refreshing
        if (IsLoading || _isRefreshing) return;

        _isRefreshing = true;
        _ = LoadDataAsync();
    }
    #endregion

    #region Data Loading & Filtering
    private async Task LoadDataAsync()
    {
        try
        {
            IsLoading = true;

            _institutions = await _institutionRepository.GetAllAsync();

            if (_institutions != null && _institutions.Any())
            {
                InstitutionFilterOptions = new List<string> { "All Institutions" }
                    .Concat(_institutions.Select(i => i.InstitutionName)
                        .Where(n => !string.IsNullOrEmpty(n))
                        .OrderBy(n => n))
                    .ToList();
            }
            else
            {
                InstitutionFilterOptions = new List<string> { "All Institutions" };
            }

            var today = DateTime.Today;
            var tomorrow = today.AddDays(1);

            var doctors = await _doctorRepository.GetAllAsync();

            // FILTER → Only today's doctors
            var todayDoctors = doctors
                .Where(a => a.CreatedDate >= today && a.CreatedDate < tomorrow)
                .OrderByDescending(a => a.CreatedDate)
                .ToList();

            Doctors.Clear();

            // Load only today's doctors
            foreach (var doctor in todayDoctors)
            {
                var institution = _institutions?.FirstOrDefault(i => i.InstitutionId == doctor.InstitutionId);
                if (institution != null)
                {
                    doctor.InstitutionName = institution.InstitutionName;
                }

                Doctors.Add(new DoctorVM(doctor));
            }

            ApplyFilters();
        }
        catch (Exception ex)
        {
            await UtilityVM.ShowAlert("Error", $"Failed to load doctors: {ex.Message}");
        }
        finally
        {
            IsLoading = false;
            _isRefreshing = false;
        }
    }

    private async void ApplyFilters()
    {
        try
        {
            IsFiltering = true;

            var filtered = await Task.Run(() =>
            {
                var result = Doctors.AsEnumerable();

                if (!string.IsNullOrWhiteSpace(SearchText))
                {
                    var searchLower = SearchText.ToLower();
                    result = result.Where(d =>
                        d.FullName.ToLower().Contains(searchLower) ||
                        (d.EmailAddress?.ToLower().Contains(searchLower) ?? false) ||
                        (d.PhoneNo?.ToLower().Contains(searchLower) ?? false) ||
                        (d.LicenseNo?.ToLower().Contains(searchLower) ?? false) ||
                        (d.InstitutionName?.ToLower().Contains(searchLower) ?? false));
                }

                if (SelectedStatusFilter != "All Statuses")
                {
                    result = result.Where(d => d.StatusText == SelectedStatusFilter);
                }

                if (!string.IsNullOrEmpty(SelectedInstitutionFilter) && SelectedInstitutionFilter != "All Institutions")
                {
                    result = result.Where(d => d.InstitutionName == SelectedInstitutionFilter);
                }

                return result.ToList();
            });

            FilteredDoctors = new ObservableCollection<DoctorVM>(filtered);
        }
        finally
        {
            IsFiltering = false;
        }
    }
    #endregion

    #region CRUD Operations
    private async Task Coverage(DoctorVM doctor)
    {
        if (doctor == null || IsProcessing) return;
        var doctorEntities = new Entities.Doctor.Doctor()
        {
            Status=doctor.Status,
            FirstName=doctor.FullName,
            DoctorId = doctor.DoctorId,
            SpecializationName=doctor.Specialization,
            InstitutionName = doctor.InstitutionName,
            LicenseNo=doctor.LicenseNo,
            MaxVisit=doctor.MaxVisit,
            BirthDate=doctor.BirthDate,
            MRRawPlanId=doctor.MRRawPlanId
        };
        try
        {
            IsLoading = true;
            ((Command<DoctorVM>)CoverageCommand).ChangeCanExecute();

            var viewVm = new ActualCoverageVM(
                doctorEntities,
                _doctorRepository, 
                _mrRawPlanRepository,
                _syncService,
                _addressService,         
                _configuration);
            var viewPage = new ActualCoveragePage(viewVm);

            await Application.Current.MainPage.Navigation.PushAsync(viewPage);
        }
        catch (Exception ex)
        {
            await UtilityVM.ShowAlert("Error", $"Failed to view doctor: {ex.Message}");
        }
        finally
        {
            IsLoading = false;
            ((Command<DoctorVM>)CoverageCommand).ChangeCanExecute();
        }
    }
    private async Task AddDoctor()
    {
        if (IsProcessing) return; // Prevent double-tap

        try
        {
            IsProcessing = true;
            ((Command)AddDoctorCommand).ChangeCanExecute(); // Disable button

            var addVm = new AddEditDoctorVM(_doctorApiClient, _institutionApiClient, _institutions);
            var addPage = new AddEditDoctorPage(addVm);

            MessagingCenter.Subscribe<AddEditDoctorVM>(this, "DoctorSaved", async (sender) =>
            {
                await LoadDataAsync();
                MessagingCenter.Unsubscribe<AddEditDoctorVM>(this, "DoctorSaved");
            });

            //await _navigation.PushModalAsync(new NavigationPage(addPage));
            await Application.Current.MainPage.Navigation.PushModalAsync(new NavigationPage(addPage));

        }
        catch (Exception ex)
        {
            await UtilityVM.ShowAlert("Error", $"Failed to open add page: {ex.Message}");
        }
        finally
        {
            IsProcessing = false;
            ((Command)AddDoctorCommand).ChangeCanExecute(); // Re-enable button
        }
    }
    private async Task ViewDoctor(DoctorVM doctor)
    {
        if (doctor == null || IsProcessing) return;

        try
        {
            IsProcessing = true;
            ((Command<DoctorVM>)ViewDoctorCommand).ChangeCanExecute();

            var viewVm = new ViewDoctorVM(doctor.Doctor);
            var viewPage = new ViewDoctorPage(viewVm);
            await Application.Current.MainPage.Navigation.PushAsync(viewPage);
            // await _navigation.PushAsync(viewPage);
        }
        catch (Exception ex)
        {
            await UtilityVM.ShowAlert("Error", $"Failed to view doctor: {ex.Message}");
        }
        finally
        {
            IsProcessing = false;
            ((Command<DoctorVM>)ViewDoctorCommand).ChangeCanExecute();
        }
    }
    private async Task EditDoctor(DoctorVM doctor)
    {
        if (doctor == null || IsProcessing) return;

        try
        {
            IsProcessing = true;
            ((Command<DoctorVM>)EditDoctorCommand).ChangeCanExecute();

            var editVm = new AddEditDoctorVM(_doctorApiClient, _institutionApiClient, _institutions, doctor.Doctor);
            var editPage = new AddEditDoctorPage(editVm);

            MessagingCenter.Subscribe<AddEditDoctorVM>(this, "DoctorSaved", async (sender) =>
            {
                await LoadDataAsync();
                MessagingCenter.Unsubscribe<AddEditDoctorVM>(this, "DoctorSaved");
            });
            await Application.Current.MainPage.Navigation.PushAsync(editPage);
            //await _navigation.PushModalAsync(new NavigationPage(editPage));
        }
        catch (Exception ex)
        {
            await UtilityVM.ShowAlert("Error", $"Failed to edit doctor: {ex.Message}");
        }
        finally
        {
            IsProcessing = false;
            ((Command<DoctorVM>)EditDoctorCommand).ChangeCanExecute();
        }
    }
    private async Task DeleteDoctor(DoctorVM doctor)
    {
        if (doctor == null || IsProcessing) return;

        try
        {
            IsProcessing = true;
            ((Command<DoctorVM>)DeleteDoctorCommand).ChangeCanExecute();

            var confirm = await UtilityVM.ShowConfirm(
                "Confirm Delete",
                $"Are you sure you want to delete Dr. {doctor.FullName}?",
                "Delete",
                "Cancel");

            if (!confirm) return;

            var response = await _doctorApiClient.DeleteAsync(doctor.Doctor.Id);

            if (response.Success)
            {
                Doctors.Remove(doctor);
                ApplyFilters();
                await UtilityVM.ShowAlert("Success", "Doctor deleted successfully");
            }
            else
            {
                await UtilityVM.ShowAlert("Error", response.Message ?? "Failed to delete doctor");
            }
        }
        catch (Exception ex)
        {
            await UtilityVM.ShowAlert("Error", $"Failed to delete doctor: {ex.Message}");
        }
        finally
        {
            IsProcessing = false;
            ((Command<DoctorVM>)DeleteDoctorCommand).ChangeCanExecute();
        }
    }
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _searchCancellationTokenSource?.Cancel();
            _searchCancellationTokenSource?.Dispose();
        }
        base.Dispose(disposing);
    }
    #endregion
}
/// <summary>
/// Doctor View Model for UI binding - Now using centralized status helper
/// </summary>
public class DoctorVM : INotifyPropertyChanged
{
    public Entities.Doctor.Doctor Doctor { get; }

    public DoctorVM(Entities.Doctor.Doctor doctor)
    {
        Doctor = doctor ?? throw new ArgumentNullException(nameof(doctor));
    }

    #region Doctor Information
    public int DoctorId => Doctor.DoctorId;
    public Guid MRRawPlanId => Doctor.MRRawPlanId;
    public string FullName => $"Dr. {Doctor.FirstName} {Doctor.MiddleInitial} {Doctor.LastName}".Replace("  ", " ").Trim();
    public string EmailAddress => Doctor.EmailAddress ?? "N/A";
    public string PhoneNo => Doctor.PhoneNo ?? "N/A";
    public string LicenseNo => Doctor.LicenseNo ?? "N/A";
    public DateTime BirthDate => Doctor.BirthDate;
    public byte MaxVisit => Doctor.MaxVisit;
    public string Specialization => Doctor.SpecializationName ?? "General";
    public string InstitutionName => Doctor.InstitutionName ?? "No Institution";
    public bool HasInstitution => !string.IsNullOrEmpty(Doctor.InstitutionName);
    #endregion

    #region Status Changes
    public void UpdateDoctorModel(Entities.Doctor.Doctor updated)
    {
        if (updated == null) return;
        Doctor.Status = updated.Status;
        RefreshStatus();
    }

    public void RefreshStatus()
    {
        OnPropertyChanged(nameof(StatusText));
        OnPropertyChanged(nameof(StatusBackgroundColor));
        OnPropertyChanged(nameof(StatusTextColor));
    }
    #endregion

    #region Status Properties - Using Centralized Helper
    public string StatusText => DoctorStatusHelper.GetStatusText(Doctor.Status);
    public byte Status=> Doctor.Status;
    public Color StatusBackgroundColor => DoctorStatusHelper.GetStatusBackgroundColor(Doctor.Status);

    public Color StatusTextColor => DoctorStatusHelper.GetStatusTextColor(Doctor.Status);
    #endregion

    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion
}