import logging

import curl_cffi
import re
import requests

from bs4 import BeautifulSoup  # pyright: ignore[reportMissingImports]

from myst_connector.settings import get_app_int, get_url


logger = logging.getLogger(__name__)


IP_ADDRESS_URL = get_url('ip_address_url')
IP_SCORE_URL = get_url('ip_score_url')
IP_SCORE_LIMIT = get_app_int('ip_score_limit')


def get_ip_address():
    try:
        logger.info('Determining IP address')
        resp = requests.get(IP_ADDRESS_URL, timeout=5)
        resp.raise_for_status()
        data = resp.json()
        logger.info('IP address: %s', data['ip'])
        return data['ip']
    except Exception:
        logger.error('Failed to determine IP address')
        raise


def get_ip_score(ip_address):
    try:
        logger.info('Getting IP score')
        # attempt to pass a timeout; curl_cffi may or may not accept timeout kwarg
        try:
            response = curl_cffi.get(IP_SCORE_URL + '/' + ip_address, impersonate='chrome', timeout=10)
        except TypeError:
            response = curl_cffi.get(IP_SCORE_URL + '/' + ip_address, impersonate='chrome')
        soup = BeautifulSoup(response.text, 'html.parser')
    except Exception:
        logger.error('Failed to fetch IP score')
        raise
    try:
        pre = soup.find('pre')
        if pre is None:
            raise ValueError('Expected <pre> element not found in IP score response')
        data = pre.get_text()
        data = data.replace('"', '').replace(',', '').replace('...', '').replace(' ', '')
        data = data.strip()
        data = re.sub('^.*:', '', data, flags=re.M).splitlines()
        logger.info('IP address details: %s', data)
        return data
    except Exception:
        logger.error('Failed to parse IP address details')
        raise


def check_ip_score(ip_score, ip_score_limit=IP_SCORE_LIMIT):
    # validate structure
    try:
        score = int(ip_score[1])
        risk = ip_score[2]
        blacklisted = ip_score[3]
    except Exception:
        logger.error('Malformed IP score data: %s', ip_score)
        return False

    if score >= ip_score_limit or risk != 'low' or blacklisted != 'false':
        logger.warning('Unacceptable IP score')
        return False
    else:
        logger.info('Acceptable IP score')
        return True
