import hashlib

import inject
import requests
import urllib3
from urllib3.exceptions import InsecureRequestWarning

from acmev2.models.identifiers import IdentifierType
from acmev2.settings import ACMESettings
from .base import ChallengeValidator, ValidationError
import logging
import josepy
import dns.resolver
from dns.nameserver import Do53Nameserver

logger = logging.getLogger(__name__)


class Dns01ChallengeValidator(ChallengeValidator):
    """
    https://datatracker.ietf.org/doc/html/rfc8555#section-8.4
    """

    def validate(self) -> bool:
        settings = inject.instance(ACMESettings)

        # Only DNS identifiers supported
        if self.authz.identifier.type != IdentifierType.dns:
            raise ValidationError(
                f"Attempted to validate identifier of type {self.authz.identifier.type} with DNS-01 challenge"
            )

        domain = f"_acme-challenge.{self.authz.identifier.value}"

        nameservers = []
        for nameserver in settings.dns_challenge_nameservers:
            ip, _, port = nameserver.partition(":")
            nameservers.append(Do53Nameserver(ip, int(port) if port else 53))

        resolver = dns.resolver.Resolver()
        if len(nameservers) != 0:
            resolver.nameservers = nameservers

        logger.info(f"Validating domain <{domain}> for challenge <{self.chall.id}>")
        expected_content = josepy.b64encode(
            hashlib.sha256(
                f"{self.chall.token}.{josepy.encode_b64jose(self.acct_jwk.thumbprint())}".encode()
            ).digest()
        ).decode()

        answers = []
        try:
            answers = resolver.resolve(domain, "TXT")
        except Exception as exc:
            logger.exception("Error validating dns-01 challenge")
            raise ValidationError(
                f"{exc.__class__.__name__}: error validating {domain}"
            ) from exc

        if len(answers) == 0:
            raise ValidationError(f"No TXT records found for domain {domain}")

        found = False
        for answer in answers:
            answer = answer.to_text().strip('"')
            logger.debug("Evaluating record %s against %s", answer, expected_content)
            if answer == expected_content:
                found = True

        if not found:
            raise ValidationError("TXT record could not be validated.")

        return found
