// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only

part of '../sqlite_repositories.dart';

/// SQLite implementation of the app-layer scheduling snapshot repository.
final class _SqliteApplicationSnapshotRepository
    implements core.SchedulingSnapshotRepository {
  /// Creates a snapshot repository for [db].
  _SqliteApplicationSnapshotRepository(
    this.db, {
    required this.defaultOwnerId,
  });

  /// Shared SQLite database handle.
  final SchedulerDb db;

  /// Owner used for save methods without an owner parameter.
  final String defaultOwnerId;

  /// Returns a snapshot by stable id.
  @override
  Future<core.SchedulingStateSnapshot?> findById(String id) async {
    final row = await _snapshotById(id);
    return row == null ? null : _snapshotFromRow(row);
  }

  /// Returns snapshots overlapping [window].
  @override
  Future<List<core.SchedulingStateSnapshot>> findInWindow(
    core.SchedulingWindow window,
  ) async {
    final rows = await (db.select(db.snapshots)
          ..orderBy([(table) => drift.OrderingTerm.asc(table.id)]))
        .get();
    final snapshots = rows
        .map(_snapshotFromRow)
        .where((snapshot) => _windowsOverlap(snapshot.window, window))
        .toList(growable: false);
    return List<core.SchedulingStateSnapshot>.unmodifiable(snapshots);
  }

  /// Saves [snapshot], inserting it when absent.
  @override
  Future<void> save(core.SchedulingStateSnapshot snapshot) async {
    final row = await _snapshotById(snapshot.id);
    if (row == null) {
      await db.into(db.snapshots).insert(
            _snapshotCompanion(
              snapshot,
              ownerId: core.OwnerId(defaultOwnerId),
              revision: core.Revision.initial,
            ),
          );
      return;
    }
    await (db.update(db.snapshots)
          ..where((table) => table.id.equals(snapshot.id)))
        .write(
      _snapshotCompanion(
        snapshot,
        ownerId: core.OwnerId(row.ownerId),
        revision: core.Revision(row.revision).next(),
      ),
    );
  }

  /// Returns a raw snapshot row by id.
  Future<SnapshotRow?> _snapshotById(String id) {
    return (db.select(db.snapshots)..where((table) => table.id.equals(id)))
        .getSingleOrNull();
  }
}
