package gemtext

import "bytes"

// ParseLine parses a single line (including the trailing \n) into a gemtext.Line.
func ParseLine(line []byte) Line {
	if len(line) == 0 {
		return nil
	}

	switch line[0] {
	case '=':
		if len(line) == 1 {
			break
		}
		if line[1] == '>' {
			return parseLinkLine(line)
		}
		if line[1] == ':' {
			return parsePromptLine(line)
		}
	case '`':
		if len(line) < 3 || line[1] != '`' || line[2] != '`' {
			break
		}
		return parsePreformatToggleLine(line)
	case '#':
		level := 1
		if len(line) > 1 && line[1] == '#' {
			level += 1
			if len(line) > 2 && line[2] == '#' {
				level += 1
			}
		}
		return parseHeadingLine(level, line)
	case '*':
		if len(line) == 1 || line[1] != ' ' {
			break
		}
		return parseListItemLine(line)
	case '>':
		return parseQuoteLine(line)
	}

	return TextLine{raw: line}
}

func parseLinkLine(raw []byte) LinkLine {
	line := LinkLine{raw: raw}

	// move past =>[<whitespace>]
	raw = bytes.TrimLeft(raw[2:], " \t")

	// find the next space or tab
	spIdx := bytes.IndexByte(raw, ' ')
	tbIdx := bytes.IndexByte(raw, '\t')
	idx := spIdx
	if idx == -1 {
		idx = tbIdx
	}
	if tbIdx >= 0 && tbIdx < idx {
		idx = tbIdx
	}

	if idx < 0 {
		line.url = bytes.TrimRight(raw, "\r\n")
		return line
	}

	line.url = raw[:idx]
	raw = raw[idx+1:]

	label := bytes.TrimRight(bytes.TrimLeft(raw, " \t"), "\r\n")
	if len(label) > 0 {
		line.label = label
	}

	return line
}

func parsePromptLine(raw []byte) PromptLine {
	line := PromptLine{raw: raw}

	// move past =:[<whitespace>]
	raw = bytes.TrimLeft(raw[2:], " \t")

	// find the next space or tab
	spIdx := bytes.IndexByte(raw, ' ')
	tbIdx := bytes.IndexByte(raw, '\t')
	idx := spIdx
	if idx == -1 {
		idx = tbIdx
	}
	if tbIdx >= 0 && tbIdx < idx {
		idx = tbIdx
	}

	if idx < 0 {
		line.url = bytes.TrimRight(raw, "\r\n")
		return line
	}

	line.url = raw[:idx]
	raw = raw[idx+1:]

	label := bytes.TrimRight(bytes.TrimLeft(raw, " \t"), "\r\n")
	if len(label) > 0 {
		line.label = label
	}

	return line
}

func parsePreformatToggleLine(raw []byte) PreformatToggleLine {
	line := PreformatToggleLine{raw: raw}

	raw = bytes.TrimRight(raw[3:], "\r\n")
	if len(raw) > 0 {
		line.altText = raw
	}

	return line
}

func parseHeadingLine(level int, raw []byte) HeadingLine {
	return HeadingLine{
		raw:      raw,
		lineType: LineTypeHeading1 - 1 + LineType(level),
		body:     bytes.TrimRight(bytes.TrimLeft(raw[level:], " \t"), "\r\n"),
	}
}

func parseListItemLine(raw []byte) ListItemLine {
	return ListItemLine{
		raw:  raw,
		body: bytes.TrimRight(raw[2:], "\r\n"),
	}
}

func parseQuoteLine(raw []byte) QuoteLine {
	return QuoteLine{
		raw:  raw,
		body: bytes.TrimRight(raw[1:], "\r\n"),
	}
}