// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "payload_update_cli.hpp"

#include "google3/host_commands.h"

#include "dbus_interface.hpp"
#include "parser.hpp"
#include "payload_update_common.hpp"

#include <iostream>

namespace google::hoth::tools
{
namespace payload_update
{
bool PayloadUpdateCLI::doUpdate()
{
    bool didReset = false;

    if (!args.hothId.empty())
    {
        if (args.reset != ResetMode::kNever)
        {
            std::optional<bool> res;
            try
            {
                res = dbus->getSpsPassthrough(args.hothId);
            }
            catch (const std::exception& e)
            {
                std::cerr << "Failed to get SPS passthrough status: "
                          << e.what() << std::endl;
            }
            if (!res && args.reset == ResetMode::kIgnore)
            {
                std::cerr << "Ignoring failed SPS passthrough status command"
                          << std::endl;
            }
            else if (res.value_or(true))
            {
                std::cerr << "Target did not report SPS passthrough disabled. "
                             "Attempting reset"
                          << std::endl;
                if (!dbus->setTargetResetOption(args.hothId,
                                                EC_TARGET_RESET_OPTION_SET))
                {
                    std::cerr << "Failed to put target into reset" << std::endl;
                    return false;
                }
                didReset = true;
            }
        }
        if (args.spsPassthrough && !dbus->setSpsPassthrough(args.hothId, false))
        {
            std::cerr << "Failed to disable SPS passthrough" << std::endl;
            return false;
        }
    }
    if (args.payloadUpdateMode == UpdateMode::kUpdateStaticWPRegions)
    {
        if (!dbus->sendStaticWPPayloadAndVerify(args.hothId,
                                                args.payloadFilename))
        {
            std::cerr << "Failed to send payload (STATIC & WP) and verify"
                      << std::endl;
            return false;
        }
    }
    else
    {
        if (!dbus->eraseStagingArea(args.hothId))
        {
            std::cerr << "Failed to erase staging area" << std::endl;
            return false;
        }
        if (!dbus->sendPayloadAndVerify(args.hothId, args.payloadFilename))
        {
            std::cerr << "Failed to send payload and verify" << std::endl;
            return false;
        }
    }
    if (!dbus->activatePayload(args.hothId))
    {
        std::cerr << "Faild to activate payload" << std::endl;
        return false;
    }

    if (args.hothId.empty() && !dbus->expectConfirmPayload())
    {
        std::cerr << "Failed to enable payload confirm" << std::endl;
        return false;
    }

    if (!args.hothId.empty())
    {
        if (args.spsPassthrough && !dbus->setSpsPassthrough(args.hothId, true))
        {
            std::cerr << "Failed to enable SPS passthrough" << std::endl;
            return false;
        }
        if (didReset)
        {
            if (!dbus->setTargetResetOption(args.hothId,
                                            EC_TARGET_RESET_OPTION_RELEASE))
            {
                std::cerr << "Failed to release target from reset" << std::endl;
                return false;
            }
        }
    }
    return true;
}

bool PayloadUpdateCLI::getOptions()
{
    return parser->parse(args);
}

bool PayloadUpdateCLI::execute()
{
    switch (args.command)
    {
        using enum payload_update::SubCommandType;
        case kVersion:
        {
            auto version =
                dbus->getPayloadVersion(args.hothId, args.versionType);
            if (version != std::nullopt)
            {
                std::cout << *version << std::endl;
                return true;
            }
            return false;
        }
        case kUpdate:
            return doUpdate();
        default:
            break;
    }
    return true;
}
} // namespace payload_update
} // namespace google::hoth::tools
