import 'dart:convert';
import 'package:comwell_key_app/database/comwell_db.dart';
import 'package:comwell_key_app/services/mappers/booking_mapper.dart';
import 'package:comwell_key_app/services/models/booking_dto.dart';
import 'package:comwell_key_app/services/models/bookings_dto.dart';
import 'package:comwell_key_app/utils/json.dart';
import 'package:drift/drift.dart';

import '../../overview/models/booking.dart';
import '../tables/booking_table.dart';

part '../../.generated/database/daos/bookings_dao.g.dart';

@DriftAccessor(tables: [BookingEntity])
class BookingsDao extends DatabaseAccessor<ComwellDatabase>
    with _$BookingsDaoMixin {
  BookingsDao(super.attachedDatabase);

  Future<Iterable<BookingDb>> getBookings() {
    return bookingEntity.all().get();
  }

  Future<Booking> getBookingDetails(
      String bookingId) async {
    final booking = await (select(bookingEntity)
          ..where((entity) => entity.id.equals(bookingId)))
        .getSingle();
    final json = jsonDecode(booking.json) as Json;
    return BookingDTO.fromJson(json).toBooking();
  }

  Future<void> insert(Iterable<BookingDTO> bookings) async {
    final entities = bookings.map((booking) {
      final json = jsonEncode(booking.toJson());
      return BookingEntityCompanion.insert(
          id: booking.confirmationNumber, json: json);
    });
    await batch((batch) => batch.insertAll(bookingEntity, entities,
        mode: InsertMode.insertOrReplace));
  }

  Future<void> insertBookings(BookingsDTO bookings) async {
    await insert(bookings.current);
  }

  Stream<BookingsDTO> watchBookings() {
    return (select(bookingEntity)).watch().map((entities) {
      return BookingsDTO(
          current: _entityToBooking(entities), past: [], cancelled: []);
    });
  }

  Iterable<BookingDTO> _entityToBooking(Iterable<BookingDb> entities) {
    return entities.map((entity) {
      final json = jsonDecode(entity.json) as Json;
      return BookingDTO.fromJson(json);
    }).toList();
  }
}