import re
import os

from enum import Enum
from typing import Callable


class BlockType(Enum):
    PARAGRAPH = "paragraph"
    HEADING = "heading"
    CODE = "code"
    QUOTE = "quote"
    ORDERED_LIST = "ordered list"
    UNORDERED_LIST = "unordered list"

def block_to_block_type(block: str) -> BlockType:
    if is_heading(block):
        return BlockType.HEADING

    if is_code(block):
        return BlockType.CODE

    if is_quote(block):
        return BlockType.QUOTE

    if is_unordered(block):
        return BlockType.UNORDERED_LIST

    if is_ordered(block):
        return BlockType.ORDERED_LIST

    return BlockType.PARAGRAPH

def is_heading(block: str) -> bool:
    pattern = r"^#{1,6}\s{1}?"
    return has_pattern(pattern, block)

def is_code(block: str) -> bool:
    pattern = rf"^```.*{os.linesep}[\s\S]*{os.linesep}```$"
    return has_pattern(pattern, block)

def is_quote(block: str) -> bool:
    pattern = r"^>"
    return each_line_has_pattern(lambda _: pattern, block)

def is_unordered(block: str) -> bool:
    pattern = r"^-\s"
    return each_line_has_pattern(lambda _: pattern, block)

def is_ordered(block: str) -> bool:
    return each_line_has_pattern(lambda i: rf"{i + 1}\.\s", block)

def has_pattern(pattern: str, block: str) -> bool:
    return re.match(pattern, block) != None

def each_line_has_pattern(pattern_builder: Callable[[int], str], block: str) -> bool:
    lines = block.split(os.linesep)

    for i in range(len(lines)):
        line = lines[i]

        if line == '':
            continue

        pattern = pattern_builder(i)
        if not has_pattern(pattern, line):
            return False

    return True
