using LSFE.MobApp.Contracts; using LSFE.MobApp.Entities.Doctor; using LSFE.MobApp.Entities.Planning; using LSFE.MobApp.Helpers; using LSFE.MobApp.Pages.CoveragePlan; using LSFE.MobApp.Services; using LSFE.MobApp.Services.Coverage; using LSFE.MobApp.ViewModels.Common; using Microsoft.Extensions.Configuration; using System.Collections.ObjectModel; using System.Windows.Input; namespace LSFE.MobApp.ViewModels.Coverage { public class ActualCoverageVM : BaseDoctorVM { private readonly Doctor _doctor; private bool _isLoading; private ObservableCollection _doctors; private readonly Repository _mrRawPlanRepository; public ActualCoverageVM( Doctor doctor, Repository doctorRepository, Repository mrRawPlanrepository, ISyncService syncService, AddressService addressService, IConfiguration configuration) : base(doctorRepository, syncService, addressService, configuration) { _doctor = doctor; _mrRawPlanRepository = mrRawPlanrepository; CloseCommand = new Command(async () => await Close()); CopyEmailCommand = new Command(async () => await CopyEmail()); CallPhoneCommand = new Command(async () => await CallPhone()); StartCoverageCommand = new Command(async () => await StartCoverage()); } #region Status Properties - Using Helper (DRY!) public string StatusText => DoctorStatusHelper.GetStatusText(_doctor.Status); public Color StatusBackgroundColor => DoctorStatusHelper.GetStatusBackgroundColor(_doctor.Status); public Color StatusTextColor => DoctorStatusHelper.GetStatusTextColor(_doctor.Status); #endregion /// /// This method is automatically called when status updates are broadcast /// protected override async void OnDoctorStatusUpdated(int doctorId) { // Only update if it's this doctor if (_doctor.DoctorId == doctorId) { var updated = await RefreshDoctorFromRepositoryAsync(doctorId); if (updated != null) { _doctor.Status = updated.Status; // Notify UI to refresh OnPropertyChanged(nameof(StatusText)); OnPropertyChanged(nameof(StatusBackgroundColor)); OnPropertyChanged(nameof(StatusTextColor)); } } } public ObservableCollection Doctors { get => _doctors; set { _doctors = value; OnPropertyChanged(); } } #region Details information 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 string Specialization => _doctor.SpecializationName ?? "General Practice"; public string InstitutionName => _doctor.InstitutionName ?? "No Institution Assigned"; public string Address => _doctor.Address ?? "No address provided"; public string MaxVisit => $"{_doctor.MaxVisit} doctors"; public string BirthDateFormatted => _doctor.BirthDate.ToString("MMMM dd, yyyy"); public string CreatedDateFormatted => _doctor.CreatedDate.ToString("MMMM dd, yyyy"); public bool HasInstitution => !string.IsNullOrEmpty(_doctor.InstitutionName); public bool HasAddress => !string.IsNullOrEmpty(_doctor.Address); #endregion public bool IsLoading { get => _isLoading; set { _isLoading = value; OnPropertyChanged(); } } #region Commands public ICommand StartCoverageCommand { get; } public ICommand CloseCommand { get; } public ICommand CopyEmailCommand { get; } public ICommand CallPhoneCommand { get; } #endregion private async Task StartCoverage() { try { ((Command)StartCoverageCommand).ChangeCanExecute(); if (_doctor.Status == 2) { await UtilityVM.ShowAlert( "Warning:", $"Failed to start coverage. The visitation for Dr. {_doctor.FirstName} {_doctor.LastName} has already been completed." ); return; } var confirm = await Application.Current.MainPage.DisplayAlert( "Start Coverage", "Do you want to begin coverage now?", "Yes, Start", "Cancel"); if (!confirm) { return; } await EnsurePlanInitializedAsync(); } catch (Exception ex) { await UtilityVM.ShowAlert("Error", $"Failed to open Market Product page: {ex.Message}"); } finally { IsLoading = false; ((Command)StartCoverageCommand).ChangeCanExecute(); } } private async Task EnsurePlanInitializedAsync() { var today = DateTime.Today; var tomorrow = today.AddDays(1); var plan = await _mrRawPlanRepository.FirstOrDefaultAsync( r => r.MRRawPlanId==_doctor.MRRawPlanId && r.DoctorId == _doctor.DoctorId); var doctor = await _doctorRepository.FirstOrDefaultAsync(d => d.DoctorId == _doctor.DoctorId); if (plan == null) { await Application.Current.MainPage.DisplayAlert("Error", "No plan found for today.", "OK"); return; } if (plan.StartTime == null) { plan.StartTime = DateTime.Now; plan.ActualCallDate = today; var result = await _mrRawPlanRepository.UpdateAsync(plan); doctor.Status = 1; await _doctorRepository.UpdateAsync(doctor); // Broadcast to ALL ViewModels - ONE LINE! DoctorStatusHelper.BroadcastStatusUpdate(_doctor.DoctorId); if (result <= 0) { await Application.Current.MainPage.DisplayAlert( "Failed", "Actual coverage recording failed, please try again!", "OK"); await Application.Current.MainPage.Navigation.PopAsync(); } } var viewVm = new MarketProductVM( _doctor, _doctorRepository, ServiceHelper.GetService(), ServiceHelper.GetService>(), ServiceHelper.GetService>(), ServiceHelper.GetService>(), _syncService, _configuration, _addressService); var viewPage = new MarketProductPage(viewVm); IsLoading = true; await Application.Current.MainPage.Navigation.PushAsync(viewPage); } private async Task Close() { await Application.Current.MainPage.Navigation.PopAsync(); } private async Task CopyEmail() { if (!string.IsNullOrEmpty(_doctor.EmailAddress)) { await Clipboard.SetTextAsync(_doctor.EmailAddress); await Application.Current.MainPage.DisplayAlert("Copied", "Email address copied to clipboard", "OK"); } } private async Task CallPhone() { if (!string.IsNullOrEmpty(_doctor.PhoneNo)) { try { if (PhoneDialer.Default.IsSupported) { PhoneDialer.Default.Open(_doctor.PhoneNo); } else { await Clipboard.SetTextAsync(_doctor.PhoneNo); await Application.Current.MainPage.DisplayAlert("Phone Number", "Phone number copied to clipboard", "OK"); } } catch (Exception ex) { await Application.Current.MainPage.DisplayAlert("Error", $"Unable to dial: {ex.Message}", "OK"); } } } } }