package org.wfc.user.api.omada;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.wfc.common.core.constant.WifiConstants;
import org.wfc.common.core.utils.ResponseUtils;
import org.wfc.omada.api.client.OmadaClientApi;
import org.wfc.omada.api.client.model.ClientInfo;
import org.wfc.omada.api.client.model.ClientRateLimitSetting;
import org.wfc.omada.api.client.model.CustomRateLimitEntity;
import org.wfc.omada.api.client.model.OperationResponseClientGridVoClientInfo;
import org.wfc.omada.api.client.model.OperationResponseWithoutResult;
import org.wfc.omada.api.hotspot.OmadaAuthorizedClientApi;
import org.wfc.omada.api.sitesetting.OmadaProfilesApi;
import org.wfc.omada.api.sitesetting.model.CreateRateLimitProfileOpenApiVo;
import org.wfc.omada.api.sitesetting.model.OperationResponseListRateLimitProfileOpenApiVo;
import org.wfc.omada.api.sitesetting.model.RateLimitProfileOpenApiVo;
import org.wfc.user.api.omada.domain.dto.ClientRateLimitSettingDto;

import java.math.RoundingMode;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * @description: Omada API
 * @author: cyc
 * @since: 2024-12-30
 */
@Slf4j
public class OmadaWifiApi extends AbstractOmadaWifiApi {

    @Autowired
    private OmadaAuthorizedClientApi omadaAuthorizedClientApi;

    @Autowired
    private OmadaClientApi omadaClientApi;

    @Autowired
    private OmadaProfilesApi omadaProfilesApi;

    private static final int KBPS_LIMIT_MAX = 1048576;
    private static final int MBPS_LIMIT_MAX = 1024;

    @Override
    public boolean authClient(String siteId, String clientMac) {
        ResponseEntity<OperationResponseClientGridVoClientInfo> activeClientsResponse = omadaClientApi.getGridActiveClients(siteId, 1, 1000, clientMac);
        if (ObjectUtil.isNotNull(activeClientsResponse.getBody())) {
            if (!ResponseUtils.isSuccessResponse(activeClientsResponse.getBody().getErrorCode(), activeClientsResponse.getBody().getMsg())) {
                return false;
            }
            // 查client是否未授权
            Optional<ClientInfo> unAuthClientOptional = activeClientsResponse.getBody().getResult().getData().stream().filter(c -> c.getMac().equals(clientMac) && c.getAuthStatus() != WifiConstants.AUTH_STATUS_AUTHORIZED).findFirst();
            if (!unAuthClientOptional.isPresent()) {
                return false;
            }
            ResponseEntity<org.wfc.omada.api.hotspot.model.OperationResponseWithoutResult> response = omadaAuthorizedClientApi.authClient(siteId, clientMac);
            if (ObjectUtil.isNotNull(response.getBody())) {
                if (response.getBody().getErrorCode() == WifiConstants.ERROR_CODE_SUCCESS) {
                    log.info("authClient success,siteId={},clientMac={},errorCode={}, msg={}", siteId, clientMac, response.getBody().getErrorCode(), response.getBody().getMsg());
                    // 授权成功后reconnect, 切割出pending的流量
                    reconnectClient(siteId, clientMac);
                    return true;
                } else {
                    log.error("authClient error,siteId={},clientMac={},errorCode={}, msg={}", siteId, clientMac, response.getBody().getErrorCode(), response.getBody().getMsg());
                    return false;
                }
            }
        }
        return false;
    }

    @Override
    public boolean cancelAuthClient(String siteId, String clientMac) {
        ResponseEntity<org.wfc.omada.api.hotspot.model.OperationResponseWithoutResult> response = omadaAuthorizedClientApi.cancelAuthClient(siteId, clientMac);
        if (ObjectUtil.isNotNull(response.getBody())) {
            if (response.getBody().getErrorCode() == WifiConstants.ERROR_CODE_SUCCESS) {
                log.info("cancelAuthClient success,siteId={},clientMac={},errorCode={}, msg={}", siteId, clientMac, response.getBody().getErrorCode(), response.getBody().getMsg());
            } else {
                log.error("cancelAuthClient error,siteId={},clientMac={},errorCode={}, msg={}", siteId, clientMac, response.getBody().getErrorCode(), response.getBody().getMsg());
            }
        }
        return true;
    }

    @Override
    public boolean reconnectClient(String siteId, String clientMac) {
        ResponseEntity<OperationResponseWithoutResult> response = omadaClientApi.reconnectClient(siteId, clientMac);
        if (ObjectUtil.isNotNull(response.getBody())) {
            if (response.getBody().getErrorCode() == WifiConstants.ERROR_CODE_SUCCESS) {
                log.info("reconnectClient success,siteId={},clientMac={},errorCode={}, msg={}", siteId, clientMac, response.getBody().getErrorCode(), response.getBody().getMsg());
            } else {
                log.error("reconnectClient error,siteId={},clientMac={},errorCode={}, msg={}", siteId, clientMac, response.getBody().getErrorCode(), response.getBody().getMsg());
            }
        }
        return false;
    }

    @Override
    public boolean updateClientRateLimitSetting(String siteId, String clientMac, ClientRateLimitSettingDto settingDto) {
        initRateLimitSettingDto(settingDto);
        ClientRateLimitSetting clientRateLimitSetting = new ClientRateLimitSetting();
        if (settingDto.getRateLimitEnable() && ((settingDto.getUpLimitEnable() && settingDto.getUpLimit() > KBPS_LIMIT_MAX)
                || (settingDto.getDownLimitEnable() && settingDto.getDownLimit() > KBPS_LIMIT_MAX))) {
            // 大于1024Mbps走Profile限速
            Optional<RateLimitProfileOpenApiVo> rateLimitOptional = getRateLimitByProfile(siteId, settingDto);
            String profileId = null;
            if (rateLimitOptional.isPresent()) {
                profileId = rateLimitOptional.get().getProfileId();
            } else {
                CreateRateLimitProfileOpenApiVo newRateLimit = new CreateRateLimitProfileOpenApiVo();
                newRateLimit.setName(UUID.randomUUID().toString());
                newRateLimit.setDownLimitEnable(settingDto.getDownLimitEnable());
                newRateLimit.setDownLimit(settingDto.getDownLimit());
                newRateLimit.setUpLimitEnable(settingDto.getUpLimitEnable());
                newRateLimit.setUpLimit(settingDto.getUpLimit());
                omadaProfilesApi.createRateLimitProfile(siteId, newRateLimit);
                Optional<RateLimitProfileOpenApiVo> newRateLimitOptional = getRateLimitByProfile(siteId, settingDto);
                if (newRateLimitOptional.isPresent()) {
                    profileId = newRateLimitOptional.get().getProfileId();
                }
            }
            if (profileId == null) {
                return false;
            }
            clientRateLimitSetting.setMode(1);
            clientRateLimitSetting.setRateLimitProfileId(profileId);
        } else {
            // 否则走Custom限速
            clientRateLimitSetting.setMode(0);
            CustomRateLimitEntity custom = new CustomRateLimitEntity();
            if (!settingDto.getRateLimitEnable()) {
                custom.setDownEnable(false);
                custom.setUpEnable(false);
                custom.setDownUnit(1);
                custom.setDownLimit(1);
                custom.setUpUnit(1);
                custom.setUpLimit(1);
            } else {
                custom.setDownEnable(settingDto.getDownLimitEnable());
                if (settingDto.getDownLimitEnable() && settingDto.getDownLimit() > MBPS_LIMIT_MAX) {
                    // Down Mbps
                    custom.setDownUnit(2);
                    double downLimitDouble = NumberUtil.div(settingDto.getDownLimit().intValue(), MBPS_LIMIT_MAX, 0, RoundingMode.HALF_UP);
                    custom.setDownLimit((int) downLimitDouble);
                } else if (settingDto.getDownLimitEnable()) {
                    // Down Kbps
                    custom.setDownUnit(1);
                    custom.setDownLimit(settingDto.getDownLimit().intValue());
                }
                custom.setUpEnable(settingDto.getUpLimitEnable());
                if (settingDto.getUpLimitEnable() && settingDto.getUpLimit() > MBPS_LIMIT_MAX) {
                    // Up Kbps
                    custom.setUpUnit(2);
                    double upLimitDouble = NumberUtil.div(settingDto.getUpLimit().intValue(), MBPS_LIMIT_MAX, 0, RoundingMode.HALF_UP);
                    custom.setUpLimit((int) upLimitDouble);
                } else if (settingDto.getUpLimitEnable()) {
                    // Up Mbps
                    custom.setUpUnit(1);
                    custom.setUpLimit(settingDto.getUpLimit().intValue());
                }
            }
            if (!settingDto.getDownLimitEnable()) {
                custom.setDownUnit(1);
                custom.setDownLimit(1);
            }
            if (!settingDto.getUpLimitEnable()) {
                custom.setUpUnit(1);
                custom.setUpLimit(1);
            }

            clientRateLimitSetting.setCustomRateLimit(custom);

        }
        ResponseEntity<OperationResponseWithoutResult> response = omadaClientApi.updateClientRateLimitSetting(siteId, clientMac, clientRateLimitSetting);
        if (ObjectUtil.isNotNull(response.getBody())) {
            if (response.getBody().getErrorCode() == WifiConstants.ERROR_CODE_SUCCESS) {
                log.info("updateClientRateLimitSetting success,siteId={},clientMac={},errorCode={}, msg={}", siteId, clientMac, response.getBody().getErrorCode(), response.getBody().getMsg());
            } else {
                log.error("updateClientRateLimitSetting error,siteId={},clientMac={},errorCode={}, msg={}", siteId, clientMac, response.getBody().getErrorCode(), response.getBody().getMsg());
            }
        }
        return true;
    }

    private void initRateLimitSettingDto(ClientRateLimitSettingDto settingDto) {
        if (ObjectUtil.isNull(settingDto.getRateLimitEnable())) {
            settingDto.setRateLimitEnable(false);
        }
        if (ObjectUtil.isNull(settingDto.getUpLimitEnable())) {
            settingDto.setUpLimitEnable(false);
        }
        if (ObjectUtil.isNull(settingDto.getDownLimitEnable())) {
            settingDto.setDownLimitEnable(false);
        }
    }

    private Optional<RateLimitProfileOpenApiVo> getRateLimitByProfile(String siteId, ClientRateLimitSettingDto settingDto) {
        ResponseEntity<OperationResponseListRateLimitProfileOpenApiVo> rateLimitProfileList = omadaProfilesApi.getRateLimitProfileList(siteId);
        if (ObjectUtil.isNull(rateLimitProfileList.getBody())) {
            return Optional.empty();
        }
        List<RateLimitProfileOpenApiVo> rateLimitProfiles = rateLimitProfileList.getBody().getResult();
        return rateLimitProfiles.stream().filter(rateLimit -> Objects.equals(settingDto.getDownLimitEnable(), rateLimit.getDownLimitEnable())
                && Objects.equals(settingDto.getUpLimitEnable(), rateLimit.getUpLimitEnable())
                && Objects.equals(settingDto.getDownLimit(), rateLimit.getDownLimit())
                && Objects.equals(settingDto.getUpLimit(), rateLimit.getUpLimit())).findFirst();
    }

}
