using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using Microsoft.EntityFrameworkCore;
using LocationTrackerApp.Models;
using LocationTrackerApp.Services;
using LocationTrackerApp.Data;
using Microsoft.Extensions.Logging;

namespace LocationTrackerApp.ViewModels;

/// <summary>
/// View model for the main view of the location tracking application
/// </summary>
public class MainViewModel : INotifyPropertyChanged
{
    private readonly ILocationService _locationService;
    private readonly LocationDbContext _dbContext;
    private readonly ILogger<MainViewModel> _logger;
    private bool _isTracking;
    private bool _isHeatMapVisible = true;
    private bool _isPointsVisible = true;
    private string _trackingStatusText = "Not Tracking";
    private string _currentLocationText = "No location";
    private string _locationCountText = "0 points";
    private string _trackingButtonText = "Start Tracking";
    private Color _trackingButtonColor = Colors.Green;
    private LocationData? _currentLocation;
    private int _locationCount;

    /// <summary>
    /// Event fired when a property value changes
    /// </summary>
    public event PropertyChangedEventHandler? PropertyChanged;

    /// <summary>
    /// Gets or sets whether location tracking is active
    /// </summary>
    public bool IsTracking
    {
        get => _isTracking;
        set
        {
            if (_isTracking != value)
            {
                _isTracking = value;
                OnPropertyChanged();
                UpdateTrackingUI();
            }
        }
    }

    /// <summary>
    /// Gets or sets whether the heat map visualization is visible
    /// </summary>
    public bool IsHeatMapVisible
    {
        get => _isHeatMapVisible;
        set
        {
            if (_isHeatMapVisible != value)
            {
                _isHeatMapVisible = value;
                OnPropertyChanged();
            }
        }
    }

    /// <summary>
    /// Gets or sets whether individual location points are visible
    /// </summary>
    public bool IsPointsVisible
    {
        get => _isPointsVisible;
        set
        {
            if (_isPointsVisible != value)
            {
                _isPointsVisible = value;
                OnPropertyChanged();
            }
        }
    }

    /// <summary>
    /// Gets or sets the tracking status text
    /// </summary>
    public string TrackingStatusText
    {
        get => _trackingStatusText;
        set
        {
            if (_trackingStatusText != value)
            {
                _trackingStatusText = value;
                OnPropertyChanged();
            }
        }
    }

    /// <summary>
    /// Gets or sets the current location text
    /// </summary>
    public string CurrentLocationText
    {
        get => _currentLocationText;
        set
        {
            if (_currentLocationText != value)
            {
                _currentLocationText = value;
                OnPropertyChanged();
            }
        }
    }

    /// <summary>
    /// Gets or sets the location count text
    /// </summary>
    public string LocationCountText
    {
        get => _locationCountText;
        set
        {
            if (_locationCountText != value)
            {
                _locationCountText = value;
                OnPropertyChanged();
            }
        }
    }

    /// <summary>
    /// Gets or sets the tracking button text
    /// </summary>
    public string TrackingButtonText
    {
        get => _trackingButtonText;
        set
        {
            if (_trackingButtonText != value)
            {
                _trackingButtonText = value;
                OnPropertyChanged();
            }
        }
    }

    /// <summary>
    /// Gets or sets the tracking button color
    /// </summary>
    public Color TrackingButtonColor
    {
        get => _trackingButtonColor;
        set
        {
            if (_trackingButtonColor != value)
            {
                _trackingButtonColor = value;
                OnPropertyChanged();
            }
        }
    }

    /// <summary>
    /// Command to toggle location tracking
    /// </summary>
    public ICommand ToggleTrackingCommand { get; }

    /// <summary>
    /// Command to toggle heat map visibility
    /// </summary>
    public ICommand ToggleHeatMapCommand { get; }

    /// <summary>
    /// Command to toggle points visibility
    /// </summary>
    public ICommand TogglePointsCommand { get; }

    /// <summary>
    /// Command to center map on user location
    /// </summary>
    public ICommand CenterOnUserCommand { get; }

    /// <summary>
    /// Command to clear all location data
    /// </summary>
    public ICommand ClearDataCommand { get; }

    /// <summary>
    /// Command to load location data
    /// </summary>
    public ICommand LoadDataCommand { get; }

    /// <summary>
    /// Command to open settings
    /// </summary>
    public ICommand SettingsCommand { get; }

    /// <summary>
    /// Initializes a new instance of MainViewModel
    /// </summary>
    /// <param name="locationService">Location tracking service</param>
    /// <param name="dbContext">Database context for location data</param>
    /// <param name="logger">Logger for recording events</param>
    public MainViewModel(ILocationService locationService, LocationDbContext dbContext, ILogger<MainViewModel> logger)
    {
        _locationService = locationService ?? throw new ArgumentNullException(nameof(locationService));
        _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));

        // Initialize commands
        ToggleTrackingCommand = new Command(async () => await ToggleTrackingAsync());
        ToggleHeatMapCommand = new Command(() => IsHeatMapVisible = !IsHeatMapVisible);
        TogglePointsCommand = new Command(() => IsPointsVisible = !IsPointsVisible);
        CenterOnUserCommand = new Command(async () => await CenterOnUserAsync());
        ClearDataCommand = new Command(async () => await ClearDataAsync());
        LoadDataCommand = new Command(async () => await LoadDataAsync());
        SettingsCommand = new Command(async () => await OpenSettingsAsync());

        // Subscribe to location service events
        _locationService.LocationChanged += OnLocationChanged;
        _locationService.TrackingStatusChanged += OnTrackingStatusChanged;

        // Initialize UI
        UpdateTrackingUI();
        _ = Task.Run(async () => await LoadLocationCountAsync());
    }

    /// <summary>
    /// Toggles location tracking on/off
    /// </summary>
    private async Task ToggleTrackingAsync()
    {
        try
        {
            if (IsTracking)
            {
                await _locationService.StopTrackingAsync();
                _logger.LogInformation("Location tracking stopped by user");
            }
            else
            {
                await _locationService.StartTrackingAsync();
                _logger.LogInformation("Location tracking started by user");
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to toggle location tracking");
            await Application.Current!.Windows[0].Page!.DisplayAlert("Error", "Failed to toggle location tracking", "OK");
        }
    }

    /// <summary>
    /// Centers the map on the user's current location
    /// </summary>
    private async Task CenterOnUserAsync()
    {
        try
        {
            var location = await _locationService.GetCurrentLocationAsync();
            if (location != null)
            {
                // This would need to be implemented in the HeatMapView
                _logger.LogInformation("Centering map on user location: {Latitude}, {Longitude}", 
                    location.Latitude, location.Longitude);
            }
            else
            {
                await Application.Current!.Windows[0].Page!.DisplayAlert("Error", "Unable to get current location", "OK");
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to center on user location");
            await Application.Current!.Windows[0].Page!.DisplayAlert("Error", "Failed to center on user location", "OK");
        }
    }

    /// <summary>
    /// Clears all location data from the database
    /// </summary>
    private async Task ClearDataAsync()
    {
        try
        {
            var result = await Application.Current!.Windows[0].Page!.DisplayAlert(
                "Clear Data", 
                "Are you sure you want to clear all location data? This action cannot be undone.", 
                "Yes", 
                "No");

            if (result)
            {
                await _dbContext.ClearAllLocationDataAsync();
                _locationCount = 0;
                LocationCountText = "0 points";
                _logger.LogInformation("All location data cleared by user");
                await Application.Current.Windows[0].Page!.DisplayAlert("Success", "All location data has been cleared", "OK");
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to clear location data");
            await Application.Current!.Windows[0].Page!.DisplayAlert("Error", "Failed to clear location data", "OK");
        }
    }

    /// <summary>
    /// Loads location data and updates the UI
    /// </summary>
    private async Task LoadDataAsync()
    {
        try
        {
            await LoadLocationCountAsync();
            _logger.LogInformation("Location data loaded by user");
            await Application.Current!.Windows[0].Page!.DisplayAlert("Success", "Location data has been loaded", "OK");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to load location data");
            await Application.Current!.Windows[0].Page!.DisplayAlert("Error", "Failed to load location data", "OK");
        }
    }

    /// <summary>
    /// Opens the settings page
    /// </summary>
    private async Task OpenSettingsAsync()
    {
        try
        {
            // This would navigate to a settings page
            _logger.LogInformation("Settings page requested by user");
            await Application.Current!.Windows[0].Page!.DisplayAlert("Settings", "Settings page coming soon!", "OK");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to open settings");
        }
    }

    /// <summary>
    /// Handles location changed events from the location service
    /// </summary>
    /// <param name="sender">Event sender</param>
    /// <param name="locationData">New location data</param>
    private void OnLocationChanged(object? sender, LocationData locationData)
    {
        try
        {
            _currentLocation = locationData;
            CurrentLocationText = $"Lat: {locationData.Latitude:F6}, Lng: {locationData.Longitude:F6}";
            
            // Update location count
            _locationCount++;
            LocationCountText = $"{_locationCount} points";

            _logger.LogDebug("Location updated: {Latitude}, {Longitude}", locationData.Latitude, locationData.Longitude);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to handle location changed event");
        }
    }

    /// <summary>
    /// Handles tracking status changed events from the location service
    /// </summary>
    /// <param name="sender">Event sender</param>
    /// <param name="isTracking">Current tracking status</param>
    private void OnTrackingStatusChanged(object? sender, bool isTracking)
    {
        try
        {
            IsTracking = isTracking;
            _logger.LogInformation("Tracking status changed: {IsTracking}", isTracking);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to handle tracking status changed event");
        }
    }

    /// <summary>
    /// Updates the tracking-related UI elements
    /// </summary>
    private void UpdateTrackingUI()
    {
        if (IsTracking)
        {
            TrackingStatusText = "Tracking Active";
            TrackingButtonText = "Stop Tracking";
            TrackingButtonColor = Colors.Red;
        }
        else
        {
            TrackingStatusText = "Not Tracking";
            TrackingButtonText = "Start Tracking";
            TrackingButtonColor = Colors.Green;
        }
    }

    /// <summary>
    /// Loads the current location count from the database
    /// </summary>
    private async Task LoadLocationCountAsync()
    {
        try
        {
            _locationCount = await _dbContext.LocationData.CountAsync();
            LocationCountText = $"{_locationCount} points";
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to load location count");
        }
    }

    /// <summary>
    /// Raises the PropertyChanged event
    /// </summary>
    /// <param name="propertyName">Name of the property that changed</param>
    protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    /// <summary>
    /// Disposes the view model and unsubscribes from events
    /// </summary>
    public void Dispose()
    {
        try
        {
            _locationService.LocationChanged -= OnLocationChanged;
            _locationService.TrackingStatusChanged -= OnTrackingStatusChanged;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error disposing MainViewModel");
        }
    }
}
