using Godot;

using Sfs3.Client.Core;
using Sfs3.Client.Requests;
using Sfs3.Client.Entities;
using System.Collections.Generic;

using System.Linq;
using System;

/**
 * Script attached to the main node in the scene.
 */
public partial class GameController : BaseController
{
    private bool runTimer;
    private float timer = 20f;

    //----------------------------------------------------------
    // UI elements
    //----------------------------------------------------------
    [ExportCategory("UI Settings")]

    [Export]
    public PopupDialog timeoutPanel;

    [Export]
    public ChatPanel chatPanel;

    //----------------------------------------------------------
    // Callback methods
    //----------------------------------------------------------
    #region
    public override void _Ready()
    {
        base._Ready();

        sfs = Global.GetSfsClient();
        
        // Add listener to send chat message when button is pressed in chat panel
        chatPanel.SendMessageAction = OnChatMessageSubmit;

        // Print system message
        chatPanel.PrintSystemMessage(String.Format("Game joined as {0}", sfs.MySelf.IsPlayer ? "player" : "spectator"));
        
        // Add SFS event listeners
        AddSmartFoxListeners();

        // If user is the first player in the Room, set a timeout
        // Having a timeout is usefult to suggest the user to leave the game if not yet started within some time
        // For example this could mean that the invited buddy refused the invitation, or the server couldn't locate other players to invite
        if (sfs.MySelf.IsPlayer && sfs.LastJoinedRoom.PlayerList.Count == 1)
            runTimer = true;
    }

    public override void _Process(double delta)
    {
        if (runTimer)
        {
            timer -= (float)delta;

            int timerInt = (int)Math.Round(timer, 0);

            if (timerInt == 0)
            {
                runTimer = false;
                timeoutPanel.Show();
            }
        }
    }

    public override void _ExitTree()
    {
        base._ExitTree();
        
        runTimer = false;
        chatPanel.Reset();
    }
    #endregion

    //----------------------------------------------------------
    // UI event listeners
    //----------------------------------------------------------
    #region
    public void OnLeaveGameButtonClick()
	{
		// Leave current game room
        sfs.Send(new LeaveRoomRequest());

        // Return to lobby scene
        GetTree().ChangeSceneToFile("scenes/Lobby.tscn");
	}

    public void OnChatMessageSubmit(string msg)
    {
        // Send public message to Room
        sfs.Send(new PublicMessageRequest(msg));
    }
    #endregion

    //----------------------------------------------------------
    // Helper methods
    //----------------------------------------------------------
    #region
    private void AddSmartFoxListeners()
    {
        sfs.AddEventListener(SFSEvent.PUBLIC_MESSAGE, OnPublicMessage);
        sfs.AddEventListener(SFSEvent.USER_ENTER_ROOM, OnUserEnterRoom);
        sfs.AddEventListener(SFSEvent.USER_EXIT_ROOM, OnUserExitRoom);
    }

    public override void RemoveSmartFoxListeners()
    {
        if (sfs != null)
        {
            sfs.RemoveEventListener(SFSEvent.PUBLIC_MESSAGE, OnPublicMessage);
            sfs.RemoveEventListener(SFSEvent.USER_ENTER_ROOM, OnUserEnterRoom);
            sfs.RemoveEventListener(SFSEvent.USER_EXIT_ROOM, OnUserExitRoom);
        }
    }
    #endregion

    //----------------------------------------------------------
    // SmartFoxServer event listeners
    //----------------------------------------------------------
    #region
    private void OnPublicMessage(ApiEvent evt)
    {
        User sender = (User) evt.Params[EventParam.Sender];
        string message = (string) evt.Params[EventParam.Message];

        // Display chat message
        chatPanel.PrintChatMessage(message, sender.Name, sender == sfs.MySelf, null);
    }

    private void OnUserEnterRoom(ApiEvent evt)
    {
        User user = (User)evt.Params[EventParam.User];
        Room room = (Room)evt.Params[EventParam.Room];

        // Display system message
        chatPanel.PrintSystemMessage("User " + user.Name + " joined this game as " + (user.IsPlayerInRoom(room) ? "player" : "spectator"));

        // Stop timeout
        if (user.IsPlayerInRoom(room))
        {
            // Stop timeout
            runTimer = false;

            // Hide leave panel
            timeoutPanel.Visible = false;
        }
    }

    private void OnUserExitRoom(ApiEvent evt)
    {
        User user = (User)evt.Params[EventParam.User];

        // Display system message
        if (user != sfs.MySelf)
            chatPanel.PrintSystemMessage("User " + user.Name + " left the game");
    }
    #endregion
}