//
//  NostaleDataParser.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.Data.Abstractions;
using NosSmooth.Data.Abstractions.Language;
using NosSmooth.Data.NOSFiles.Files;
using NosSmooth.Data.NOSFiles.Options;
using NosSmooth.Data.NOSFiles.Parsers;
using NosSmooth.Data.NOSFiles.Readers;
using Remora.Results;
namespace NosSmooth.Data.NOSFiles;
/// 
/// Parser of NosTale .NOS files.
/// 
public class NostaleDataParser
{
    private readonly FileReader _fileReader;
    private readonly NostaleDataOptions _options;
    private readonly LanguageServiceOptions _languageOptions;
    private NostaleData? _parsed;
    /// 
    /// Initializes a new instance of the  class.
    /// 
    /// The file reader.
    /// The options.
    /// The language options.
    public NostaleDataParser
    (
        FileReader fileReader,
        IOptions options,
        IOptions languageOptions
    )
    {
        _fileReader = fileReader;
        _options = options.Value;
        _languageOptions = languageOptions.Value;
    }
    /// 
    /// Extract NosTale files from archives.
    /// 
    /// The path to the nostale data files.
    /// The languages to include.
    /// The nostale files.
    public Result GetFiles(string? path = null, params Language[] languages)
    {
        string datFilesPath = Path.Combine(path ?? _options.NostaleDataPath, _options.InfosFileName);
        string mapGridsFilesPath = Path.Combine(path ?? _options.NostaleDataPath, _options.MapGridsFileName);
        string languageFilesPath = Path.Combine(path ?? _options.NostaleDataPath, _options.LanguageFileName);
        var datFile = _fileReader.ReadFileSystemFile(datFilesPath);
        if (!datFile.IsSuccess)
        {
            return Result.FromError(datFile);
        }
        var mapGridsFile = _fileReader.ReadFileSystemFile(mapGridsFilesPath);
        if (!mapGridsFile.IsSuccess)
        {
            return Result.FromError(mapGridsFile);
        }
        var languageFiles = new Dictionary();
        foreach (var language in languages.Concat(_options.SupportedLanguages).Distinct())
        {
            var langString = language.ToString().ToUpper();
            var langPath = languageFilesPath.Replace("%lang%", langString);
            var languageFile = _fileReader.ReadFileSystemFile(langPath);
            if (!languageFile.IsSuccess)
            {
                return Result.FromError(languageFile);
            }
            languageFiles.Add(language, languageFile.Entity.Content);
        }
        return new NostaleFiles(languageFiles, datFile.Entity.Content, mapGridsFile.Entity.Content);
    }
    /// 
    /// Parse the nostale files.
    /// 
    /// The path to the files.
    /// The languages to parse.
    /// Parsed data or an error.
    public Result ParseFiles(string? path = null, params Language[] languages)
    {
        try
        {
            if (_parsed is not null)
            {
                return _parsed;
            }
            var filesResult = GetFiles(path, languages);
            if (!filesResult.IsSuccess)
            {
                return Result.FromError(filesResult);
            }
            var files = filesResult.Entity;
            var skillParser = new SkillParser();
            var skillsResult = skillParser.Parse(files);
            if (!skillsResult.IsSuccess)
            {
                return Result.FromError(skillsResult);
            }
            var mapParser = new MapParser();
            var mapsResult = mapParser.Parse(files);
            if (!mapsResult.IsSuccess)
            {
                return Result.FromError(mapsResult);
            }
            var itemParser = new ItemParser();
            var itemsResult = itemParser.Parse(files);
            if (!itemsResult.IsSuccess)
            {
                return Result.FromError(itemsResult);
            }
            var monsterParser = new MonsterParser();
            var monstersResult = monsterParser.Parse(files);
            if (!monstersResult.IsSuccess)
            {
                return Result.FromError(monstersResult);
            }
            var langParser = new LangParser();
            var translations
                = new Dictionary>>();
            foreach (var language in files.LanguageFiles.Keys)
            {
                var languageParseResult = langParser.Parse(files, language);
                if (!languageParseResult.IsSuccess)
                {
                    return Result.FromError(languageParseResult);
                }
                translations.Add(language, languageParseResult.Entity);
            }
            return _parsed = new NostaleData
            (
                translations,
                itemsResult.Entity,
                monstersResult.Entity,
                skillsResult.Entity,
                mapsResult.Entity
            );
        }
        catch (Exception e)
        {
            return e;
        }
    }
    /// 
    /// Create a language service from parsed files.
    /// 
    /// A language service or an error.
    public Result CreateLanguageService()
    {
        var parsed = ParseFiles();
        if (!parsed.IsSuccess)
        {
            return Result.FromError(parsed);
        }
        return new LanguageService(parsed.Entity.Translations, _languageOptions);
    }
    /// 
    /// Create an info service from parsed files.
    /// 
    /// An info service or an error.
    public Result CreateInfoService()
    {
        var parsed = ParseFiles();
        if (!parsed.IsSuccess)
        {
            return Result.FromError(parsed);
        }
        return new InfoService(parsed.Entity);
    }
}