from typing import NamedTuple

from .exceptions import ParseError

COMMENTCHARS = "#;"


class ParsedLine(NamedTuple):
    lineno: int
    section: str | None
    name: str | None
    value: str | None


def parse_lines(path: str, line_iter: list[str]) -> list[ParsedLine]:
    result: list[ParsedLine] = []
    section = None
    for lineno, line in enumerate(line_iter):
        name, data = _parseline(path, line, lineno)
        # new value
        if name is not None and data is not None:
            result.append(ParsedLine(lineno, section, name, data))
        # new section
        elif name is not None and data is None:
            if not name:
                raise ParseError(path, lineno, "empty section name")
            section = name
            result.append(ParsedLine(lineno, section, None, None))
        # continuation
        elif name is None and data is not None:
            if not result:
                raise ParseError(path, lineno, "unexpected value continuation")
            last = result.pop()
            if last.name is None:
                raise ParseError(path, lineno, "unexpected value continuation")

            if last.value:
                last = last._replace(value=f"{last.value}\n{data}")
            else:
                last = last._replace(value=data)
            result.append(last)
    return result


def _parseline(path: str, line: str, lineno: int) -> tuple[str | None, str | None]:
    # blank lines
    if iscommentline(line):
        line = ""
    else:
        line = line.rstrip()
    if not line:
        return None, None
    # section
    if line[0] == "[":
        realline = line
        for c in COMMENTCHARS:
            line = line.split(c)[0].rstrip()
        if line[-1] == "]":
            return line[1:-1], None
        return None, realline.strip()
    # value
    elif not line[0].isspace():
        try:
            name, value = line.split("=", 1)
            if ":" in name:
                raise ValueError()
        except ValueError:
            try:
                name, value = line.split(":", 1)
            except ValueError:
                raise ParseError(path, lineno, f"unexpected line: {line!r}") from None
        return name.strip(), value.strip()
    # continuation
    else:
        return None, line.strip()


def iscommentline(line: str) -> bool:
    c = line.lstrip()[:1]
    return c in COMMENTCHARS
