using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using Newtonsoft.Json;
using TouchyTickets.Upgrades;

namespace TouchyTickets; 

public static class SaveHandler {

    public static readonly JsonSerializer Serializer = JsonSerializer.Create(new JsonSerializerSettings {
        TypeNameHandling = TypeNameHandling.Auto,
        Formatting = Formatting.Indented
    });
    private const int SaveVersion = 3;

    public static void Save(GameImpl game) {
        var file = SaveHandler.GetSaveFile(true);
        using var stream = new JsonTextWriter(file.CreateText());
        var data = new SaveData {
            SaveVersion = SaveHandler.SaveVersion,
            Tickets = game.Tickets,
            LastUpdate = game.LastUpdate,
            Map = game.Map,
            Stars = game.Stars,
            TimesRestarted = game.TimesRestarted,
            Upgrades = game.AppliedUpgrades.Select(u => u.Name).ToList(),
            TutorialStep = game.Tutorial.CurrentStep,
            PlayTime = game.PlayTime
        };
        SaveHandler.Serializer.Serialize(stream, data);
    }

    public static bool Load(GameImpl game) {
        var file = SaveHandler.GetSaveFile(false);
        if (!file.Exists)
            return false;
        SaveData data;
        using (var stream = new JsonTextReader(file.OpenText()))
            data = SaveHandler.Serializer.Deserialize<SaveData>(stream);

        game.Tickets = data.Tickets;
        game.LastUpdate = data.LastUpdate;
        game.Map = data.Map.Copy();
        game.Stars = data.Stars;
        game.TimesRestarted = data.TimesRestarted;
        game.AppliedUpgrades.Clear();
        foreach (var name in data.Upgrades)
            game.AppliedUpgrades.Add(Upgrade.Upgrades[name]);
        game.Tutorial.CurrentStep = data.TutorialStep;
        game.PlayTime = data.PlayTime;

        // version 1 had smaller maps
        if (data.SaveVersion <= 1) {
            game.Map = game.Map.Copy(20, 20);
            foreach (var upgrade in game.AppliedUpgrades.Intersect(Upgrade.MapSize))
                upgrade.OnApplied();
        }
        // new tutorial additions need to be forced
        if (data.SaveVersion <= 2) {
            if (game.Tutorial.CurrentStep > 4)
                game.Tutorial.CurrentStep = 4;
        }

        return true;
    }

    public static DirectoryInfo GetGameDirectory(bool create) {
        var path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        var dir = new DirectoryInfo(Path.Combine(path, "TouchyTickets"));
        if (!dir.Exists && create)
            dir.Create();
        return dir;
    }

    private static FileInfo GetSaveFile(bool create) {
        return new FileInfo(Path.Combine(SaveHandler.GetGameDirectory(create).FullName, "Save"));
    }

}

public class SaveData {

    public int SaveVersion;
    public BigInteger Tickets;
    public DateTime LastUpdate;
    public ParkMap Map;
    public int Stars;
    public int TimesRestarted;
    public List<string> Upgrades;
    public int TutorialStep;
    public TimeSpan PlayTime;

}