package funkin;

import funkin.Controls;
import flixel.FlxCamera;
import funkin.input.PreciseInputManager;
import flixel.input.actions.FlxActionInput;
import flixel.input.gamepad.FlxGamepad;
import flixel.util.FlxSignal;

// import ui.DeviceManager;
// import props.Player;
class PlayerSettings
{
  static public var numPlayers(default, null) = 0;
  static public var numAvatars(default, null) = 0;
  static public var player1(default, null):PlayerSettings;
  static public var player2(default, null):PlayerSettings;

  static public var onAvatarAdd(default, null) = new FlxTypedSignal<PlayerSettings->Void>();
  static public var onAvatarRemove(default, null) = new FlxTypedSignal<PlayerSettings->Void>();

  public var id(default, null):Int;

  public var controls(default, null):Controls;

  // public var avatar:Player;
  // public var camera(get, never):PlayCamera;

  function new(id:Int)
  {
    trace('loading player settings for id: $id');

    this.id = id;
    this.controls = new Controls('player$id', None);

    #if CLEAR_INPUT_SAVE
    FlxG.save.data.controls = null;
    FlxG.save.flush();
    #end

    var useDefault = true;
    var controlData = FlxG.save.data.controls;
    if (controlData != null)
    {
      var keyData:Dynamic = null;
      if (id == 0 && controlData.p1 != null && controlData.p1.keys != null) keyData = controlData.p1.keys;
      else if (id == 1 && controlData.p2 != null && controlData.p2.keys != null) keyData = controlData.p2.keys;

      if (keyData != null)
      {
        useDefault = false;
        trace("loaded key data: " + haxe.Json.stringify(keyData));
        controls.fromSaveData(keyData, Keys);
      }
    }

    if (useDefault)
    {
      trace("falling back to default control scheme");
      controls.setKeyboardScheme(Solo);
    }

    // Apply loaded settings.
    PreciseInputManager.instance.initializeKeys(controls);
  }

  function addGamepad(gamepad:FlxGamepad)
  {
    var useDefault = true;
    var controlData = FlxG.save.data.controls;
    if (controlData != null)
    {
      var padData:Dynamic = null;
      if (id == 0 && controlData.p1 != null && controlData.p1.pad != null) padData = controlData.p1.pad;
      else if (id == 1 && controlData.p2 != null && controlData.p2.pad != null) padData = controlData.p2.pad;

      if (padData != null)
      {
        useDefault = false;
        trace("loaded pad data: " + haxe.Json.stringify(padData));
        controls.addGamepadWithSaveData(gamepad.id, padData);
      }
    }

    if (useDefault) controls.addDefaultGamepad(gamepad.id);
  }

  public function saveControls()
  {
    if (FlxG.save.data.controls == null) FlxG.save.data.controls = {};

    var playerData:{?keys:Dynamic, ?pad:Dynamic}
    if (id == 0)
    {
      if (FlxG.save.data.controls.p1 == null) FlxG.save.data.controls.p1 = {};
      playerData = FlxG.save.data.controls.p1;
    }
    else
    {
      if (FlxG.save.data.controls.p2 == null) FlxG.save.data.controls.p2 = {};
      playerData = FlxG.save.data.controls.p2;
    }

    var keyData = controls.createSaveData(Keys);
    if (keyData != null)
    {
      playerData.keys = keyData;
      trace("saving key data: " + haxe.Json.stringify(keyData));
    }

    if (controls.gamepadsAdded.length > 0)
    {
      var padData = controls.createSaveData(Gamepad(controls.gamepadsAdded[0]));
      if (padData != null)
      {
        trace("saving pad data: " + haxe.Json.stringify(padData));
        playerData.pad = padData;
      }
    }

    FlxG.save.flush();
  }

  static public function init():Void
  {
    if (player1 == null)
    {
      player1 = new PlayerSettings(0);
      ++numPlayers;
    }

    FlxG.gamepads.deviceConnected.add(onGamepadAdded);

    var numGamepads = FlxG.gamepads.numActiveGamepads;
    for (i in 0...numGamepads)
    {
      var gamepad = FlxG.gamepads.getByID(i);
      if (gamepad != null) onGamepadAdded(gamepad);
    }

    // 	player1.controls.addDefaultGamepad(0);
    // }

    // if (numGamepads > 1)
    // {
    // 	if (player2 == null)
    // 	{
    // 		player2 = new PlayerSettings(1, None);
    // 		++numPlayers;
    // 	}

    // 	var gamepad = FlxG.gamepads.getByID(1);
    // 	if (gamepad == null)
    // 		throw 'Unexpected null gamepad. id:0';

    // 	player2.controls.addDefaultGamepad(1);
    // }

    // DeviceManager.init();
  }

  static function onGamepadAdded(gamepad:FlxGamepad)
  {
    player1.addGamepad(gamepad);
  }

  /*
    public function setKeyboardScheme(scheme)
    {
      controls.setKeyboardScheme(scheme);
    }

    static public function addAvatar(avatar:Player):PlayerSettings
    {
      var settings:PlayerSettings;

      if (player1 == null)
      {
        player1 = new PlayerSettings(0, Solo);
        ++numPlayers;
      }

      if (player1.avatar == null)
        settings = player1;
      else
      {
        if (player2 == null)
        {
          if (player1.controls.keyboardScheme.match(Duo(true)))
            player2 = new PlayerSettings(1, Duo(false));
          else
            player2 = new PlayerSettings(1, None);
          ++numPlayers;
        }

        if (player2.avatar == null)
          settings = player2;
        else
          throw throw 'Invalid number of players: ${numPlayers + 1}';
      }
      ++numAvatars;
      settings.avatar = avatar;
      avatar.settings = settings;

      splitCameras();

      onAvatarAdd.dispatch(settings);

      return settings;
    }

    static public function removeAvatar(avatar:Player):Void
    {
      var settings:PlayerSettings;

      if (player1 != null && player1.avatar == avatar)
        settings = player1;
      else if (player2 != null && player2.avatar == avatar)
      {
        settings = player2;
        if (player1.controls.keyboardScheme.match(Duo(_)))
          player1.setKeyboardScheme(Solo);
      }
      else
        throw "Cannot remove avatar that is not for a player";

      settings.avatar = null;
      while (settings.controls.gamepadsAdded.length > 0)
      {
        final id = settings.controls.gamepadsAdded.shift();
        settings.controls.removeGamepad(id);
        DeviceManager.releaseGamepad(FlxG.gamepads.getByID(id));
      }

      --numAvatars;

      splitCameras();

      onAvatarRemove.dispatch(avatar.settings);
    }

   */
  static public function reset()
  {
    player1 = null;
    player2 = null;
    numPlayers = 0;
  }
}