/*
 *
 *    Copyright (c) 2021 Project CHIP Authors
 *    Copyright (c) 2019 Google LLC.
 *    All rights reserved.
 *
 *    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 "AppTask.h"
#include "AppConfig.h"
#include "CHIPDeviceManager.h"
#include "DeviceCallbacks.h"
#include "LEDWidget.h"
#include "qrcodegen.h"
#include <app/server/OnboardingCodesUtil.h>
#include <app/util/attribute-storage.h>
#include <assert.h>
#include <platform/CHIPDeviceLayer.h>
#include <setup_payload/QRCodeSetupPayloadGenerator.h>
#include <setup_payload/SetupPayload.h>

#include <app/clusters/network-commissioning/network-commissioning.h>
#include <platform/ASR/NetworkCommissioningDriver.h>

#include "init_Matter.h"
#if CONFIG_ENABLE_CHIP_SHELL
#include "matter_shell.h"
#endif
#include <app-common/zap-generated/attributes/Accessors.h>

namespace {
lega_thread_t sAppTaskHandle;
} // namespace

LEDWidget lightLED;

using namespace ::chip;
using namespace ::chip::Credentials;
using namespace ::chip::DeviceManager;
using namespace ::chip::DeviceLayer;
using namespace ::chip::System;

AppTask AppTask::sAppTask;

namespace {
constexpr EndpointId kNetworkCommissioningEndpointMain      = 0;
constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE;

app::Clusters::NetworkCommissioning::Instance
    sWiFiNetworkCommissioningInstance(kNetworkCommissioningEndpointMain /* Endpoint Id */,
                                      &(NetworkCommissioning::ASRWiFiDriver::GetInstance()));
} // namespace

void NetWorkCommissioningInstInit()
{
    sWiFiNetworkCommissioningInstance.Init();

    // We only have network commissioning on endpoint 0.
    emberAfEndpointEnableDisable(kNetworkCommissioningEndpointSecondary, false);
}

static DeviceCallbacks EchoCallbacks;

CHIP_ERROR AppTask::StartAppTask()
{
    // Start App task.
    OSStatus result = lega_rtos_create_thread(&sAppTaskHandle, 2, APP_TASK_NAME, (lega_thread_function_t) AppTaskMain,
                                              APP_TASK_STACK_SIZE, (lega_thread_arg_t) this);
    return (result == kNoErr) ? CHIP_NO_ERROR : CHIP_APPLICATION_ERROR(0x02);
}

bool IsLightOn()
{
    EmberAfStatus status;
    bool on = true;
    status  = app::Clusters::OnOff::Attributes::OnOff::Get(1, &on);

    if (status != EMBER_ZCL_STATUS_SUCCESS)
    {
        ASR_LOG("Error Read OnOff Attribute 0x%02x\n", status);
    }

    return on != false;
}

uint8_t GetLightLevel()
{
    EmberAfStatus status;
    app::DataModel::Nullable<uint8_t> currentLevel;

    status = app::Clusters::LevelControl::Attributes::CurrentLevel::Get(1, currentLevel);

    if (status != EMBER_ZCL_STATUS_SUCCESS)
    {
        ASR_LOG("Error Read CurrentLevel Attribute 0x%02x\n", status);
        return -1;
    }

    if (currentLevel.IsNull())
    {
        ASR_LOG("Error currentLevel is null\n");
        return -1;
    }

    return currentLevel.Value();
}

void led_startup_status()
{
    uint8_t currentLevel;

    if (IsLightOn() == true)
    {
        currentLevel = GetLightLevel();
        lightLED.Set(1);
        lightLED.SetBrightness(currentLevel);
    }
}

void AppTask::AppTaskMain(void * pvParameter)
{
    ASR_LOG("App Task started");

    if (MatterInitializer::Init_Matter_Stack(MATTER_DEVICE_NAME) != CHIP_NO_ERROR)
        appError(CHIP_ERROR_INTERNAL);

    CHIPDeviceManager & deviceMgr = CHIPDeviceManager::GetInstance();

    if (deviceMgr.Init(&EchoCallbacks) != CHIP_NO_ERROR)
        appError(CHIP_ERROR_INTERNAL);

    if (MatterInitializer::Init_Matter_Server() != CHIP_NO_ERROR)
        appError(CHIP_ERROR_INTERNAL);

    NetWorkCommissioningInstInit();

    ASR_LOG("Current Firmware Version: %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING);

    ConfigurationMgr().LogDeviceConfig();

    // Print setup info
    PrintOnboardingCodes(chip::RendezvousInformationFlag(chip::RendezvousInformationFlag::kBLE));

#if (LIGHT_SELECT == LIGHT_SELECT_LED)
    lightLED.Init(LIGHT_LED); // embedded board light
#elif (LIGHT_SELECT == LIGHT_SELECT_RGB)
    lightLED.RGB_init();
#endif

    /* get led onoff status and level value */
    led_startup_status();
#if CONFIG_ENABLE_CHIP_SHELL
    RegisterLightCommands();
#endif
    /* Delete task */
    lega_rtos_delete_thread(NULL);
}
