import 'dart:async';
import 'dart:isolate';

import 'package:logging/logging.dart';
import 'package:shared_models/room.dart';

// class GameRoomManager {
//   GameRoomManager({required SendPort this.socketManagerSendPort}) {
//     managerReceivePort = ReceivePort();
//     gamePorts = {};
//     receiveSubscription = managerReceivePort.listen((message) {
//       if (message is GameRoomManagerMessage) {
//         handleMessage(message);
//       } else if (message is GameRoomMessage) {
//         final gameUuid = message.gameUuid;
//         final gamePort = gamePorts[gameUuid];
//         if (gamePort == null) {
//           _logger.warning('Received GameRoomMessage for empty gamePort');
//           return;
//         }
//         gamePort.send(message);
//       } else {
//         _logger.warning('Received unknown message: $message');
//       }
//     });
//   }

//   late final Map<String, SendPort> gamePorts;
//   late final ReceivePort managerReceivePort;
//   late final StreamSubscription<dynamic> receiveSubscription;
//   final SendPort socketManagerSendPort;
//   final Logger _logger = Logger('GameRoomManager');

//   void close() {
//     receiveSubscription.cancel();
//     //TODO remove connections
//   }

//   Future<void> createRoom({required String roomUuid}) async {
//     // receivePort
//     final wsSendPort = SocketManager().createWsSendPort(roomUuid);
//     await Isolate.spawn(LiveGameRoom.spawn, LiveGameRoomData(roomUuid: roomUuid, wsSendPort: wsSendPort, gameManagerSendPort: ));
//     // first message from new isolate will be its SendPort
//     gamePorts[roomUuid] = await roomReceivePort.first as SendPort;
//   }

//   void routePlayerToRoom(String roomCode, PlayerConnection player) {
//     gamePorts[roomCode]?.addPlayer(player);
//   }

//   void handleMessage(message) {
//     throw UnimplementedError();
//   }
// }

class LiveGameRoomData {
  LiveGameRoomData({
    required this.wsSendPort,
    required this.roomUuid,
  });

  final SendPort wsSendPort;
  final String roomUuid;
}

class LiveGameRoom {
  LiveGameRoom({
    required this.receivePort,
    required this.wsSendPort,
    required this.logger,
    required this.streamSubscription,
    required this.roomUuid,
  });

  Timer? gameLoop;
  // final Map<String, PlayerState> players = {};
  final ReceivePort receivePort;
  final SendPort wsSendPort;
  final Logger logger;
  final StreamSubscription<dynamic> streamSubscription;
  final String roomUuid;

  static void spawn(LiveGameRoomData data) {
    // Create new isolate for this room
    // Return handle for communication
    final receivePort = ReceivePort();
    data.wsSendPort.send(receivePort.sendPort);
    final logger = Logger('LiveGameRoom-${data.roomUuid}');

    // ignore: cancel_subscriptions
    final streamSubscription = receivePort.listen(logger.info);

    LiveGameRoom(
      receivePort: receivePort,
      wsSendPort: data.wsSendPort,
      logger: logger,
      streamSubscription: streamSubscription,
      roomUuid: data.roomUuid,
    ).start();

    return;
  }

  void start() {
    gameLoop = Timer.periodic(const Duration(milliseconds: 750), update);
  }

  void update(Timer timer) {
    logger.finest('Room $roomUuid tick: ${timer.tick}');
    wsSendPort.send(
      RoomPingMessage(
        roomUuid,
        dest: PingDestination.client,
      ),
    );
  }

  void close() {
    streamSubscription.cancel();
  }
}