using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using RpgRoller.Contracts;
using RpgRoller.Data;
using RpgRoller.Domain;

namespace RpgRoller.Services;

public sealed class GameService : IGameService
{
    public GameService(IDbContextFactory<RpgRollerDbContext> dbContextFactory, IPasswordHasher<UserAccount> passwordHasher, IDiceRoller diceRoller)
    {
        GameStateStore stateStore = new();
        GamePersistenceService persistenceService = new(dbContextFactory, stateStore);
        m_AuthService = new(stateStore, passwordHasher, persistenceService);
        m_CampaignService = new(stateStore, persistenceService);
        m_CharacterService = new(stateStore, persistenceService);
        m_RollService = new(stateStore, persistenceService, diceRoller);
        m_SkillService = new(stateStore, persistenceService);
        m_UserAdministrationService = new(stateStore, persistenceService);
        persistenceService.LoadStateFromDatabase();
        lock (stateStore.Gate)
        {
            stateStore.RebuildCampaignStateLocked();
        }
    }

    public IReadOnlyList<RulesetDefinition> GetRulesets()
    {
        return DiceRules.SupportedRulesets.Select(r => new RulesetDefinition(r.Id, r.Name, r.DiceSyntax)).ToArray();
    }

    public ServiceResult<UserSummary> Register(string username, string password, string displayName)
    {
        return m_AuthService.Register(username, password, displayName);
    }

    public ServiceResult<(UserSummary User, string SessionToken)> Login(string username, string password)
    {
        return m_AuthService.Login(username, password);
    }

    public void Logout(string sessionToken)
    {
        m_AuthService.Logout(sessionToken);
    }

    public UserSummary? GetUserBySession(string sessionToken)
    {
        return m_AuthService.GetUserBySession(sessionToken);
    }

    public ServiceResult<MeResponse> GetMe(string sessionToken)
    {
        return m_AuthService.GetMe(sessionToken);
    }

    public ServiceResult<CampaignSummary> CreateCampaign(string sessionToken, string name, string rulesetId)
    {
        return m_CampaignService.CreateCampaign(sessionToken, name, rulesetId);
    }

    public ServiceResult<IReadOnlyList<CampaignSummary>> GetCampaigns(string sessionToken)
    {
        return m_CampaignService.GetCampaigns(sessionToken);
    }

    public ServiceResult<IReadOnlyList<CampaignOption>> GetCharacterCampaignOptions(string sessionToken)
    {
        return m_CampaignService.GetCharacterCampaignOptions(sessionToken);
    }

    public ServiceResult<CampaignRoster> GetCampaign(string sessionToken, Guid campaignId)
    {
        return m_CampaignService.GetCampaign(sessionToken, campaignId);
    }

    public ServiceResult<bool> DeleteCampaign(string sessionToken, Guid campaignId)
    {
        return m_CampaignService.DeleteCampaign(sessionToken, campaignId);
    }

    public ServiceResult<IReadOnlyList<string>> GetUsernames(string sessionToken)
    {
        return m_UserAdministrationService.GetUsernames(sessionToken);
    }

    public ServiceResult<IReadOnlyList<AdminUserSummary>> GetUsers(string sessionToken)
    {
        return m_UserAdministrationService.GetUsers(sessionToken);
    }

    public ServiceResult<AdminUserSummary> UpdateUserRoles(string sessionToken, Guid userId, IReadOnlyList<string> roles)
    {
        return m_UserAdministrationService.UpdateUserRoles(sessionToken, userId, roles);
    }

    public ServiceResult<bool> DeleteUser(string sessionToken, Guid userId)
    {
        return m_UserAdministrationService.DeleteUser(sessionToken, userId);
    }

    public ServiceResult<CharacterSummary> CreateCharacter(string sessionToken, string name, Guid campaignId)
    {
        return m_CharacterService.CreateCharacter(sessionToken, name, campaignId);
    }

    public ServiceResult<CharacterSummary> UpdateCharacter(string sessionToken, Guid characterId, string name, Guid? campaignId, string? ownerUsername = null)
    {
        return m_CharacterService.UpdateCharacter(sessionToken, characterId, name, campaignId, ownerUsername);
    }

    public ServiceResult<bool> DeleteCharacter(string sessionToken, Guid characterId)
    {
        return m_CharacterService.DeleteCharacter(sessionToken, characterId);
    }

    public ServiceResult<bool> ActivateCharacter(string sessionToken, Guid characterId)
    {
        return m_CharacterService.ActivateCharacter(sessionToken, characterId);
    }

    public ServiceResult<IReadOnlyList<CharacterSummary>> GetOwnCharacters(string sessionToken)
    {
        return m_CharacterService.GetOwnCharacters(sessionToken);
    }

    public ServiceResult<SkillGroupSummary> CreateSkillGroup(string sessionToken, Guid characterId, string name, string diceRollDefinition, int wildDice, bool allowFumble, int? fumbleRange = null)
    {
        return m_SkillService.CreateSkillGroup(sessionToken, characterId, name, diceRollDefinition, wildDice, allowFumble, fumbleRange);
    }

    public ServiceResult<SkillGroupSummary> UpdateSkillGroup(string sessionToken, Guid skillGroupId, string name, string diceRollDefinition, int wildDice, bool allowFumble, int? fumbleRange = null)
    {
        return m_SkillService.UpdateSkillGroup(sessionToken, skillGroupId, name, diceRollDefinition, wildDice, allowFumble, fumbleRange);
    }

    public ServiceResult<bool> DeleteSkillGroup(string sessionToken, Guid skillGroupId)
    {
        return m_SkillService.DeleteSkillGroup(sessionToken, skillGroupId);
    }

    public ServiceResult<SkillSummary> CreateSkill(string sessionToken, Guid characterId, string name, string diceRollDefinition, int wildDice, bool allowFumble, Guid? skillGroupId = null, int? fumbleRange = null, bool rolemasterAutoRetry = false)
    {
        return m_SkillService.CreateSkill(sessionToken, characterId, name, diceRollDefinition, wildDice, allowFumble, skillGroupId, fumbleRange, rolemasterAutoRetry);
    }

    public ServiceResult<SkillSummary> UpdateSkill(string sessionToken, Guid skillId, string name, string diceRollDefinition, int wildDice, bool allowFumble, Guid? skillGroupId = null, int? fumbleRange = null, bool rolemasterAutoRetry = false)
    {
        return m_SkillService.UpdateSkill(sessionToken, skillId, name, diceRollDefinition, wildDice, allowFumble, skillGroupId, fumbleRange, rolemasterAutoRetry);
    }

    public ServiceResult<bool> DeleteSkill(string sessionToken, Guid skillId)
    {
        return m_SkillService.DeleteSkill(sessionToken, skillId);
    }

    public ServiceResult<CharacterSheet> GetCharacterSheet(string sessionToken, Guid characterId)
    {
        return m_SkillService.GetCharacterSheet(sessionToken, characterId);
    }

    public ServiceResult<RollResult> RollSkill(string sessionToken, Guid skillId, string visibility, int situationalModifier = 0)
    {
        return m_RollService.RollSkill(sessionToken, skillId, visibility, situationalModifier);
    }

    public ServiceResult<RollResult> RollCustom(string sessionToken, Guid characterId, string expression, string visibility)
    {
        return m_RollService.RollCustom(sessionToken, characterId, expression, visibility);
    }

    public ServiceResult<IReadOnlyList<CampaignLogEntry>> GetCampaignLog(string sessionToken, Guid campaignId)
    {
        return m_RollService.GetCampaignLog(sessionToken, campaignId);
    }

    public ServiceResult<CampaignLogPage> GetCampaignLogPage(string sessionToken, Guid campaignId, Guid? afterRollId = null, int? limit = null)
    {
        return m_RollService.GetCampaignLogPage(sessionToken, campaignId, afterRollId, limit);
    }

    public ServiceResult<CampaignRollDetail> GetRollDetail(string sessionToken, Guid rollId)
    {
        return m_RollService.GetRollDetail(sessionToken, rollId);
    }

    public ServiceResult<CampaignStateSnapshot> GetCampaignStateSnapshot(string sessionToken, Guid campaignId)
    {
        return m_RollService.GetCampaignStateSnapshot(sessionToken, campaignId);
    }

    private readonly GameAuthService m_AuthService;
    private readonly GameCampaignService m_CampaignService;
    private readonly GameCharacterService m_CharacterService;
    private readonly GameRollService m_RollService;
    private readonly GameSkillService m_SkillService;
    private readonly GameUserAdministrationService m_UserAdministrationService;
}