// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/// Since this file includes Sky/Mojo, it will need to be mocked out for unit
/// tests.
/// Unfortunately, imports can't be replaced, so the best thing to do is to swap
/// out the whole file.
///
/// The goal of the SettingsManager is to handle viewing and editing of the
/// Croupier Settings.
/// loadSettings: Get the settings of the current player or specified userID.
/// saveSettings: For the current player and their userID, save settings.
/// In the background, these values will be synced.
/// When setting up a syncgroup, the userIDs are very important.

import '../../settings/client.dart' as settings_client;
import '../../logic/game/game.dart' as logic_game;
import '../../logic/croupier_settings.dart' show CroupierSettings;
import 'croupier_client.dart' show CroupierClient;
import 'discovery_client.dart' show DiscoveryClient;
import 'util.dart' as util;

import 'dart:async';
import 'dart:convert' show UTF8, JSON;

import 'package:v23discovery/discovery.dart' as discovery;
import 'package:syncbase/syncbase_client.dart' as sc;

class SettingsManager {
  final util.KeyValueCallback updateSettingsCallback;
  final util.KeyValueCallback updateGamesCallback;
  final util.KeyValueCallback updatePlayerFoundCallback;
  final util.KeyValueCallback updateGameStatusCallback;
  final util.AsyncKeyValueCallback updateGameLogCallback;
  final CroupierClient _cc;
  sc.SyncbaseTable tb;

  static const String _discoveryGameAdKey = "discovery-game-ad";

  // The game subscription. Cancel when done listening.
  StreamSubscription<sc.WatchChange> _gameSubscription;

  SettingsManager(
      settings_client.AppSettings appSettings,
      this.updateSettingsCallback,
      this.updateGamesCallback,
      this.updatePlayerFoundCallback,
      this.updateGameStatusCallback,
      this.updateGameLogCallback)
      : _cc = new CroupierClient(appSettings);

  Future _prepareSettingsTable() async {
    if (tb != null) {
      return; // Then we're already prepared.
    }

    sc.SyncbaseDatabase db = await _cc.createDatabase();
    tb = await _cc.createTable(db, util.tableNameSettings);

    // Start to watch the stream for the shared settings table.
    await _cc.watchEverything(db, util.tableNameSettings,
        util.settingsWatchSyncPrefix, _onSettingsChange);
  }

  // In the case of the settings manager, we're checking for any changes to
  // any person's Croupier Settings.
  Future _onSettingsChange(String key, String value, bool duringScan) async {
    this.updateSettingsCallback(util.userIDFromSettingsDataKey(key), value);
  }

  // Guaranteed to be called when the program starts.
  // If no Croupier Settings exist, then random ones are created.
  Future<String> load() async {
    util.log('SettingsManager.load');
    await _prepareSettingsTable();

    int userID = await _getUserID();
    if (userID == null) {
      CroupierSettings settings = new CroupierSettings.random();
      String jsonStr = settings.toJSONString();
      await this.save(settings.userID, jsonStr);
      return jsonStr;
    } else {
      return await _tryReadData(tb, util.settingsDataKeyFromUserID(userID));
    }
  }

  Future<String> _tryReadData(sc.SyncbaseTable st, String rowkey) async {
    var row = st.row(rowkey);
    if (!(await row.exists())) {
      print("$rowkey did not exist");
      return null;
    }
    return UTF8.decode(await row.get());
  }

  // Note: only the current user is allowed to save settings.
  // This means we can also save their user id.
  // All other settings will be synced instead.
  Future save(int userID, String jsonString) async {
    util.log('SettingsManager.save');
    await _prepareSettingsTable();

    await tb.row(util.settingsPersonalKey).put(UTF8.encode("$userID"));
    await tb
        .row(util.settingsDataKeyFromUserID(userID))
        .put(UTF8.encode(jsonString));
  }

  // Best called after load(), to ensure that there are settings in the table.
  Future createSettingsSyncgroup() async {
    int id = await _getUserID();

    _cc.createSyncgroup(
        await _mySettingsSyncgroupName(), util.tableNameSettings,
        prefix: util.settingsDataKeyFromUserID(id));
  }

  Future<String> _mySettingsSyncgroupName() async {
    return _cc.makeSyncgroupName(await _syncSettingsSuffix());
  }

  // Forward any player changes and game status signals to Croupier's logic.
  Future _onGameChange(String key, String value, bool duringScan) async {
    if (key.indexOf("/players") != -1) {
      if (this.updatePlayerFoundCallback != null) {
        String type = util.playerUpdateTypeFromPlayerKey(key);
        switch (type) {
          case "player_number":
            // Update the player number for this player.
            this.updatePlayerFoundCallback(key, value);
            break;
          case "settings_sg":
            // Join this player's settings syncgroup.
            _cc.joinSyncgroup(value);

            // Also, signal that this player has been found.
            this.updatePlayerFoundCallback(key, null);
            break;
          default:
            print("Unexpected key: $key with value $value");
            assert(false);
        }
      }
    } else if (key.indexOf("/status") != -1) {
      if (this.updateGameStatusCallback != null) {
        this.updateGameStatusCallback(key, value);
      }
    } else if (key.indexOf("/log") != -1) {
      if (this.updateGameLogCallback != null) {
        await this.updateGameLogCallback(key, value, duringScan);
      }
    }
  }

  Future<logic_game.GameStartData> createGameSyncgroup(
      String type, int gameID) async {
    print("Creating game syncgroup for $type and $gameID");
    sc.SyncbaseDatabase db = await _cc.createDatabase();
    sc.SyncbaseTable gameTable = await _cc.createTable(db, util.tableNameGames);

    // Watch all the data in the game.
    assert(_gameSubscription == null);
    _gameSubscription = await _cc.watchEverything(
        db, util.tableNameGames, util.syncgamePrefix(gameID), _onGameChange,
        sorter: (sc.WatchChange a, sc.WatchChange b) {
      return a.rowKey.compareTo(b.rowKey);
    });

    print("Now writing to some rows of $gameID");
    // Start up the table and write yourself as player 0.
    await gameTable.row(util.gameTypeKey(gameID)).put(UTF8.encode("$type"));

    int id = await _getUserID();
    await gameTable.row(util.gameOwnerKey(gameID)).put(UTF8.encode("$id"));
    await gameTable
        .row(util.playerSettingsKeyFromData(gameID, id))
        .put(UTF8.encode(await _mySettingsSyncgroupName()));

    logic_game.GameStartData gsd =
        new logic_game.GameStartData(type, 0, gameID, id);

    String sgName = _cc.makeSyncgroupName(util.syncgameSuffix("${gsd.gameID}"));

    await gameTable.row(util.gameSyncgroupKey(gameID)).put(UTF8.encode(sgName));

    await _cc.createSyncgroup(sgName, util.tableNameGames,
        prefix: util.syncgamePrefix(gameID));

    return gsd;
  }

  void quitGame() {
    if (_gameSubscription != null) {
      _gameSubscription.cancel();
      _gameSubscription = null;
    }
  }

  Future joinGameSyncgroup(String sgName, int gameID) async {
    print("Now joining game syncgroup at $sgName and $gameID");

    sc.SyncbaseDatabase db = await _cc.createDatabase();
    sc.SyncbaseTable gameTable = await _cc.createTable(db, util.tableNameGames);

    // Watch for the players in the game.
    _gameSubscription = await _cc.watchEverything(
        db, util.tableNameGames, util.syncgamePrefix(gameID), _onGameChange,
        sorter: (sc.WatchChange a, sc.WatchChange b) {
      return a.rowKey.compareTo(b.rowKey);
    });

    await _cc.joinSyncgroup(sgName);

    int id = await _getUserID();
    await gameTable
        .row(util.playerSettingsKeyFromData(gameID, id))
        .put(UTF8.encode(await _mySettingsSyncgroupName()));
  }

  Future setPlayerNumber(int gameID, int userID, int playerNumber) async {
    sc.SyncbaseDatabase db = await _cc.createDatabase();
    sc.SyncbaseTable gameTable = await _cc.createTable(db, util.tableNameGames);

    await gameTable
        .row(util.playerNumberKeyFromData(gameID, userID))
        .put(UTF8.encode("$playerNumber"));
  }

  Future setGameStatus(int gameID, String status) async {
    sc.SyncbaseDatabase db = await _cc.createDatabase();
    sc.SyncbaseTable gameTable = await _cc.createTable(db, util.tableNameGames);

    await gameTable.row(util.gameStatusKey(gameID)).put(UTF8.encode(status));
  }

  Future<String> getGameStatus(int gameID) async {
    sc.SyncbaseDatabase db = await _cc.createDatabase();
    sc.SyncbaseTable gameTable = await _cc.createTable(db, util.tableNameGames);

    return _tryReadData(gameTable, util.gameStatusKey(gameID));
  }

  Future<String> getGameSyncgroup(int gameID) async {
    sc.SyncbaseDatabase db = await _cc.createDatabase();
    sc.SyncbaseTable gameTable = await _cc.createTable(db, util.tableNameGames);
    return _tryReadData(gameTable, util.gameSyncgroupKey(gameID));
  }

  Future<logic_game.GameStartData> getGameStartData(int gameID) async {
    sc.SyncbaseDatabase db = await _cc.createDatabase();
    sc.SyncbaseTable gameTable = await _cc.createTable(db, util.tableNameGames);

    String owner = await _tryReadData(gameTable, util.gameOwnerKey(gameID));
    String type = await _tryReadData(gameTable, util.gameTypeKey(gameID));

    int id = await _getUserID();
    String playerNumber =
        await _tryReadData(gameTable, util.playerNumberKeyFromData(gameID, id));
    int pn = playerNumber != null ? int.parse(playerNumber) : null;

    return new logic_game.GameStartData(type, pn, gameID, int.parse(owner));
  }

  // TODO(alexfandrianto): It is possible that the more efficient way of
  // scanning is to do it for only short bursts. In that case, we should call
  // stopScanSettings a few seconds after starting it.

  // Someone who is creating a game should scan for players who wish to join.
  Future scanSettings() async {
    SettingsScanHandler ssh =
        new SettingsScanHandler(_cc, this.updateGamesCallback);
    return _cc.discoveryClient.scan(
        _discoveryGameAdKey,
        'v.InterfaceName="${util.discoveryInterfaceName}"',
        ssh.found,
        ssh.lost);
  }

  Future stopScanSettings() {
    return _cc.discoveryClient.stopScan(_discoveryGameAdKey);
  }

  // Someone who wants to join a game should advertise their presence.
  Future advertiseSettings(logic_game.GameStartData gsd) async {
    String settingsSuffix = await _syncSettingsSuffix();
    String gameSuffix = util.syncgameSuffix("${gsd.gameID}");
    return _cc.discoveryClient.advertise(
        _discoveryGameAdKey,
        DiscoveryClient.advertisementMaker(
            interfaceName: util.discoveryInterfaceName,
            attrs: <String, String>{
              util.syncgameSettingsAttr: _cc.makeSyncgroupName(settingsSuffix),
              util.syncgameGameStartDataAttr: gsd.toJSONString()
            },
            addrs: <String>[
              _cc.makeSyncgroupName(gameSuffix)
            ]));
  }

  Future stopAdvertiseSettings() {
    return _cc.discoveryClient.stopAdvertise(_discoveryGameAdKey);
  }

  Future<int> _getUserID() async {
    String result = await _tryReadData(tb, util.settingsPersonalKey);
    if (result == null) {
      return null;
    }
    return int.parse(result);
  }

  Future<String> _syncSettingsSuffix([int userID]) async {
    int id = userID;
    if (id == null) {
      id = await _getUserID();
    }

    return "${util.sgSuffix}-$id";
  }
}

// Manages found and lost settings advertisements.
// Upon finding a settings advertisement, you want to join the syncgroup that
// they're advertising.
class SettingsScanHandler {
  CroupierClient _cc;
  Map<String, String> settingsAddrs;
  Map<String, String> gameAddrs;
  util.KeyValueCallback updateGamesCallback;

  SettingsScanHandler(this._cc, this.updateGamesCallback) {
    settingsAddrs = new Map<String, String>();
    gameAddrs = new Map<String, String>();
  }

  void found(discovery.Update s) {
    util.log(
        "SettingsScanHandler Found ${s.id} ${s.interfaceName} ${s.addresses}");

    if (s.addresses.length == 1 && s.attributes != null) {
      // Note: Assumes 1 address and attributes for the game.
      String id = s.id.toString();
      settingsAddrs[id] = s.attributes[util.syncgameSettingsAttr];
      gameAddrs[id] = s.addresses[0];

      String gameSettingsJSON = s.attributes[util.syncgameGameStartDataAttr];
      updateGamesCallback(gameAddrs[id], gameSettingsJSON);

      _cc.joinSyncgroup(settingsAddrs[id]);
    } else {
      // An unexpected service was found. Who is advertising it?
      // https://github.com/vanadium/issues/issues/846
      util.log("Unexpected service found: ${s.toString()}");
    }
  }

  void lost(List<int> idList) {
    util.log("SettingsScanHandler Lost $idList");

    // TODO(alexfandrianto): Leave the syncgroup?
    // Looks like leave isn't actually implemented, so we can't do this.
    String id = idList.toString();
    String addr = gameAddrs[id];
    if (addr != null) {
      updateGamesCallback(addr, null);
    }
    settingsAddrs.remove(id);
    gameAddrs.remove(id);
  }
}
