using System;
using System.Threading.Tasks;

using SteamKit2;
using SteamKit2.Internal;

//
// Sample 8: Unified Messages
//
// this sample introduces the usage of the unified service API
//
// unified services are a type of webapi service that can be accessed with either
// HTTP requests or through the Steam network
//
// in this case, this sample will demonstrate using the IPlayer unified service
// through the connection to steam
//

if ( args.Length < 2 )
{
    Console.WriteLine( "Sample8: No username and password specified!" );
    return;
}

// save our logon details
var user = args[0];
var pass = args[1];

// create our steamclient instance
var steamClient = new SteamClient();
// create the callback manager which will route callbacks to function calls
var manager = new CallbackManager( steamClient );

// get the steamuser handler, which is used for logging on after successfully connecting
var steamUser = steamClient.GetHandler<SteamUser>();

// get the steam unified messages handler, which is used for sending and receiving responses from the unified service api
var steamUnifiedMessages = steamClient.GetHandler<SteamUnifiedMessages>();

// we also want to create our local service interface, which will help us build requests to the unified api
var playerService = steamUnifiedMessages.CreateService<Player>();


// register a few callbacks we're interested in
// these are registered upon creation to a callback manager, which will then route the callbacks
// to the functions specified
manager.Subscribe<SteamClient.ConnectedCallback>( OnConnected );
manager.Subscribe<SteamClient.DisconnectedCallback>( OnDisconnected );

manager.Subscribe<SteamUser.LoggedOnCallback>( OnLoggedOn );
manager.Subscribe<SteamUser.LoggedOffCallback>( OnLoggedOff );

// subscribe to incoming messages from the GameNotificationsClient service
manager.SubscribeServiceNotification<GameNotificationsClient, CGameNotifications_OnNotificationsRequested_Notification>( OnGameStartedNotification );

var isRunning = true;

Console.WriteLine( "Connecting to Steam..." );

// initiate the connection
steamClient.Connect();

// create our callback handling loop
while ( isRunning )
{
    // in order for the callbacks to get routed, they need to be handled by the manager
    manager.RunWaitCallbacks( TimeSpan.FromSeconds( 1 ) );
}

void OnConnected( SteamClient.ConnectedCallback callback )
{
    Console.WriteLine( "Connected to Steam! Logging in '{0}'...", user );

    steamUser.LogOn( new SteamUser.LogOnDetails
    {
        Username = user,
        Password = pass,
    } );
}

void OnDisconnected( SteamClient.DisconnectedCallback callback )
{
    Console.WriteLine( "Disconnected from Steam" );

    isRunning = false;
}

async void OnLoggedOn( SteamUser.LoggedOnCallback callback )
{
    if ( callback.Result != EResult.OK )
    {
        if ( callback.Result == EResult.AccountLogonDenied )
        {
            // if we recieve AccountLogonDenied or one of it's flavors (AccountLogonDeniedNoMailSent, etc)
            // then the account we're logging into is SteamGuard protected
            // see sample 5 for how SteamGuard can be handled

            Console.WriteLine( "Unable to logon to Steam: This account is SteamGuard protected." );

            isRunning = false;
            return;
        }

        Console.WriteLine( "Unable to logon to Steam: {0} / {1}", callback.Result, callback.ExtendedResult );

        isRunning = false;
        return;
    }

    Console.WriteLine( "Successfully logged on!" );

    // now that we're logged onto Steam, lets query the IPlayer service for our badge levels

    // first, build our request object, these are autogenerated and can normally be found in the SteamKit2.Internal namespace
    CPlayer_GetGameBadgeLevels_Request req = new CPlayer_GetGameBadgeLevels_Request
    {
        // we want to know our 440 (TF2) badge level
        appid = 440,
    };

    // now lets send the request and await for the response
    var response = await playerService.GetGameBadgeLevels( req );

    // alternatively, the request can be made using SteamUnifiedMessages directly, but then you must build the service request name manually
    // the name format is in the form of <Service>.<Method>#<Version>
    response = await steamUnifiedMessages.SendMessage<CPlayer_GetGameBadgeLevels_Request, CPlayer_GetGameBadgeLevels_Response>( "Player.GetGameBadgeLevels#1", req );

    if ( response.Result != EResult.OK )
    {
        Console.WriteLine( $"Unified service request failed with {response.Result}" );
        return;
    }

    Console.WriteLine( $"Our player level is {response.Body.player_level}" );

    foreach ( var badge in response.Body.badges )
    {
        Console.WriteLine( $"Badge series {badge.series} is level {badge.level}" );
    }

    // now that we've completed our task, lets log off after a few seconds to receive possible notifications
    await Task.Delay( 10000 );
    steamUser.LogOff();
}

static void OnGameStartedNotification( SteamUnifiedMessages.ServiceMethodNotification<CGameNotifications_OnNotificationsRequested_Notification> notification )
{
    Console.WriteLine($"User with id {notification.Body.steamid} started the game:");
    Console.WriteLine(notification.Body.appid);
}

static void OnLoggedOff( SteamUser.LoggedOffCallback callback )
{
    Console.WriteLine( "Logged off of Steam: {0}", callback.Result );
}
