import re
from datetime import datetime

from PyInquirer import Validator, ValidationError
from prompt_toolkit.document import Document

# This file contains functions used for validation and Validator classes that use them.
# Validators are used by questions.


def non_empty(document: Document) -> bool:
    if not document.text:
        raise ValidationError(
            message="Please enter a non-empty value.",
            cursor_position=len(document.text),
        )
    return True


def valid_date(document: Document) -> bool:
    try:
        datetime.strptime(document.text, "%Y-%m-%d")
        return True
    except ValueError:
        raise ValidationError(
            message="Please enter a valid yyyy-mm-dd date.",
            cursor_position=len(document.text),
        )


email_regex = r"^(\w|\d|\.|\_|\-)+$"


def valid_email_prefix(document: Document) -> bool:
    try:
        assert re.match(email_regex, document.text)
        return True
    except AssertionError:
        raise ValidationError(
            message="Please enter a valid email prefix (e.g. james.f).",
            cursor_position=len(document.text),
        )


def valid_email_prefix_list(document: Document) -> bool:
    try:
        for prefix in document.text.split(","):
            assert re.match(email_regex, prefix.strip())
        return True
    except AssertionError:
        raise ValidationError(
            message="Please enter a comma seperated list of valid email prefixes (e.g. james.f).",
            cursor_position=len(document.text),
        )


url_regex = (
    r"^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$"
)


def valid_url(document: Document) -> bool:
    try:
        assert re.match(url_regex, document.text.strip())
        return True
    except AssertionError:
        raise ValidationError(
            message="Please enter a valid url.", cursor_position=len(document.text)
        )


def valid_url_list(document: Document) -> bool:
    try:
        for url in document.text.split(","):
            assert re.match(url_regex, url.strip())
        return True
    except AssertionError:
        raise ValidationError(
            message="Please enter a comma seperated list of valid urls.",
            cursor_position=len(document.text),
        )


def valid_cron(document: Document) -> bool:
    # Cron supports lots of advanced features such as ranges, so the regex is very long.
    cron_regex = r"^(\*|([0-9]|0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])|\*\/([0-9]|0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])) (\*|([0-9]|0[0-9]|1[0-9]|2[0-3])|\*\/([0-9]|0[0-9]|1[0-9]|2[0-3])) (\*|([1-9]|0[0-9]|1[0-9]|2[0-9]|3[0-1])|\*\/([1-9]|0[0-9]|1[0-9]|2[0-9]|3[0-1])) (\*|([1-9]|0[0-9]|1[0-2])|\*\/([1-9]|0[0-9]|1[0-2])) (\*|([0-6])|\*\/([0-6]))$"
    try:
        if document.text.strip() != "null":
            assert re.match(cron_regex, document.text.strip())
        return True
    except AssertionError:
        raise ValidationError(
            message="Please enter a valid cron or null.",
            cursor_position=len(document.text),
        )


def valid_directory(document: Document) -> bool:
    directory_regex = r"^(/)?([^/\0]+(/)?)+$"
    try:
        assert re.match(directory_regex, document.text.strip())
        return True
    except AssertionError:
        raise ValidationError(
            message="Please enter a valid unix directory.",
            cursor_position=len(document.text),
        )


class ValidNonEmpty(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a non-empty value."""
        return non_empty(document)


class ValidEmailPrefix(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a valid email prefix."""
        return non_empty(document) and valid_email_prefix(document)


class ValidEmailPrefixList(Validator):
    def validate(self, document: Document) -> bool:
        return non_empty(document) and valid_email_prefix_list(document)


class ValidClientIds(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a syntaxtically valid client id list."""
        # Checkboxes don't support validation yet.
        # https://github.com/CITGuru/PyInquirer/issues/46
        return True


class ValidDate(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a valid yyyy-mm-dd date."""
        return non_empty(document) and valid_date(document)


class ValidOptionalUrl(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a syntaxtically valid url."""
        return document.text == "" or valid_url(document)


class ValidUrl(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a syntaxtically valid url."""
        return non_empty(document) and valid_url(document)


class ValidUrlList(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a syntaxtically valid url list."""
        return non_empty(document) and valid_url_list(document)


class ValidOptionalUrlList(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a syntaxtically valid url list."""
        return document.text == "" or valid_url_list(document)


class ValidCron(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a syntaxtically valid crontab style string."""
        return non_empty(document) and valid_cron(document)


class ValidDirectory(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a syntaxtically valid unix path."""
        return non_empty(document) and valid_directory(document)


class ValidOptionalDirectory(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a syntaxtically valid unix path."""
        return document.text == "" and valid_directory(document)

import re
from datetime import datetime

from PyInquirer import Validator, ValidationError
from prompt_toolkit.document import Document

# This file contains functions used for validation and Validator classes that use them.
# Validators are used by questions.


def non_empty(document: Document) -> bool:
    if not document.text:
        raise ValidationError(
            message="Please enter a non-empty value.",
            cursor_position=len(document.text),
        )
    return True


def valid_date(document: Document) -> bool:
    try:
        datetime.strptime(document.text, "%Y-%m-%d")
        return True
    except ValueError:
        raise ValidationError(
            message="Please enter a valid yyyy-mm-dd date.",
            cursor_position=len(document.text),
        )


email_regex = r"^(\w|\d|\.|\_|\-)+$"


def valid_email_prefix(document: Document) -> bool:
    try:
        assert re.match(email_regex, document.text)
        return True
    except AssertionError:
        raise ValidationError(
            message="Please enter a valid email prefix (e.g. james.f).",
            cursor_position=len(document.text),
        )


def valid_email_prefix_list(document: Document) -> bool:
    try:
        for prefix in document.text.split(","):
            assert re.match(email_regex, prefix.strip())
        return True
    except AssertionError:
        raise ValidationError(
            message="Please enter a comma seperated list of valid email prefixes (e.g. james.f).",
            cursor_position=len(document.text),
        )


url_regex = (
    r"^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$"
)


def valid_url(document: Document) -> bool:
    try:
        assert re.match(url_regex, document.text.strip())
        return True
    except AssertionError:
        raise ValidationError(
            message="Please enter a valid url.", cursor_position=len(document.text)
        )


def valid_url_list(document: Document) -> bool:
    try:
        for url in document.text.split(","):
            assert re.match(url_regex, url.strip())
        return True
    except AssertionError:
        raise ValidationError(
            message="Please enter a comma seperated list of valid urls.",
            cursor_position=len(document.text),
        )


def valid_cron(document: Document) -> bool:
    # Cron supports lots of advanced features such as ranges, so the regex is very long.
    cron_regex = r"^(\*|([0-9]|0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])|\*\/([0-9]|0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])) (\*|([0-9]|0[0-9]|1[0-9]|2[0-3])|\*\/([0-9]|0[0-9]|1[0-9]|2[0-3])) (\*|([1-9]|0[0-9]|1[0-9]|2[0-9]|3[0-1])|\*\/([1-9]|0[0-9]|1[0-9]|2[0-9]|3[0-1])) (\*|([1-9]|0[0-9]|1[0-2])|\*\/([1-9]|0[0-9]|1[0-2])) (\*|([0-6])|\*\/([0-6]))$"
    try:
        if document.text.strip() != "null":
            assert re.match(cron_regex, document.text.strip())
        return True
    except AssertionError:
        raise ValidationError(
            message="Please enter a valid cron or null.",
            cursor_position=len(document.text),
        )


def valid_directory(document: Document) -> bool:
    directory_regex = r"^(/)?([^/\0]+(/)?)+$"
    try:
        assert re.match(directory_regex, document.text.strip())
        return True
    except AssertionError:
        raise ValidationError(
            message="Please enter a valid unix directory.",
            cursor_position=len(document.text),
        )


class ValidNonEmpty(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a non-empty value."""
        return non_empty(document)


class ValidEmailPrefix(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a valid email prefix."""
        return non_empty(document) and valid_email_prefix(document)


class ValidEmailPrefixList(Validator):
    def validate(self, document: Document) -> bool:
        return non_empty(document) and valid_email_prefix_list(document)


class ValidClientIds(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a syntaxtically valid client id list."""
        # Checkboxes don't support validation yet.
        # https://github.com/CITGuru/PyInquirer/issues/46
        return True


class ValidDate(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a valid yyyy-mm-dd date."""
        return non_empty(document) and valid_date(document)


class ValidOptionalUrl(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a syntaxtically valid url."""
        return document.text == "" or valid_url(document)


class ValidUrl(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a syntaxtically valid url."""
        return non_empty(document) and valid_url(document)


class ValidUrlList(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a syntaxtically valid url list."""
        return non_empty(document) and valid_url_list(document)


class ValidOptionalUrlList(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a syntaxtically valid url list."""
        return document.text == "" or valid_url_list(document)


class ValidCron(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a syntaxtically valid crontab style string."""
        return non_empty(document) and valid_cron(document)


class ValidDirectory(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a syntaxtically valid unix path."""
        return non_empty(document) and valid_directory(document)


class ValidOptionalDirectory(Validator):
    def validate(self, document: Document) -> bool:
        """Return True with no errors for a syntaxtically valid unix path."""
        return document.text == "" and valid_directory(document)

# This file contains functions used for validation and Validator classes that use them. # Validators are used by questions. #[\]@!\$&'\(\)\*\+,;=.]+$" # Cron supports lots of advanced features such as ranges, so the regex is very long. Return True with no errors for a non-empty value. Return True with no errors for a valid email prefix. Return True with no errors for a syntaxtically valid client id list. # Checkboxes don't support validation yet. # https://github.com/CITGuru/PyInquirer/issues/46 Return True with no errors for a valid yyyy-mm-dd date. Return True with no errors for a syntaxtically valid url. Return True with no errors for a syntaxtically valid url. Return True with no errors for a syntaxtically valid url list. Return True with no errors for a syntaxtically valid url list. Return True with no errors for a syntaxtically valid crontab style string. Return True with no errors for a syntaxtically valid unix path. Return True with no errors for a syntaxtically valid unix path.