using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using TakeoutSaaS.Domain.Stores.Entities;
using TakeoutSaaS.Domain.Stores.Enums;
using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Infrastructure.App.Persistence;

namespace TakeoutSaaS.Infrastructure.App.Repositories;

/// <summary>
/// 门店聚合的 EF Core 仓储实现。
/// </summary>
/// <remarks>
/// 初始化仓储。
/// </remarks>
public sealed class EfStoreRepository(TakeoutAppDbContext context) : IStoreRepository
{
    /// <inheritdoc />
    public Task<Store?> FindByIdAsync(long storeId, long? tenantId, CancellationToken cancellationToken = default, bool includeDeleted = false)
    {
        var query = context.Stores.AsNoTracking();

        // 1. 包含软删除数据时忽略全局过滤
        if (includeDeleted)
        {
            query = query.IgnoreQueryFilters();
        }

        // 2. (空行后) 可选租户过滤
        if (tenantId.HasValue)
        {
            query = query.Where(x => x.TenantId == tenantId.Value);
        }

        // 3. (空行后) 默认排除已删除门店（双保险）
        if (!includeDeleted)
        {
            query = query.Where(x => x.DeletedAt == null);
        }

        // 4. (空行后) 返回门店实体
        return query
            .Where(x => x.Id == storeId)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<Store>> GetByMerchantIdAsync(long merchantId, long tenantId, CancellationToken cancellationToken = default)
    {
        return await context.Stores
            .AsNoTracking()
            .Where(x =>
                x.TenantId == tenantId &&
                x.MerchantId == merchantId &&
                x.DeletedAt == null)
            .OrderBy(x => x.Name)
            .ToListAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<Store>> SearchAsync(
        long? tenantId,
        long? merchantId,
        StoreStatus? status,
        StoreAuditStatus? auditStatus,
        StoreBusinessStatus? businessStatus,
        StoreOwnershipType? ownershipType,
        string? keyword,
        bool includeDeleted = false,
        CancellationToken cancellationToken = default)
    {
        var query = context.Stores.AsNoTracking();

        // 1. 包含软删除数据时忽略全局过滤
        if (includeDeleted)
        {
            query = query.IgnoreQueryFilters();
        }

        // 2. (空行后) 可选租户过滤
        if (tenantId.HasValue)
        {
            query = query.Where(x => x.TenantId == tenantId.Value);
        }

        // 3. (空行后) 可选过滤：商户
        if (merchantId.HasValue)
        {
            query = query.Where(x => x.MerchantId == merchantId.Value);
        }

        // 4. (空行后) 默认排除已删除门店（双保险）
        if (!includeDeleted)
        {
            query = query.Where(x => x.DeletedAt == null);
        }

        // 5. (空行后) 可选过滤：状态
        if (status.HasValue)
        {
            query = query.Where(x => x.Status == status.Value);
        }

        // 6. (空行后) 可选过滤：审核状态
        if (auditStatus.HasValue)
        {
            query = query.Where(x => x.AuditStatus == auditStatus.Value);
        }

        // 7. (空行后) 可选过滤：经营状态
        if (businessStatus.HasValue)
        {
            query = query.Where(x => x.BusinessStatus == businessStatus.Value);
        }

        // 8. (空行后) 可选过滤：主体类型
        if (ownershipType.HasValue)
        {
            query = query.Where(x => x.OwnershipType == ownershipType.Value);
        }

        // 9. (空行后) 可选过滤：关键词
        if (!string.IsNullOrWhiteSpace(keyword))
        {
            var trimmed = keyword.Trim();
            query = query.Where(x =>
                x.Name.Contains(trimmed) ||
                x.Code.Contains(trimmed) ||
                (x.Phone != null && x.Phone.Contains(trimmed)));
        }

        // 10. (空行后) 查询并返回结果
        var stores = await query
            .OrderBy(x => x.Name)
            .ToListAsync(cancellationToken);

        return stores;
    }

    /// <inheritdoc />
    public async Task<bool> ExistsStoreWithinDistanceAsync(
        long merchantId,
        long tenantId,
        double longitude,
        double latitude,
        double distanceMeters,
        CancellationToken cancellationToken = default)
    {
        // 1. 校验距离阈值
        if (distanceMeters <= 0)
        {
            return false;
        }

        // 2. (空行后) 拉取候选坐标
        var coordinates = await context.Stores
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId && x.MerchantId == merchantId)
            .Where(x => x.DeletedAt == null)
            .Where(x => x.Longitude.HasValue && x.Latitude.HasValue)
            .Select(x => new { Longitude = x.Longitude!.Value, Latitude = x.Latitude!.Value })
            .ToListAsync(cancellationToken);

        // 3. (空行后) 计算距离并判断是否命中
        foreach (var coordinate in coordinates)
        {
            var distance = CalculateDistanceMeters(latitude, longitude, coordinate.Latitude, coordinate.Longitude);
            if (distance <= distanceMeters)
            {
                return true;
            }
        }

        // 4. (空行后) 返回未命中结果
        return false;
    }

    /// <inheritdoc />
    public async Task<Dictionary<long, int>> GetStoreCountsAsync(long? tenantId, IReadOnlyCollection<long> merchantIds, CancellationToken cancellationToken = default)
    {
        if (merchantIds.Count == 0)
        {
            return new Dictionary<long, int>();
        }

        var query = context.Stores.AsNoTracking();

        // 1. 可选租户过滤
        if (tenantId.HasValue)
        {
            query = query.Where(x => x.TenantId == tenantId.Value);
        }

        // 2. (空行后) 排除已删除门店
        query = query.Where(x => x.DeletedAt == null);

        // 3. (空行后) 分组统计门店数量
        return await query
            .Where(x => merchantIds.Contains(x.MerchantId))
            .GroupBy(x => x.MerchantId)
            .Select(group => new { group.Key, Count = group.Count() })
            .ToDictionaryAsync(x => x.Key, x => x.Count, cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<StoreBusinessHour>> GetBusinessHoursAsync(long storeId, long? tenantId, CancellationToken cancellationToken = default, bool includeDeleted = false)
    {
        var query = context.StoreBusinessHours.AsNoTracking();

        // 1. 包含软删除数据时忽略全局过滤
        if (includeDeleted)
        {
            query = query.IgnoreQueryFilters();
        }

        // 2. (空行后) 可选租户过滤
        if (tenantId.HasValue)
        {
            query = query.Where(x => x.TenantId == tenantId.Value);
        }

        // 3. (空行后) 查询并返回营业时段
        var hours = await query
            .Where(x => x.StoreId == storeId)
            .OrderBy(x => x.DayOfWeek)
            .ThenBy(x => x.StartTime)
            .ToListAsync(cancellationToken);

        return hours;
    }

    /// <inheritdoc />
    public Task<StoreFee?> GetStoreFeeAsync(long storeId, long? tenantId, CancellationToken cancellationToken = default, bool includeDeleted = false)
    {
        var query = context.StoreFees.AsNoTracking();

        // 1. 包含软删除数据时忽略全局过滤
        if (includeDeleted)
        {
            query = query.IgnoreQueryFilters();
        }

        // 2. (空行后) 可选租户过滤
        if (tenantId.HasValue)
        {
            query = query.Where(x => x.TenantId == tenantId.Value);
        }

        // 3. (空行后) 返回费用配置
        return query
            .Where(x => x.StoreId == storeId)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Task AddStoreFeeAsync(StoreFee storeFee, CancellationToken cancellationToken = default)
    {
        return context.StoreFees.AddAsync(storeFee, cancellationToken).AsTask();
    }

    /// <inheritdoc />
    public Task UpdateStoreFeeAsync(StoreFee storeFee, CancellationToken cancellationToken = default)
    {
        context.StoreFees.Update(storeFee);
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<StoreQualification>> GetQualificationsAsync(long storeId, long? tenantId, CancellationToken cancellationToken = default, bool includeDeleted = false)
    {
        var query = context.StoreQualifications.AsNoTracking();

        // 1. 包含软删除数据时忽略全局过滤
        if (includeDeleted)
        {
            query = query.IgnoreQueryFilters();
        }

        // 2. (空行后) 可选租户过滤
        if (tenantId.HasValue)
        {
            query = query.Where(x => x.TenantId == tenantId.Value);
        }

        // 3. (空行后) 查询并返回资质列表
        var qualifications = await query
            .Where(x => x.StoreId == storeId)
            .OrderBy(x => x.SortOrder)
            .ThenBy(x => x.QualificationType)
            .ToListAsync(cancellationToken);
        return qualifications;
    }

    /// <inheritdoc />
    public Task<StoreQualification?> FindQualificationByIdAsync(long qualificationId, long tenantId, CancellationToken cancellationToken = default)
    {
        return context.StoreQualifications
            .Where(x => x.TenantId == tenantId && x.Id == qualificationId)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Task AddQualificationAsync(StoreQualification qualification, CancellationToken cancellationToken = default)
    {
        return context.StoreQualifications.AddAsync(qualification, cancellationToken).AsTask();
    }

    /// <inheritdoc />
    public Task UpdateQualificationAsync(StoreQualification qualification, CancellationToken cancellationToken = default)
    {
        context.StoreQualifications.Update(qualification);
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public async Task DeleteQualificationAsync(long qualificationId, long tenantId, CancellationToken cancellationToken = default)
    {
        var existing = await context.StoreQualifications
            .Where(x => x.TenantId == tenantId && x.Id == qualificationId)
            .FirstOrDefaultAsync(cancellationToken);

        if (existing != null)
        {
            context.StoreQualifications.Remove(existing);
        }
    }

    /// <inheritdoc />
    public Task AddAuditRecordAsync(StoreAuditRecord record, CancellationToken cancellationToken = default)
    {
        return context.StoreAuditRecords.AddAsync(record, cancellationToken).AsTask();
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<StoreAuditRecord>> GetAuditRecordsAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
    {
        var records = await context.StoreAuditRecords
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId && x.StoreId == storeId)
            .OrderByDescending(x => x.CreatedAt)
            .ToListAsync(cancellationToken);
        return records;
    }

    /// <inheritdoc />
    public Task<StoreBusinessHour?> FindBusinessHourByIdAsync(long businessHourId, long tenantId, CancellationToken cancellationToken = default)
    {
        return context.StoreBusinessHours
            .Where(x => x.TenantId == tenantId && x.Id == businessHourId)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<StoreDeliveryZone>> GetDeliveryZonesAsync(long storeId, long? tenantId, CancellationToken cancellationToken = default, bool includeDeleted = false)
    {
        var query = context.StoreDeliveryZones.AsNoTracking();

        // 1. 包含软删除数据时忽略全局过滤
        if (includeDeleted)
        {
            query = query.IgnoreQueryFilters();
        }

        // 2. (空行后) 可选租户过滤
        if (tenantId.HasValue)
        {
            query = query.Where(x => x.TenantId == tenantId.Value);
        }

        // 3. (空行后) 查询并返回配送区域
        var zones = await query
            .Where(x => x.StoreId == storeId)
            .OrderBy(x => x.SortOrder)
            .ToListAsync(cancellationToken);

        return zones;
    }

    /// <inheritdoc />
    public Task<StoreDeliveryZone?> FindDeliveryZoneByIdAsync(long deliveryZoneId, long? tenantId, CancellationToken cancellationToken = default, bool includeDeleted = false)
    {
        var query = context.StoreDeliveryZones.AsQueryable();

        // 1. 包含软删除数据时忽略全局过滤
        if (includeDeleted)
        {
            query = query.IgnoreQueryFilters();
        }

        // 2. (空行后) 可选租户过滤
        if (tenantId.HasValue)
        {
            query = query.Where(x => x.TenantId == tenantId.Value);
        }

        // 3. (空行后) 返回配送区域实体
        return query
            .Where(x => x.Id == deliveryZoneId)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<StoreHoliday>> GetHolidaysAsync(long storeId, long? tenantId, CancellationToken cancellationToken = default, bool includeDeleted = false)
    {
        var query = context.StoreHolidays.AsNoTracking();

        // 1. 包含软删除数据时忽略全局过滤
        if (includeDeleted)
        {
            query = query.IgnoreQueryFilters();
        }

        // 2. (空行后) 可选租户过滤
        if (tenantId.HasValue)
        {
            query = query.Where(x => x.TenantId == tenantId.Value);
        }

        // 3. (空行后) 查询并返回节假日
        var holidays = await query
            .Where(x => x.StoreId == storeId)
            .OrderBy(x => x.Date)
            .ToListAsync(cancellationToken);

        return holidays;
    }

    /// <inheritdoc />
    public Task<StoreHoliday?> FindHolidayByIdAsync(long holidayId, long? tenantId, CancellationToken cancellationToken = default, bool includeDeleted = false)
    {
        var query = context.StoreHolidays.AsQueryable();

        // 1. 包含软删除数据时忽略全局过滤
        if (includeDeleted)
        {
            query = query.IgnoreQueryFilters();
        }

        // 2. (空行后) 可选租户过滤
        if (tenantId.HasValue)
        {
            query = query.Where(x => x.TenantId == tenantId.Value);
        }

        // 3. (空行后) 返回节假日实体
        return query
            .Where(x => x.Id == holidayId)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<StoreTableArea>> GetTableAreasAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
    {
        var areas = await context.StoreTableAreas
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId && x.StoreId == storeId)
            .OrderBy(x => x.SortOrder)
            .ToListAsync(cancellationToken);

        return areas;
    }

    /// <inheritdoc />
    public Task<StoreTableArea?> FindTableAreaByIdAsync(long areaId, long tenantId, CancellationToken cancellationToken = default)
    {
        return context.StoreTableAreas
            .Where(x => x.TenantId == tenantId && x.Id == areaId)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<StoreTable>> GetTablesAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
    {
        var tables = await context.StoreTables
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId && x.StoreId == storeId)
            .OrderBy(x => x.TableCode)
            .ToListAsync(cancellationToken);

        return tables;
    }

    /// <inheritdoc />
    public Task<StoreTable?> FindTableByIdAsync(long tableId, long tenantId, CancellationToken cancellationToken = default)
    {
        return context.StoreTables
            .Where(x => x.TenantId == tenantId && x.Id == tableId)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Task<StoreTable?> FindTableByCodeAsync(string tableCode, long tenantId, CancellationToken cancellationToken = default)
    {
        return context.StoreTables
            .Where(x => x.TenantId == tenantId && x.TableCode == tableCode)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Task<StorePickupSetting?> GetPickupSettingAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
    {
        return context.StorePickupSettings
            .Where(x => x.TenantId == tenantId && x.StoreId == storeId)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Task AddPickupSettingAsync(StorePickupSetting setting, CancellationToken cancellationToken = default)
    {
        return context.StorePickupSettings.AddAsync(setting, cancellationToken).AsTask();
    }

    /// <inheritdoc />
    public Task UpdatePickupSettingAsync(StorePickupSetting setting, CancellationToken cancellationToken = default)
    {
        context.StorePickupSettings.Update(setting);
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<StorePickupSlot>> GetPickupSlotsAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
    {
        var slots = await context.StorePickupSlots
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId && x.StoreId == storeId)
            .OrderBy(x => x.StartTime)
            .ToListAsync(cancellationToken);
        return slots;
    }

    /// <inheritdoc />
    public Task<StorePickupSlot?> FindPickupSlotByIdAsync(long slotId, long tenantId, CancellationToken cancellationToken = default)
    {
        return context.StorePickupSlots
            .Where(x => x.TenantId == tenantId && x.Id == slotId)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Task AddPickupSlotsAsync(IEnumerable<StorePickupSlot> slots, CancellationToken cancellationToken = default)
    {
        return context.StorePickupSlots.AddRangeAsync(slots, cancellationToken);
    }

    /// <inheritdoc />
    public Task UpdatePickupSlotAsync(StorePickupSlot slot, CancellationToken cancellationToken = default)
    {
        context.StorePickupSlots.Update(slot);
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public async Task<IReadOnlyList<StoreEmployeeShift>> GetShiftsAsync(long storeId, long tenantId, DateTime? from = null, DateTime? to = null, CancellationToken cancellationToken = default)
    {
        var query = context.StoreEmployeeShifts
            .AsNoTracking()
            .Where(x => x.TenantId == tenantId && x.StoreId == storeId);

        if (from.HasValue)
        {
            query = query.Where(x => x.ShiftDate >= from.Value.Date);
        }

        if (to.HasValue)
        {
            query = query.Where(x => x.ShiftDate <= to.Value.Date);
        }

        var shifts = await query
            .OrderBy(x => x.ShiftDate)
            .ThenBy(x => x.StartTime)
            .ToListAsync(cancellationToken);

        return shifts;
    }

    /// <inheritdoc />
    public Task<StoreEmployeeShift?> FindShiftByIdAsync(long shiftId, long tenantId, CancellationToken cancellationToken = default)
    {
        return context.StoreEmployeeShifts
            .Where(x => x.TenantId == tenantId && x.Id == shiftId)
            .FirstOrDefaultAsync(cancellationToken);
    }

    /// <inheritdoc />
    public Task AddStoreAsync(Store store, CancellationToken cancellationToken = default)
    {
        return context.Stores.AddAsync(store, cancellationToken).AsTask();
    }

    /// <inheritdoc />
    public Task AddBusinessHoursAsync(IEnumerable<StoreBusinessHour> hours, CancellationToken cancellationToken = default)
    {
        return context.StoreBusinessHours.AddRangeAsync(hours, cancellationToken);
    }

    /// <inheritdoc />
    public Task UpdateBusinessHourAsync(StoreBusinessHour hour, CancellationToken cancellationToken = default)
    {
        context.StoreBusinessHours.Update(hour);
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public Task AddDeliveryZonesAsync(IEnumerable<StoreDeliveryZone> zones, CancellationToken cancellationToken = default)
    {
        return context.StoreDeliveryZones.AddRangeAsync(zones, cancellationToken);
    }

    /// <inheritdoc />
    public Task UpdateDeliveryZoneAsync(StoreDeliveryZone zone, CancellationToken cancellationToken = default)
    {
        context.StoreDeliveryZones.Update(zone);
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public Task AddHolidaysAsync(IEnumerable<StoreHoliday> holidays, CancellationToken cancellationToken = default)
    {
        return context.StoreHolidays.AddRangeAsync(holidays, cancellationToken);
    }

    /// <inheritdoc />
    public Task UpdateHolidayAsync(StoreHoliday holiday, CancellationToken cancellationToken = default)
    {
        context.StoreHolidays.Update(holiday);
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public Task AddTableAreasAsync(IEnumerable<StoreTableArea> areas, CancellationToken cancellationToken = default)
    {
        return context.StoreTableAreas.AddRangeAsync(areas, cancellationToken);
    }

    /// <inheritdoc />
    public Task UpdateTableAreaAsync(StoreTableArea area, CancellationToken cancellationToken = default)
    {
        context.StoreTableAreas.Update(area);
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public Task AddTablesAsync(IEnumerable<StoreTable> tables, CancellationToken cancellationToken = default)
    {
        return context.StoreTables.AddRangeAsync(tables, cancellationToken);
    }

    /// <inheritdoc />
    public Task UpdateTableAsync(StoreTable table, CancellationToken cancellationToken = default)
    {
        context.StoreTables.Update(table);
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public Task AddShiftsAsync(IEnumerable<StoreEmployeeShift> shifts, CancellationToken cancellationToken = default)
    {
        return context.StoreEmployeeShifts.AddRangeAsync(shifts, cancellationToken);
    }

    /// <inheritdoc />
    public Task UpdateShiftAsync(StoreEmployeeShift shift, CancellationToken cancellationToken = default)
    {
        context.StoreEmployeeShifts.Update(shift);
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public Task SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        return context.SaveChangesAsync(cancellationToken);
    }

    /// <inheritdoc />
    public async Task DeleteBusinessHourAsync(long businessHourId, long tenantId, CancellationToken cancellationToken = default)
    {
        var existing = await context.StoreBusinessHours
            .Where(x => x.TenantId == tenantId && x.Id == businessHourId)
            .FirstOrDefaultAsync(cancellationToken);

        if (existing != null)
        {
            context.StoreBusinessHours.Remove(existing);
        }
    }

    /// <inheritdoc />
    public async Task DeleteDeliveryZoneAsync(long deliveryZoneId, long? tenantId, CancellationToken cancellationToken = default)
    {
        // 1. 查询目标配送区域
        var query = context.StoreDeliveryZones.AsQueryable();
        if (tenantId.HasValue)
        {
            query = query.Where(x => x.TenantId == tenantId.Value);
        }

        // 2. (空行后) 执行软删除
        var existing = await query
            .Where(x => x.Id == deliveryZoneId)
            .FirstOrDefaultAsync(cancellationToken);

        if (existing != null)
        {
            context.StoreDeliveryZones.Remove(existing);
        }
    }

    /// <inheritdoc />
    public async Task DeleteHolidayAsync(long holidayId, long? tenantId, CancellationToken cancellationToken = default)
    {
        // 1. 查询目标节假日
        var query = context.StoreHolidays.AsQueryable();
        if (tenantId.HasValue)
        {
            query = query.Where(x => x.TenantId == tenantId.Value);
        }

        // 2. (空行后) 执行软删除
        var existing = await query
            .Where(x => x.Id == holidayId)
            .FirstOrDefaultAsync(cancellationToken);

        if (existing != null)
        {
            context.StoreHolidays.Remove(existing);
        }
    }

    /// <inheritdoc />
    public async Task DeleteTableAreaAsync(long areaId, long tenantId, CancellationToken cancellationToken = default)
    {
        var existing = await context.StoreTableAreas
            .Where(x => x.TenantId == tenantId && x.Id == areaId)
            .FirstOrDefaultAsync(cancellationToken);

        if (existing != null)
        {
            context.StoreTableAreas.Remove(existing);
        }
    }

    /// <inheritdoc />
    public async Task DeleteTableAsync(long tableId, long tenantId, CancellationToken cancellationToken = default)
    {
        var existing = await context.StoreTables
            .Where(x => x.TenantId == tenantId && x.Id == tableId)
            .FirstOrDefaultAsync(cancellationToken);

        if (existing != null)
        {
            context.StoreTables.Remove(existing);
        }
    }

    /// <inheritdoc />
    public async Task DeletePickupSlotAsync(long slotId, long tenantId, CancellationToken cancellationToken = default)
    {
        var existing = await context.StorePickupSlots
            .Where(x => x.TenantId == tenantId && x.Id == slotId)
            .FirstOrDefaultAsync(cancellationToken);

        if (existing != null)
        {
            context.StorePickupSlots.Remove(existing);
        }
    }

    /// <inheritdoc />
    public async Task DeleteShiftAsync(long shiftId, long tenantId, CancellationToken cancellationToken = default)
    {
        var existing = await context.StoreEmployeeShifts
            .Where(x => x.TenantId == tenantId && x.Id == shiftId)
            .FirstOrDefaultAsync(cancellationToken);

        if (existing != null)
        {
            context.StoreEmployeeShifts.Remove(existing);
        }
    }

    /// <inheritdoc />
    public Task UpdateStoreAsync(Store store, CancellationToken cancellationToken = default)
    {
        context.Stores.Update(store);
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public async Task DeleteStoreAsync(long storeId, long tenantId, CancellationToken cancellationToken = default)
    {
        var existing = await context.Stores
            .Where(x => x.TenantId == tenantId && x.Id == storeId)
            .FirstOrDefaultAsync(cancellationToken);

        if (existing == null)
        {
            return;
        }

        context.Stores.Remove(existing);
    }

    private static double CalculateDistanceMeters(double latitude1, double longitude1, double latitude2, double longitude2)
    {
        const double earthRadius = 6371000d;
        var latRad1 = DegreesToRadians(latitude1);
        var latRad2 = DegreesToRadians(latitude2);
        var deltaLat = DegreesToRadians(latitude2 - latitude1);
        var deltaLon = DegreesToRadians(longitude2 - longitude1);
        var sinLat = Math.Sin(deltaLat / 2);
        var sinLon = Math.Sin(deltaLon / 2);
        var a = sinLat * sinLat + Math.Cos(latRad1) * Math.Cos(latRad2) * sinLon * sinLon;
        var c = 2 * Math.Asin(Math.Min(1, Math.Sqrt(a)));
        return earthRadius * c;
    }

    private static double DegreesToRadians(double degrees) => degrees * (Math.PI / 180d);
}
