import 'dart:convert';

import 'package:comwell_key_app/database/comwell_db.dart';
import 'package:comwell_key_app/hotel_information/models/hotel.dart';
import 'package:comwell_key_app/utils/json.dart';
import 'package:drift/drift.dart';

import '../tables/hotel_information_table.dart';

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

@DriftAccessor(tables: [HotelInformationEntity])
class HotelInformationDAO extends DatabaseAccessor<ComwellDatabase>
    with _$HotelInformationDAOMixin {
  HotelInformationDAO(super.attachedDatabase);

  /// Get hotel information by hotel code
  Future<Hotel> getHotelByCode(String hotelCode) async {
    final query = select(hotelInformationEntity)
      ..where((tbl) => tbl.hotelCode.equals(hotelCode));
    final result = await query.getSingle();
    final json = jsonDecode(result.json) as Json;
    return Hotel.fromJson(json);
  }

  /// Save hotel information to database
  Future<void> saveHotel(Hotel hotel) async {
    final json = jsonEncode(hotel.toJson());
    final entity = HotelInformationEntityCompanion.insert(
      hotelCode: hotel.hotelCode,
      json: json,
    );
    await batch((batch) => batch.insert(hotelInformationEntity, entity,
        mode: InsertMode.insertOrReplace));
  }

  /// Watch hotel information changes
  Stream<Hotel?> watchHotelByCode(String hotelCode) {
    return (select(hotelInformationEntity)
          ..where((tbl) => tbl.hotelCode.equals(hotelCode)))
        .watchSingleOrNull()
        .map((result) {
      if (result == null) {
        return null;
      }
      final json = jsonDecode(result.json) as Json;
      return Hotel.fromJson(json);
    });
  }

  /// Delete hotel information by hotel code
  Future<void> deleteHotelByCode(String hotelCode) async {
    await (delete(hotelInformationEntity)
          ..where((tbl) => tbl.hotelCode.equals(hotelCode)))
        .go();
  }

  /// Get all hotels
  Future<List<Hotel>> getAllHotels() async {
    final results = await select(hotelInformationEntity).get();
    return results.map((result) {
      final json = jsonDecode(result.json) as Json;
      return Hotel.fromJson(json);
    }).toList();
  }
}