using Newtonsoft.Json.Linq;
using OF_DL.Enumerations;
using OF_DL.Models;
using OF_DL.Models.Config;
using OF_DL.Models.Entities.Users;
using OF_DL.Services;

namespace OF_DL.Tests.Services;

internal sealed class TempFolder : IDisposable
{
    public TempFolder()
    {
        Path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), "ofdl-tests", Guid.NewGuid().ToString("N"));
        Directory.CreateDirectory(Path);
    }

    public string Path { get; }

    public void Dispose()
    {
        try
        {
            Directory.Delete(Path, true);
        }
        catch
        {
            // ignored
        }
    }
}

internal sealed class ProgressRecorder : IProgressReporter
{
    public long Total { get; private set; }

    public void ReportProgress(long increment) => Total += increment;
}

internal sealed class FakeConfigService(Config config) : IConfigService
{
    public Config CurrentConfig { get; private set; } = config;

    public bool IsCliNonInteractive { get; } = config.NonInteractiveMode;

    public Task<bool> LoadConfigurationAsync(string[] args) => Task.FromResult(true);

    public Task SaveConfigurationAsync(string filePath = "config.conf") => Task.CompletedTask;

    public void UpdateConfig(Config newConfig) => CurrentConfig = newConfig;

    public List<(string Name, bool Value)> GetToggleableProperties() => [];

    public bool ApplyToggleableSelections(List<string> selectedNames) => false;
}

internal sealed class FakeDbService : IDbService
{
    public bool CheckDownloadedResult { get; init; }

    public long StoredFileSize { get; init; }

    public (string folder, long mediaId, string apiType, string directory, string filename, long size,
        bool downloaded, DateTime createdAt)? LastUpdateMedia { get; private set; }

    public Task UpdateMedia(string folder, long mediaId, string apiType, string directory, string filename,
        long size, bool downloaded, DateTime createdAt)
    {
        LastUpdateMedia = (folder, mediaId, apiType, directory, filename, size, downloaded, createdAt);
        return Task.CompletedTask;
    }

    public Task<long> GetStoredFileSize(string folder, long mediaId, string apiType) =>
        Task.FromResult(StoredFileSize);

    public Task<bool> CheckDownloaded(string folder, long mediaId, string apiType) =>
        Task.FromResult(CheckDownloadedResult);

    public Task AddMessage(string folder, long postId, string messageText, string price, bool isPaid,
        bool isArchived, DateTime createdAt, long userId) => throw new NotImplementedException();

    public Task AddPost(string folder, long postId, string messageText, string price, bool isPaid, bool isArchived,
        DateTime createdAt) => throw new NotImplementedException();

    public Task AddStory(string folder, long postId, string messageText, string price, bool isPaid, bool isArchived,
        DateTime createdAt) => throw new NotImplementedException();

    public Task CreateDb(string folder) => throw new NotImplementedException();

    public Task CreateUsersDb(Dictionary<string, long> users) => throw new NotImplementedException();

    public Task CheckUsername(KeyValuePair<string, long> user, string path) => throw new NotImplementedException();

    public Task AddMedia(string folder, long mediaId, long postId, string link, string? directory,
        string? filename, long? size, string apiType, string mediaType, bool preview, bool downloaded,
        DateTime? createdAt) => throw new NotImplementedException();

    public Task<DateTime?> GetMostRecentPostDate(string folder) => throw new NotImplementedException();
}

internal sealed class FakeApiService : IApiService
{
    public Dictionary<long, string>? MediaToReturn { get; init; }

    public DateTime LastModifiedToReturn { get; set; } = new(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc);

    public bool OfdlCalled { get; private set; }

    public bool CdmCalled { get; private set; }

    public Task<string> GetDrmMpdPssh(string mpdUrl, string policy, string signature, string kvp) =>
        Task.FromResult("pssh");

    public Task<DateTime> GetDrmMpdLastModified(string mpdUrl, string policy, string signature, string kvp) =>
        Task.FromResult(LastModifiedToReturn);

    public Task<string> GetDecryptionKeyOfdl(Dictionary<string, string> drmHeaders, string licenceUrl, string pssh)
    {
        OfdlCalled = true;
        return Task.FromResult("ofdl-key");
    }

    public Task<string> GetDecryptionKeyCdm(Dictionary<string, string> drmHeaders, string licenceUrl, string pssh)
    {
        CdmCalled = true;
        return Task.FromResult("cdm-key");
    }

    public Dictionary<string, string> GetDynamicHeaders(string path, string queryParam) =>
        new() { { "X-Test", "value" } };

    public Task<Dictionary<long, string>?> GetMedia(MediaType mediaType, string endpoint, string? username,
        string folder) => Task.FromResult(MediaToReturn);

    public Task<Dictionary<string, long>?> GetLists(string endpoint) => throw new NotImplementedException();

    public Task<List<string>?> GetListUsers(string endpoint) => throw new NotImplementedException();

    public Task<OF_DL.Models.Entities.Purchased.PaidPostCollection> GetPaidPosts(string endpoint, string folder,
        string username, List<long> paidPostIds, IStatusReporter statusReporter) =>
        throw new NotImplementedException();

    public Task<OF_DL.Models.Entities.Posts.PostCollection> GetPosts(string endpoint, string folder,
        List<long> paidPostIds, IStatusReporter statusReporter) => throw new NotImplementedException();

    public Task<OF_DL.Models.Entities.Posts.SinglePostCollection> GetPost(string endpoint, string folder) =>
        throw new NotImplementedException();

    public Task<OF_DL.Models.Entities.Streams.StreamsCollection> GetStreams(string endpoint, string folder,
        List<long> paidPostIds, IStatusReporter statusReporter) => throw new NotImplementedException();

    public Task<OF_DL.Models.Entities.Archived.ArchivedCollection> GetArchived(string endpoint, string folder,
        IStatusReporter statusReporter) => throw new NotImplementedException();

    public Task<OF_DL.Models.Entities.Messages.MessageCollection> GetMessages(string endpoint, string folder,
        IStatusReporter statusReporter) => throw new NotImplementedException();

    public Task<OF_DL.Models.Entities.Purchased.PaidMessageCollection> GetPaidMessages(string endpoint,
        string folder, string username, IStatusReporter statusReporter) => throw new NotImplementedException();

    public Task<OF_DL.Models.Entities.Purchased.SinglePaidMessageCollection> GetPaidMessage(string endpoint,
        string folder) => throw new NotImplementedException();

    public Task<Dictionary<string, long>> GetPurchasedTabUsers(string endpoint, Dictionary<string, long> users) =>
        throw new NotImplementedException();

    public Task<List<OF_DL.Models.Entities.Purchased.PurchasedTabCollection>> GetPurchasedTab(string endpoint,
        string folder, Dictionary<string, long> users) => throw new NotImplementedException();

    public Task<User?> GetUserInfo(string endpoint) =>
        throw new NotImplementedException();

    public Task<JObject?> GetUserInfoById(string endpoint) =>
        throw new NotImplementedException();

    public Task<Dictionary<string, long>?> GetActiveSubscriptions(string endpoint,
        bool includeRestrictedSubscriptions) => throw new NotImplementedException();

    public Task<Dictionary<string, long>?> GetExpiredSubscriptions(string endpoint,
        bool includeRestrictedSubscriptions) => throw new NotImplementedException();
}

internal sealed class FakeFileNameService : IFileNameService
{
    public Task<string> BuildFilename(string fileFormat, Dictionary<string, string> values) =>
        throw new NotImplementedException();

    public Task<Dictionary<string, string>> GetFilename(object info, object media, object author,
        List<string> selectedProperties, string username, Dictionary<string, long>? users = null) =>
        throw new NotImplementedException();
}

internal sealed class FakeAuthService : IAuthService
{
    public Auth? CurrentAuth { get; set; }

    public Task<bool> LoadFromFileAsync(string filePath = "auth.json") => throw new NotImplementedException();

    public Task<bool> LoadFromBrowserAsync() => throw new NotImplementedException();

    public Task SaveToFileAsync(string filePath = "auth.json") => throw new NotImplementedException();

    public void ValidateCookieString() => throw new NotImplementedException();

    public Task<User?> ValidateAuthAsync() => throw new NotImplementedException();

    public void Logout() => throw new NotImplementedException();
}
