using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using LSFE.MobApp.Contracts;
using LSFE.MobApp.Entities.Account;
using LSFE.MobApp.Entities.Doctor;
using LSFE.MobApp.Entities.Location;
using LSFE.MobApp.Models;
using LSFE.MobApp.Services;
using LSFE.Infrastructure.Entities.Maintenance;
using Microsoft.Extensions.Logging;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace LSFE.MobApp.ViewModels
{
    public partial class MainPageVM : ObservableObject, INotifyPropertyChanged
    {
        private readonly Repository<User> _userRepository;
        private readonly Repository<Institution> _institutionRepository;
        private readonly Repository<Doctor> _doctorRepository;
        private readonly IDatabaseService _databaseService;
        private readonly ILogger<MainPageVM> _logger;
        private readonly ISyncService _syncService; // Add sync service
        private readonly IApiClientFactory _apiClientFactory; // Add API client factory

        private DateTime _currentMonthStart;
        private string _selectedTask = "REMOTE, TASK 1";
        private bool _isLeftPanelVisible = true;
        private int _currentCycle;
        private bool _isLoading;
        private bool _isSyncing; // Add sync status
        private string _statusMessage = string.Empty; // Add status message

        public ObservableCollection<Institution> Institutions { get; set; } = new();
        public ObservableCollection<Entities.Doctor.Doctor> AllDoctors { get; set; } = new();

        // Add property to track selected doctor
        [ObservableProperty]
        private Doctor selectedDoctor;

        // Add property to control which view is shown
        [ObservableProperty]
        private bool isCalendarViewVisible = true;

        // Property to control doctor view visibility
        public bool IsDoctorViewVisible => !isCalendarViewVisible;

        // Command to toggle institution expansion
        [RelayCommand]
        private void ToggleInstitution(Institution institution)
        {
            if (institution != null)
            {
                institution.IsExpanded = !institution.IsExpanded;
            }
        }


        public bool IsSyncing
        {
            get => _isSyncing;
            set => SetProperty(ref _isSyncing, value);
        }

        public string StatusMessage
        {
            get => _statusMessage;
            set => SetProperty(ref _statusMessage, value);
        }

        // Add this property for header visibility
        private bool _isHeaderVisible = true;
        public bool IsHeaderVisible
        {
            get => _isHeaderVisible;
            set
            {
                if (_isHeaderVisible != value)
                {
                    _isHeaderVisible = value;
                    OnPropertyChanged(nameof(IsHeaderVisible));
                }
            }
        }

        public string SelectedTask
        {
            get => _selectedTask;
            set => SetProperty(ref _selectedTask, value);
        }

        public DateTime CurrentMonthStart
        {
            get => _currentMonthStart;
            set
            {
                if (SetProperty(ref _currentMonthStart, value))
                {
                    OnPropertyChanged(nameof(CycleText));
                    OnPropertyChanged(nameof(CurrentMonthText));
                   // LoadCalendarMonth();
                }
            }
        }

        public bool IsLeftPanelVisible
        {
            get => _isLeftPanelVisible;
            set
            {
                if (SetProperty(ref _isLeftPanelVisible, value))
                {
                    OnPropertyChanged(nameof(LeftPanelWidth));
                    OnPropertyChanged(nameof(LeftPanelVisibility));
                }
            }
        }

        public int CurrentCycle
        {
            get => _currentCycle;
            set
            {
                if (SetProperty(ref _currentCycle, value))
                {
                    OnPropertyChanged(nameof(CycleText));
                }
            }
        }

        public bool IsLoading
        {
            get => _isLoading;
            set => SetProperty(ref _isLoading, value);
        }

        public string CycleText => $"Cycle {CurrentCycle}";
        public string CurrentMonthText => CurrentMonthStart.ToString("MMMM yyyy");
        public GridLength LeftPanelWidth => IsLeftPanelVisible ? new GridLength(250, GridUnitType.Absolute) : new GridLength(0, GridUnitType.Absolute);
        public bool LeftPanelVisibility => IsLeftPanelVisible;

        public MainPageVM(
            Repository<User> userRepository,
            Repository<Doctor> doctorRepository,
            Repository<Institution> institutionRepository,
            IDatabaseService databaseService,
            ILogger<MainPageVM> logger,
            ISyncService syncService, // Add sync service injection
            IApiClientFactory apiClientFactory) // Add API client factory injection
        {
            _userRepository = userRepository;
            _doctorRepository = doctorRepository;
            _institutionRepository = institutionRepository;
            _databaseService = databaseService;
            _logger = logger;
            _syncService = syncService;
            _apiClientFactory = apiClientFactory;

            //InitializePlottingNavigationItems();

            // Initialize with current month
            CurrentMonthStart = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
            CurrentCycle = DateTime.Today.Month;

            // Load data asynchronously
            _ = Task.Run(async () => await InitializeDataAsync());
        }
        [RelayCommand]
        private async Task SyncFromServerAsync()
        {
            if (IsSyncing) return;

            try
            {
                IsSyncing = true;
                StatusMessage = "Fetching data from server...";

                // Create API client using the exact API entity type
                var apiClient = _apiClientFactory.CreateClient<Institutions>("institutions");

                // Call your Web API endpoint
                var serverInstitutions = await apiClient.GetAllAsync();

                if (serverInstitutions?.Any() == true)
                {
                    StatusMessage = $"Received {serverInstitutions.Count} institutions from server";
                    _logger.LogInformation($"Successfully fetched {serverInstitutions.Count} institutions from server");

                    // Log sample data to verify API response
                    foreach (var institution in serverInstitutions.Take(3))
                    {
                        _logger.LogInformation($"API Data: ID={institution.InstitutionId}, Name={institution.InstitutionName}, Territory={institution.TerritoryId}, Active={institution.IsActive}");
                    }

                    // Process the data
                    await ProcessServerDataAsync(serverInstitutions);

                    StatusMessage = "Server data processed successfully!";
                }
                else
                {
                    StatusMessage = "No data received from server";
                    _logger.LogWarning("No institutions received from server");
                }

                // Clear status message after delay
                await Task.Delay(3000);
                StatusMessage = string.Empty;
            }
            catch (HttpRequestException httpEx)
            {
                _logger.LogError(httpEx, "Network error while fetching from server");
                StatusMessage = "Network error: Check your connection";
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error fetching data from server");
                StatusMessage = $"Server error: {ex.Message}";
            }
            finally
            {
                IsSyncing = false;

                // Clear error messages after delay
                if (!string.IsNullOrEmpty(StatusMessage))
                {
                    await Task.Delay(5000);
                    StatusMessage = string.Empty;
                }
            }
        }
        // Option 1: Use InsertAsync directly instead of SaveAsync
        private async Task ProcessServerDataAsync(List<Institutions> serverInstitutions)
        {
            try
            {
                _logger.LogInformation($"=== PROCESSING SERVER DATA ===");
                _logger.LogInformation($"Received {serverInstitutions.Count} institutions from server");

                int newCount = 0;
                int updatedCount = 0;
                int errorCount = 0;

                foreach (var serverInstitution in serverInstitutions)
                {
                    try
                    {
                        // Find existing local record by InstitutionId
                        var existingLocal = await _institutionRepository.FirstOrDefaultAsync(x => x.InstitutionId == serverInstitution.InstitutionId);

                        if (existingLocal == null)
                        {
                            // Create new local record with DEFAULT GUID initially
                            var newInstitution = new Institution
                            {
                                Id = default(Guid), // Use default GUID for SaveAsync to work
                                InstitutionId = serverInstitution.InstitutionId,
                                InstitutionName = serverInstitution.InstitutionName,
                                TerritoryId = serverInstitution.TerritoryId,
                                IsActive = serverInstitution.IsActive,
                                LastSyncedAt = DateTime.UtcNow,
                                NeedsSync = false,
                                CreatedDate = DateTime.UtcNow
                            };

                            _logger.LogInformation($"Creating: {newInstitution.InstitutionName} (ServerID: {newInstitution.InstitutionId})");

                            // Method 1: Use SaveAsync with default GUID
                            var result = await _institutionRepository.SaveAsync(newInstitution);

                            _logger.LogInformation($"Save result: {result}");

                            if (result > 0)
                            {
                                newCount++;
                                _logger.LogInformation($"✅ Successfully created: {newInstitution.InstitutionName}");
                            }
                            else
                            {
                                _logger.LogWarning($"❌ SaveAsync failed, trying direct insert...");

                                // Method 2: Try direct insert as backup
                                //try
                                //{
                                //    newInstitution.Id = Guid.NewGuid(); // Set proper GUID for direct insert

                                //    // Use direct SQLite insert
                                //    var insertQuery = @"
                                //INSERT INTO Institutions (Id, InstitutionId, InstitutionName, TerritoryId, IsActive, CreatedDate, LastSyncedAt, NeedsSync) 
                                //VALUES (?, ?, ?, ?, ?, ?, ?, ?)";

                                //    await _institutionRepository.QueryAsync<object>(insertQuery,
                                //        newInstitution.Id.ToString(),
                                //        newInstitution.InstitutionId,
                                //        newInstitution.InstitutionName,
                                //        newInstitution.TerritoryId,
                                //        newInstitution.IsActive ? 1 : 0,
                                //        newInstitution.CreatedDate.ToString("yyyy-MM-dd HH:mm:ss"),
                                //        newInstitution.LastSyncedAt.ToString("yyyy-MM-dd HH:mm:ss"),
                                //        newInstitution.NeedsSync ? 1 : 0
                                //    );

                                //    newCount++;
                                //    _logger.LogInformation($"✅ Direct insert successful: {newInstitution.InstitutionName}");
                                //}
                                //catch (Exception insertEx)
                                //{
                                //    _logger.LogError(insertEx, $"❌ Direct insert also failed: {newInstitution.InstitutionName}");
                                //    errorCount++;
                                //}
                            }

                            // Verify the record was saved
                            var verification = await _institutionRepository.FirstOrDefaultAsync(x => x.InstitutionId == serverInstitution.InstitutionId);
                            if (verification != null)
                            {
                                _logger.LogInformation($"✅ Verified in database: {verification.InstitutionName} with GUID: {verification.Id}");
                            }
                            else
                            {
                                _logger.LogWarning($"❌ Could not verify saved record for {newInstitution.InstitutionName}");
                            }
                        }
                        else
                        {
                            // Update existing record
                            var oldName = existingLocal.InstitutionName;
                            existingLocal.InstitutionName = serverInstitution.InstitutionName;
                            existingLocal.TerritoryId = serverInstitution.TerritoryId;
                            existingLocal.IsActive = serverInstitution.IsActive;
                            existingLocal.LastSyncedAt = DateTime.UtcNow;
                            existingLocal.NeedsSync = false;

                            var result = await _institutionRepository.UpdateAsync(existingLocal);

                            if (result > 0)
                            {
                                updatedCount++;
                                _logger.LogInformation($"✅ Updated: {oldName} -> {existingLocal.InstitutionName}");
                            }
                            else
                            {
                                _logger.LogWarning($"❌ Failed to update: {existingLocal.InstitutionName}");
                                errorCount++;
                            }
                        }
                    }
                    catch (Exception itemEx)
                    {
                        _logger.LogError(itemEx, $"Error processing institution {serverInstitution.InstitutionId}: {serverInstitution.InstitutionName}");
                        errorCount++;
                    }
                }

                _logger.LogInformation($"=== SYNC SUMMARY ===");
                _logger.LogInformation($"New: {newCount}, Updated: {updatedCount}, Errors: {errorCount}");

                // Final verification - count records in database
                var finalCount = (await _institutionRepository.GetAllAsync()).Count;
                _logger.LogInformation($"Total records in database after sync: {finalCount}");

                // Refresh the UI data
                await LoadDataFromDatabaseAsync();

                StatusMessage = $"Processed: {newCount} new, {updatedCount} updated, {errorCount} errors. Total DB records: {finalCount}";
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error processing server data");
                throw;
            }
        }

        private async Task InitializeDataAsync()
        {
            try
            {
                IsLoading = true;
                await _databaseService.InitializeAsync();

                await _institutionRepository.GetActiveAsync();

                await LoadDataFromDatabaseAsync();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error initializing data");
            }
            finally
            {
                IsLoading = false;
            }
        }

        private async Task LoadDataFromDatabaseAsync()
        {
            try
            {
                // Load institutions from database
                var institutions = await _institutionRepository.GetActiveAsync();
                var users = await _doctorRepository.GetActiveAsync();

                // Update UI on main thread
                MainThread.BeginInvokeOnMainThread(() =>
                {
                    // Clear existing collections
                    Institutions.Clear();
                    AllDoctors.Clear();

                    // Add all users to AllUsers collection
                    foreach (var user in users)
                    {
                        // Set institution name for display
                        var institution = institutions.FirstOrDefault(i => i.InstitutionId == user.InstitutionId);
                        if (institution != null)
                        {
                            user.InstitutionName = institution.InstitutionName;
                        }
                        AllDoctors.Add(user);
                    }

                    // Group users by institution and add to Institutions collection
                    foreach (var institution in institutions)
                    {
                        var institutionUsers = users.Where(u => u.InstitutionId == institution.InstitutionId).ToList();
                        institution.Doctors.Clear();
                        foreach (var user in institutionUsers)
                        {
                            institution.Doctors.Add(user);
                        }
                        Institutions.Add(institution);
                    }

                    _logger.LogInformation($"Loaded {institutions.Count} institutions and {users.Count} users from database");
                });
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error loading data from database");
                throw;
            }
        }

        // Updated RefreshDataAsync with sync functionality
        [RelayCommand]
        private async Task RefreshDataAsync()
        {
            if (IsSyncing) return; // Prevent multiple sync operations

            try
            {
                IsSyncing = true;
                StatusMessage = "Syncing with server...";

                // First try to sync with server
                var syncSuccess = await _syncService.SyncPullCoveragePlanTodayAsync();

                if (syncSuccess)
                {
                    StatusMessage = "Sync successful! Loading updated data...";
                    _logger.LogInformation("Data sync completed successfully");
                }
                else
                {
                    StatusMessage = "Sync failed, loading local data...";
                    _logger.LogWarning("Data sync failed, falling back to local data");
                }

                // Load updated local data
                await LoadDataFromDatabaseAsync();

                StatusMessage = syncSuccess ? "Data refreshed successfully!" : "Loaded local data";

                // Clear status message after delay
                await Task.Delay(3000);
                StatusMessage = string.Empty;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error refreshing data");
                StatusMessage = $"Error: {ex.Message}";

                // Clear error message after delay
                await Task.Delay(5000);
                StatusMessage = string.Empty;
            }
            finally
            {
                IsSyncing = false;
            }
        }
     

        [RelayCommand]
        private void ToggleLeftPanel()
        {
            IsLeftPanelVisible = !IsLeftPanelVisible;
        }

        [RelayCommand]
        private void PreviousMonth()
        {
            CurrentMonthStart = CurrentMonthStart.AddMonths(-1);
        }

        [RelayCommand]
        private void NextMonth()
        {
            CurrentMonthStart = CurrentMonthStart.AddMonths(1);
        }
    }
}