﻿#include "stdafx.h"
#include "RegisterWin11ContextMenu.h"
#include "PathUtils.h"
#include "UnicodeUtils.h"
#include <winrt/Windows.Management.Deployment.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.ApplicationModel.h>
#include <future>

using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Management::Deployment;

#pragma comment(lib, "windowsapp.lib")

std::wstring RegisterWin11ContextMenuCommand::ReRegisterPackage()
{

    auto future = std::async([&]() {
        try
        {
            CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
            OnOutOfScope(CoUninitialize());
            PackageManager                                                    manager;

            // first unregister if already registered
            Collections::IIterable<winrt::Windows::ApplicationModel::Package> packages;
            try
            {
                packages = manager.FindPackagesForUser(L"");
            }
            catch (winrt::hresult_error const& ex)
            {
                std::wstring error = L"FindPackagesForUser failed (Errorcode: ";
                error += std::to_wstring(ex.code().value);
                error += L"):\n";
                error += ex.message();
                return error;
            }

            for (const auto& package : packages)
            {
                if (package.Id().Name() != L"3A48D7FC-AEE2-4CBC-91D1-0007951B8006")
                    continue;

                winrt::hstring fullName            = package.Id().FullName();
                auto           deploymentOperation = manager.RemovePackageAsync(fullName, RemovalOptions::None);
                auto           deployResult        = deploymentOperation.get();
                if (SUCCEEDED(deployResult.ExtendedErrorCode()))
                    break;

                // Undeployment failed
                std::wstring error = L"RemovePackageAsync failed (Errorcode: ";
                error += std::to_wstring(deployResult.ExtendedErrorCode());
                error += L"):\n";
                error += deployResult.ErrorText();
                return error;
            }

            // now register the package
            auto              appDir = CPathUtils::GetAppParentDirectory();
            Uri               externalUri(static_cast<LPCWSTR>(appDir));
            auto              packagePath = appDir + L"bin\\package.msix";
            Uri               packageUri(static_cast<LPCWSTR>(packagePath));
            AddPackageOptions options;
            options.ExternalLocationUri(externalUri);
            auto deploymentOperation = manager.AddPackageByUriAsync(packageUri, options);

            auto deployResult        = deploymentOperation.get();

            if (!SUCCEEDED(deployResult.ExtendedErrorCode()))
            {
                std::wstring error = L"AddPackageByUriAsync failed (Errorcode: ";
                error += std::to_wstring(deployResult.ExtendedErrorCode());
                error += L"):\n";
                error += deployResult.ErrorText();
                return error;
            }
        }
        catch (const winrt::hresult_error& ex)
        {
            std::wstring error = L"Caught winrt::hresult_error (Errorcode: ";
            error += std::to_wstring(ex.code().value);
            error += L"):\n";
            error += ex.message();
            return error;
        }
        catch (const std::exception& ex)
        {
            return CUnicodeUtils::StdGetUnicode(ex.what());
        }
        return std::wstring();
    });
    auto ret    = future.get();
    return ret;
}
