//
//  Game.cs
//
//  Copyright (c) František Boháček. All rights reserved.
//  Licensed under the MIT license. See LICENSE file in the project root for full license information.
using Microsoft.Extensions.Options;
using NosSmooth.Core.Stateful;
using NosSmooth.Game.Data;
using NosSmooth.Game.Data.Characters;
using NosSmooth.Game.Data.Chat;
using NosSmooth.Game.Data.Inventory;
using NosSmooth.Game.Data.Maps;
using NosSmooth.Game.Data.Mates;
using NosSmooth.Game.Data.Raids;
using NosSmooth.Game.Data.Social;
namespace NosSmooth.Game;
/// 
/// Represents base nostale game class with the character, current map, friends and current raid.
/// 
public class Game : IStatefulEntity
{
    private readonly GameOptions _options;
    private Map? _currentMap;
    /// 
    /// Initializes a new instance of the  class.
    /// 
    /// The options for the game.
    public Game(IOptions options)
    {
        Semaphores = new GameSemaphores();
        _options = options.Value;
    }
    /// 
    /// Gets the game semaphores.
    /// 
    internal GameSemaphores Semaphores { get; }
    /// 
    /// Gets the playing character of the client.
    /// 
    public Character? Character { get; internal set; }
    /// 
    /// Gets the mates of the current character.
    /// 
    public Mates? Mates { get; internal set; }
    /// 
    /// Gets or sets the inventory of the character.
    /// 
    public Inventory? Inventory { get; internal set; }
    /// 
    /// Get or sets the friends of the character.
    /// 
    public IReadOnlyList? Friends { get; internal set; }
    /// 
    /// Gets or sets the skills of the player.
    /// 
    public Skills? Skills { get; internal set; }
    /// 
    /// Gets or sets the family.
    /// 
    public Family? Family { get; internal set; }
    /// 
    /// Gets or sets the group the player is in.
    /// 
    public Group? Group { get; internal set; }
    /// 
    /// Gets the current map of the client.
    /// 
    /// 
    /// Will be null until current map packet is received.
    /// 
    public Map? CurrentMap
    {
        get => _currentMap;
        internal set { _currentMap = value; }
    }
    /// 
    /// Gets the active raid the client is currently on.
    /// 
    /// 
    /// May be null if there is no raid in progress.
    /// 
    public Raid? CurrentRaid { get; internal set; }
    /// 
    /// Creates the mates if they are null, or updates the current mates.
    /// 
    /// The function for creating the mates.
    /// The function for updating the mates.
    /// Whether to release the semaphore used for changing the mates.
    /// The cancellation token for cancelling the operation.
    /// The updated mates.
    internal async Task CreateOrUpdateMatesAsync
    (
        Func create,
        Func update,
        bool releaseSemaphore = true,
        CancellationToken ct = default
    )
    {
        return await CreateOrUpdateAsync
        (
            GameSemaphoreType.Mates,
            () => Mates,
            s => Mates = s,
            create,
            update,
            releaseSemaphore,
            ct
        );
    }
    /// 
    /// Creates the skills if they are null, or updates the current skills.
    /// 
    /// The function for creating the skills.
    /// The function for updating the skills.
    /// Whether to release the semaphore used for changing the skills.
    /// The cancellation token for cancelling the operation.
    /// The updated skills.
    internal async Task CreateOrUpdateSkillsAsync
    (
        Func create,
        Func update,
        bool releaseSemaphore = true,
        CancellationToken ct = default
    )
    {
        return await CreateOrUpdateAsync
        (
            GameSemaphoreType.Skills,
            () => Skills,
            s => Skills = s,
            create,
            update,
            releaseSemaphore,
            ct
        );
    }
    /// 
    /// Creates the inventory if it is null, or updates the current inventory.
    /// 
    /// The function for creating the inventory.
    /// The function for updating the inventory.
    /// Whether to release the semaphore used for changing the inventory.
    /// The cancellation token for cancelling the operation.
    /// The updated inventory.
    internal async Task CreateOrUpdateInventoryAsync
    (
        Func create,
        Func update,
        bool releaseSemaphore = true,
        CancellationToken ct = default
    )
    {
        return await CreateOrUpdateAsync
        (
            GameSemaphoreType.Inventory,
            () => Inventory,
            i => Inventory = i,
            create,
            update,
            releaseSemaphore,
            ct
        );
    }
    /// 
    /// Creates the family if it is null, or updates the current family.
    /// 
    /// The function for creating the family.
    /// The function for updating the family.
    /// Whether to release the semaphore used for changing the family.
    /// The cancellation token for cancelling the operation.
    /// The updated family.
    internal async Task CreateOrUpdateFamilyAsync
    (
        Func create,
        Func update,
        bool releaseSemaphore = true,
        CancellationToken ct = default
    )
    {
        var family = await CreateOrUpdateAsync
        (
            GameSemaphoreType.Family,
            () => Family,
            c => Family = c,
            create,
            update,
            releaseSemaphore,
            ct
        );
        await CreateOrUpdateCharacterAsync
        (
            () => new Character
            {
                Family = family
            },
            c =>
            {
                c.Family = family;
                return c;
            },
            ct: ct
        );
        return family;
    }
    /// 
    /// Creates the friends if it is null, or updates the current friends.
    /// 
    /// The function for creating the friends.
    /// The function for updating the friends.
    /// Whether to release the semaphore used for changing the friends.
    /// The cancellation token for cancelling the operation.
    /// The updated friends.
    internal async Task?> CreateOrUpdateFriendsAsync
    (
        Func?> create,
        Func, IReadOnlyList?> update,
        bool releaseSemaphore = true,
        CancellationToken ct = default
    )
    {
        return await CreateOrUpdateAsync
        (
            GameSemaphoreType.Friends,
            () => Friends,
            c => Friends = c,
            create,
            update,
            releaseSemaphore,
            ct
        );
    }
    /// 
    /// Creates the group if it is null, or updates the current group.
    /// 
    /// The function for creating the group.
    /// The function for updating the group.
    /// Whether to release the semaphore used for changing the group.
    /// The cancellation token for cancelling the operation.
    /// The updated group.
    internal async Task CreateOrUpdateGroupAsync
    (
        Func create,
        Func update,
        bool releaseSemaphore = true,
        CancellationToken ct = default
    )
    {
        return await CreateOrUpdateAsync
        (
            GameSemaphoreType.Group,
            () => Group,
            c => Group = c,
            create,
            update,
            releaseSemaphore,
            ct
        );
    }
    /// 
    /// Creates the character if it is null, or updates the current character.
    /// 
    /// The function for creating the character.
    /// The function for updating the character.
    /// Whether to release the semaphore used for changing the character.
    /// The cancellation token for cancelling the operation.
    /// The updated character.
    internal async Task CreateOrUpdateCharacterAsync
    (
        Func create,
        Func update,
        bool releaseSemaphore = true,
        CancellationToken ct = default
    )
    {
        return await CreateOrUpdateAsync
        (
            GameSemaphoreType.Character,
            () => Character,
            c => Character = c,
            create,
            update,
            releaseSemaphore,
            ct
        );
    }
    /// 
    /// Creates the map if it is null, or updates the current map.
    /// 
    /// The function for creating the map.
    /// Whether to release the semaphore used for changing the map.
    /// The cancellation token for cancelling the operation.
    /// The updated character.
    internal async Task