/*
 * Copyright (C) 2025-2025 Huawei Device Co., Ltd.
 * 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 "antifraud_service.h"

#include <string>
#include "antifraud_adapter.h"
#include "anonymize_adapter.h"
#include "antifraud_cloud_service.h"
#include "common_type.h"
#include "hitrace/tracechain.h"
#include "telephony_log_wrapper.h"
#include "iservice_registry.h"

namespace OHOS {
namespace Telephony {
constexpr const int32_t MAX_VOICE_TEXT_LENGTH = 1000;
AntiFraudService::AntiFraudService()
{}

AntiFraudService::~AntiFraudService()
{}

void AntiFraudService::SetCallStatusManager(std::shared_ptr<CallStatusManager> callStatusManager)
{
    callStatusManagerPtr_ = callStatusManager;
}

std::shared_ptr<DataShare::DataShareHelper> AntiFraudService::CreateDataShareHelper(
    int32_t systemAbilityId, const char *uri)
{
    sptr<ISystemAbilityManager> saManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
    if (saManager == nullptr) {
        TELEPHONY_LOGE("CellularDataRdbHelper GetSystemAbilityManager failed.");
        return nullptr;
    }
    sptr<IRemoteObject> remoteObj = saManager->GetSystemAbility(systemAbilityId);
    if (remoteObj == nullptr) {
        TELEPHONY_LOGE("CellularDataRdbHelper GetSystemAbility Service Failed.");
        return nullptr;
    }
    return DataShare::DataShareHelper::Creator(remoteObj, uri);
}

bool AntiFraudService::IsSwitchOn(const std::string switchName)
{
    auto settingHelper = CreateDataShareHelper(TELEPHONY_CALL_MANAGER_SYS_ABILITY_ID,
        USER_SETTINGSDATA_URI.c_str());
    if (settingHelper == nullptr) {
        TELEPHONY_LOGE("settingHelper is null");
        return false;
    }

    DataShare::DataSharePredicates predicates;
    std::vector<std::string> columns;
    std::string keyword = "KEYWORD";
    predicates.EqualTo(keyword, switchName);
    Uri userStttingsDataUri(USER_SETTINGSDATA_URI);
    auto result = settingHelper->Query(userStttingsDataUri, predicates, columns);
    if (result == nullptr) {
        TELEPHONY_LOGE("setting DB: query error");
        settingHelper->Release();
        return false;
    }

    result->GoToFirstRow();
    int32_t columnIndex;
    std::string resultValue;
    std::string valueStr = "VALUE";
    result->GetColumnIndex(valueStr, columnIndex);
    result->GetString(columnIndex, resultValue);
    result->Close();
    settingHelper->Release();
    if (resultValue.empty()) {
        if (switchName == ANTIFRAUD_CONTACTS_ENABLED_VOICE || switchName == ANTIFRAUD_CONTACTS_ENABLED_VIDEO) {
            return true;
        }
        return false;
    }

    TELEPHONY_LOGI("Antifraud switch: %{public}s query end, the result value is %{public}s",
        switchName.c_str(), resultValue.c_str());
    if (resultValue == "1" || resultValue == "true") {
        return true;
    } else {
        return false;
    }
}

bool AntiFraudService::IsAntiFraudSwitchOn(const VideoStateType videoStateType)
{
    if (videoStateType == VideoStateType::TYPE_VIDEO) {
        return IsSwitchOn(ANTIFRAUD_SWITCH_VIDEO);
    }
    return IsSwitchOn(ANTIFRAUD_SWITCH_VOICE);
}

bool AntiFraudService::IsAntiFraudContactsEnabled(const VideoStateType videoStateType)
{
    if (videoStateType == VideoStateType::TYPE_VIDEO) {
        return IsSwitchOn(ANTIFRAUD_CONTACTS_ENABLED_VIDEO);
    }
    return IsSwitchOn(ANTIFRAUD_CONTACTS_ENABLED_VOICE);
}

bool AntiFraudService::IsUserImprovementPlanSwitchOn()
{
    return IsSwitchOn(USER_IMPROPLAN_SWITCH);
}

void AntiFraudService::InitParams()
{
    fraudDetectText_ = "";
    antiFraudState_ = static_cast<int32_t>(AntiFraudState::ANTIFRAUD_STATE_DEFAULT);
}

int32_t AntiFraudService::GetStoppedSlotId()
{
    std::lock_guard<ffrt::mutex> lock(mutex_);
    return stoppedSlotId_;
}
 
int32_t AntiFraudService::GetStoppedIndex()
{
    std::lock_guard<ffrt::mutex> lock(mutex_);
    return stoppedIndex_;
}
 
void AntiFraudService::SetStoppedSlotId(int32_t slotId)
{
    std::lock_guard<ffrt::mutex> lock(mutex_);
    stoppedSlotId_ = slotId;
}
 
void AntiFraudService::SetStoppedIndex(int32_t index)
{
    std::lock_guard<ffrt::mutex> lock(mutex_);
    stoppedIndex_ = index;
}

void AntiFraudService::RecordDetectResult(const OHOS::AntiFraudService::StartDetectionResult &antiFraudResult,
    std::string resultPhoneNum, int32_t resultSlotId, int32_t resultIndex)
{
    if (GetStoppedSlotId() == resultSlotId && GetStoppedIndex() == resultIndex) {
        TELEPHONY_LOGI("detect stopped, no need to record result");
        SetStoppedSlotId(-1);
        SetStoppedIndex(-1);
        return;
    }

    std::lock_guard<ffrt::mutex> lock(fraudMutex_);
    antiFraudResultExt_.isVoiceSemanticFraud = antiFraudResult.voiceDetectionResult.result;
    antiFraudResultExt_.isSpeechSynthesisFraud = antiFraudResult.speechSynthesisResult.result;
    antiFraudResultExt_.speechSynthesisProb = antiFraudResult.speechSynthesisResult.pvalue;
    antiFraudResultExt_.isXoipFraud = antiFraudResult.voipCallTransferResult.result;
    if (!antiFraudResult.voiceDetectionResult.voiceText.empty() &&
        antiFraudResult.voiceDetectionResult.voiceText.length() <= MAX_VOICE_TEXT_LENGTH) {
        fraudDetectText_ = antiFraudResult.voiceDetectionResult.voiceText;
    }

    if (antiFraudResultExt_.isVoiceSemanticFraud || antiFraudResultExt_.isSpeechSynthesisFraud ||
        antiFraudResultExt_.isXoipFraud) {
        TELEPHONY_LOGI("AntiFraud detect finish, is fraud call");
        antiFraudState_ = static_cast<int32_t>(AntiFraudState::ANTIFRAUD_STATE_RISK);
    } else {
        TELEPHONY_LOGI("AntiFraud detect finish, is not fraud call");
        antiFraudState_ = static_cast<int32_t>(AntiFraudState::ANTIFRAUD_STATE_NOT_RISK_OR_STOPPED);
    }
    if (callStatusManagerPtr_ != nullptr) {
        callStatusManagerPtr_->TriggerAntiFraud(antiFraudState_, antiFraudResultExt_);
    }

    if (antiFraudResultExt_.isVoiceSemanticFraud && IsUserImprovementPlanSwitchOn()) {
        TELEPHONY_LOGI("text reported to the cloud after anonymize");
        int ret = AnonymizeText();
        if (ret != 0) {
            TELEPHONY_LOGE("Anonymize text fail");
            return;
        }
        OHOS::AntiFraudService::AntiFraudResult fraudResult = antiFraudResult.voiceDetectionResult;
        std::make_shared<AntiFraudCloudService>(resultPhoneNum)->UploadPostRequest(fraudResult);
    }
}

int32_t AntiFraudService::CheckAntiFraudService(const OHOS::AntiFraudService::AfsDetectType &detectType)
{
    auto antiFraudAdapter = DelayedSingleton<AntiFraudAdapter>::GetInstance();
    int32_t antiFraudErrCode = antiFraudAdapter->AntiFraudDetectCheck(detectType);
    if (antiFraudErrCode != 0) {
        TELEPHONY_LOGE("Check AntiFraud, no need to detect, ErrCode:%{public}d", antiFraudErrCode);
        return antiFraudErrCode;
    }
    return 0;
}

int32_t AntiFraudService::StartAntiFraudService(const std::string &phoneNum, int32_t slotId, int32_t index,
    const OHOS::AntiFraudService::AfsDetectType &detectType)
{
    int32_t antiFraudErrCode = CheckAntiFraudService(detectType);
    if (antiFraudErrCode != 0) {
        return antiFraudErrCode;
    }
    if (callStatusManagerPtr_ != nullptr) {
        if (callStatusManagerPtr_->GetAntiFraudSlotId() != slotId ||
            callStatusManagerPtr_->GetAntiFraudIndex() != index) {
            TELEPHONY_LOGI("call ending, no need to antifraud detect");
            return -1;
        }
    }
    OHOS::HiviewDFX::HiTraceId chainId = OHOS::HiviewDFX::HiTraceChain::GetId();
    if (!chainId.IsValid()) {
        chainId =
            OHOS::HiviewDFX::HiTraceChain::Begin("StartAntiFraudService", HiTraceFlag::HITRACE_FLAG_INCLUDE_ASYNC);
    }
    auto antiFraudAdapter = DelayedSingleton<AntiFraudAdapter>::GetInstance();
    auto listener = std::make_shared<AntiFraudStartDetectResListenerImpl>(phoneNum, slotId, index);
    antiFraudErrCode = antiFraudAdapter->AntiFraudStartDetect(listener, detectType);
    if (antiFraudErrCode != 0) {
        TELEPHONY_LOGE("AntiFraudStartDetect failed, ErrCode=%{public}d", antiFraudErrCode);
        return antiFraudErrCode;
    }
    TELEPHONY_LOGI("AntiFraud begin detect, slotId=%{public}d, index=%{public}d", slotId, index);
    std::lock_guard<ffrt::mutex> lock(fraudMutex_);
    antiFraudState_ = static_cast<int32_t>(AntiFraudState::ANTIFRAUD_STATE_STARTED);
    if (callStatusManagerPtr_ != nullptr) {
        callStatusManagerPtr_->TriggerAntiFraud(antiFraudState_, antiFraudResultExt_);
    }
    InitParams();
    return 0;
}

void AntiFraudService::UpdateVideoState(VideoStateType priorVideoState, VideoStateType nextVideoState)
{
    if (priorVideoState == VideoStateType::TYPE_VOICE && nextVideoState == VideoStateType::TYPE_VIDEO) {
        OHOS::AntiFraudService::AfsDetectType detectType(
            OHOS::AntiFraudService::ANTIFRAUD_DETECT_TYPE_XOIP_TRANSFER, false, "", 0);
        StopAntiFraudDetectByType(detectType);
    }
}

int32_t AntiFraudService::StopAntiFraudService(int32_t slotId, int32_t index)
{
    auto antiFraudAdapter = DelayedSingleton<AntiFraudAdapter>::GetInstance();
    int32_t antiFraudErrCode = antiFraudAdapter->StopAntiFraud();
    if (antiFraudErrCode != 0) {
        TELEPHONY_LOGE("Stop AntiFraud failed, ErrCode=%{public}d", antiFraudErrCode);
        return antiFraudErrCode;
    }
    TELEPHONY_LOGI("AntiFraud stop detect, slotId=%{public}d, index=%{public}d", slotId, index);
    SetStoppedSlotId(slotId);
    SetStoppedIndex(index);
    return 0;
}

int32_t AntiFraudService::StopAntiFraudDetectByType(const OHOS::AntiFraudService::AfsDetectType &detectType)
{
    auto antiFraudAdapter = DelayedSingleton<AntiFraudAdapter>::GetInstance();
    if (antiFraudAdapter == nullptr) {
        return -1;
    }
    int32_t antiFraudErrCode = antiFraudAdapter->StopAntiFraudByType(detectType);
    if (antiFraudErrCode != 0) {
        TELEPHONY_LOGE("Stop AntiFraud by type failed, ErrCode=%{public}d", antiFraudErrCode);
        return antiFraudErrCode;
    }
    TELEPHONY_LOGI("AntiFraud stop detect by type, type=%{public}u", detectType.type_);
    return 0;
}

void AntiFraudService::AntiFraudStartDetectResListenerImpl::HandleAntiFraudStartDetectRes(
    const OHOS::AntiFraudService::StartDetectionResult &startDetectionResult)
{
    TELEPHONY_LOGI(
        "HandleAntiFraudStartDetectRes: voiceDetectionResult=%{public}d, speechSynthesisResult=%{public}d, "
        "voipCallTransferResult=%{public}d, slotId=%{public}d, index=%{public}d",
        startDetectionResult.voiceDetectionResult.result, startDetectionResult.speechSynthesisResult.result,
        startDetectionResult.voipCallTransferResult.result, slotId_, index_);
    auto antiFraudService = DelayedSingleton<AntiFraudService>::GetInstance();
    if (antiFraudService != nullptr) {
        antiFraudService->RecordDetectResult(startDetectionResult, phoneNum_, slotId_, index_);
    }
}

void AntiFraudService::AddRuleToConfig(const std::string rulesName, void *config)
{
    DIA_String key;
    std::string skey = "SELECT_RULE";
    key.data = skey.data();
    key.dataLength = SELECT_RULE_LENGTH;
    DIA_Rule rule;
    std::string rName = rulesName;
    rule.ruleName = rName.data();
    if ((rName == "CHINA_RESIDENT_PASSPORT") || (rName == "PERMIT_HM_TO_LAND") ||
        (rName == "PERMIT_TW_TO_LAND") || (rName == "POLICE_OFFICER_CARD")) {
        rule.isOpenKeywords = true;
    }
    auto anonymizeAdapter = DelayedSingleton<AnonymizeAdapter>::GetInstance();
    int ret = anonymizeAdapter->SetRule(config, &key, &rule);
    if (ret != 0) {
        TELEPHONY_LOGE("AddRuleToConfig fail, rulename=%{public}s", rulesName.c_str());
    }
}

int AntiFraudService::AnonymizeText()
{
    void *config = nullptr;
    auto anonymizeAdapter = DelayedSingleton<AnonymizeAdapter>::GetInstance();
    int ret = anonymizeAdapter->InitConfig(&config);
    if (ret != 0) {
        TELEPHONY_LOGE("InitConfig fail");
        return ret;
    }
    AddRuleToConfig("PRC", config);
    AddRuleToConfig("CHINA_RESIDENT_PASSPORT", config);
    AddRuleToConfig("MILITARY_IDENTITY_CARD_NUMBER", config);
    AddRuleToConfig("BANK_CARD_NUMBER", config);
    AddRuleToConfig("PERMIT_LAND_TO_HM", config);
    AddRuleToConfig("PERMIT_LAND_TO_TW", config);
    AddRuleToConfig("PERMIT_HM_TO_LAND", config);
    AddRuleToConfig("PERMIT_TW_TO_LAND", config);
    AddRuleToConfig("BIRTH_CERTIFICATE", config);
    AddRuleToConfig("SEAFARER_PASSPORT", config);
    AddRuleToConfig("POLICE_OFFICER_CARD", config);

    void *assistant = nullptr;
    ret = anonymizeAdapter->CreateAnonymize(config, &assistant);
    if (ret != 0) {
        TELEPHONY_LOGE("CreateAnonymize fail");
        return ret;
    }

    DIA_String input;
    std::string fraudDetectText = fraudDetectText_;
    input.data = fraudDetectText.data();
    input.dataLength = strlen(input.data);
    DIA_String *output = nullptr;
    ret = anonymizeAdapter->IdentifyAnonymize(assistant, &input, &output);
    if (ret != 0) {
        TELEPHONY_LOGE("IdentifyAnonymize fail");
        return ret;
    } else {
        fraudDetectText_ = (std::string)output->data;
    }
    anonymizeAdapter->ReleaseConfig(&config);
    anonymizeAdapter->ReleaseAnonymize(&assistant);
    anonymizeAdapter->ReleaseOutputData(&output);
    return 0;
}
}
}