using Microsoft.EntityFrameworkCore;
using LocationTrackerApp.Models;

namespace LocationTrackerApp.Data;

/// <summary>
/// Entity Framework DbContext for managing location data in SQLite database
/// </summary>
public class LocationDbContext : DbContext
{
    /// <summary>
    /// Database path for SQLite storage
    /// </summary>
    public string DatabasePath { get; }

    /// <summary>
    /// DbSet for LocationData entities
    /// </summary>
    public DbSet<LocationData> LocationData { get; set; } = null!;

    /// <summary>
    /// Initializes a new instance of LocationDbContext
    /// </summary>
    /// <param name="databasePath">Path to the SQLite database file</param>
    public LocationDbContext(string databasePath)
    {
        DatabasePath = databasePath;
    }

    /// <summary>
    /// Configures the database connection and options
    /// </summary>
    /// <param name="optionsBuilder">Options builder for configuring the database</param>
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite($"Data Source={DatabasePath}");
        
        // Enable sensitive data logging for development (remove in production)
        #if DEBUG
        optionsBuilder.EnableSensitiveDataLogging();
        #endif
    }

    /// <summary>
    /// Configures entity relationships and constraints
    /// </summary>
    /// <param name="modelBuilder">Model builder for configuring entities</param>
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        // Configure LocationData entity
        modelBuilder.Entity<LocationData>(entity =>
        {
            // Set primary key
            entity.HasKey(e => e.Id);

            // Configure indexes for better query performance
            entity.HasIndex(e => e.Timestamp)
                  .HasDatabaseName("IX_LocationData_Timestamp");

            entity.HasIndex(e => e.SessionId)
                  .HasDatabaseName("IX_LocationData_SessionId");

            entity.HasIndex(e => new { e.Latitude, e.Longitude })
                  .HasDatabaseName("IX_LocationData_Coordinates");

            // Configure column types and constraints
            entity.Property(e => e.Latitude)
                  .HasColumnType("REAL")
                  .IsRequired();

            entity.Property(e => e.Longitude)
                  .HasColumnType("REAL")
                  .IsRequired();

            entity.Property(e => e.Accuracy)
                  .HasColumnType("REAL")
                  .HasDefaultValue(0.0);

            entity.Property(e => e.Altitude)
                  .HasColumnType("REAL");

            entity.Property(e => e.Speed)
                  .HasColumnType("REAL");

            entity.Property(e => e.Timestamp)
                  .HasColumnType("TEXT")
                  .IsRequired();

            entity.Property(e => e.SessionId)
                  .HasColumnType("TEXT")
                  .HasMaxLength(100);

            entity.Property(e => e.Notes)
                  .HasColumnType("TEXT")
                  .HasMaxLength(500);
        });
    }

    /// <summary>
    /// Ensures the database is created and up to date
    /// </summary>
    public async Task EnsureDatabaseCreatedAsync()
    {
        await Database.EnsureCreatedAsync();
    }

    /// <summary>
    /// Clears all location data from the database
    /// </summary>
    public async Task ClearAllLocationDataAsync()
    {
        await Database.ExecuteSqlRawAsync("DELETE FROM LocationData");
    }

    /// <summary>
    /// Gets location data within a specified time range
    /// </summary>
    /// <param name="startTime">Start time for the query</param>
    /// <param name="endTime">End time for the query</param>
    /// <returns>List of location data within the time range</returns>
    public async Task<List<LocationData>> GetLocationDataInTimeRangeAsync(DateTime startTime, DateTime endTime)
    {
        return await LocationData
            .Where(l => l.Timestamp >= startTime && l.Timestamp <= endTime)
            .OrderBy(l => l.Timestamp)
            .ToListAsync();
    }

    /// <summary>
    /// Gets location data for a specific session
    /// </summary>
    /// <param name="sessionId">Session identifier</param>
    /// <returns>List of location data for the session</returns>
    public async Task<List<LocationData>> GetLocationDataBySessionAsync(string sessionId)
    {
        return await LocationData
            .Where(l => l.SessionId == sessionId)
            .OrderBy(l => l.Timestamp)
            .ToListAsync();
    }
}
