from pathlib import Path

from PIL import Image, ImageDraw, ImageFont


ROOT = Path(__file__).resolve().parents[1]
FIG_DIR = ROOT / "figures"
OUTPUT_TEXT = FIG_DIR / "evaluation_output.txt"
OUTPUT_IMAGE = FIG_DIR / "result_terminal_screenshot.png"

FONT_REGULAR_CANDIDATES = [
    Path("/Users/student/Library/Fonts/JetBrainsMonoNLNerdFontMono-Regular.ttf"),
    Path("/Users/student/Library/Fonts/JetBrainsMonoNerdFontMono-Regular.ttf"),
    Path("/System/Library/Fonts/SFNSMono.ttf"),
]
FONT_BOLD_CANDIDATES = [
    Path("/Users/student/Library/Fonts/JetBrainsMonoNLNerdFontMono-SemiBold.ttf"),
    Path("/Users/student/Library/Fonts/JetBrainsMonoNerdFontMono-SemiBold.ttf"),
    Path("/System/Library/Fonts/SFNSMono.ttf"),
]

BG = "#2c303a"
BORDER = "#515562"
PATH_COLOR = "#95c8c8"
ACCENT = "#efc76a"
PROMPT = "#c8d06b"
TEXT = "#f2f3f5"
MUTED = "#d7dbe0"
CURSOR = "#f5f6f7"

WIDTH = 2200
PADDING_X = 34
PADDING_Y = 28
WINDOW_RADIUS = 30


def pick_font(candidates, size):
    for path in candidates:
        if path.exists():
            return ImageFont.truetype(str(path), size=size)
    return ImageFont.load_default()


FONT_PROMPT = pick_font(FONT_BOLD_CANDIDATES, 31)
FONT_COMMAND = pick_font(FONT_REGULAR_CANDIDATES, 28)
FONT_OUTPUT = pick_font(FONT_REGULAR_CANDIDATES, 26)


def line_height(font):
    bbox = font.getbbox("Ag")
    return bbox[3] - bbox[1] + 10


PROMPT_LINE_HEIGHT = line_height(FONT_PROMPT)
COMMAND_LINE_HEIGHT = line_height(FONT_COMMAND)
OUTPUT_LINE_HEIGHT = line_height(FONT_OUTPUT)


def measure(draw, text, font):
    bbox = draw.textbbox((0, 0), text, font=font)
    return bbox[2] - bbox[0]


def wrap_plain_text(draw, text, font, max_width):
    if not text:
        return [""]

    pieces = []
    current = ""
    for char in text:
        test = current + char
        if current and measure(draw, test, font) > max_width:
            pieces.append(current)
            current = char
        else:
            current = test
    if current:
        pieces.append(current)
    return pieces


def draw_segments(draw, xy, segments):
    x, y = xy
    for text, color, font in segments:
        draw.text((x, y), text, fill=color, font=font)
        x += measure(draw, text, font)


def output_lines(draw):
    lines = OUTPUT_TEXT.read_text(encoding="utf-8").splitlines()
    wrapped = []
    max_width = WIDTH - 2 * PADDING_X
    for line in lines:
        wrapped.extend(wrap_plain_text(draw, line, FONT_OUTPUT, max_width))
    return wrapped


def prompt_segments(with_time=False):
    segments = [
        ("Code/NN/Project01/MDMS", PATH_COLOR, FONT_PROMPT),
        (" [", TEXT, FONT_PROMPT),
        (" v3.11.15(.venv)", ACCENT, FONT_PROMPT),
        ("]", TEXT, FONT_PROMPT),
    ]
    if with_time:
        segments.extend(
            [
                ("  2s", ACCENT, FONT_PROMPT),
            ]
        )
    return segments


def command_segments():
    return [
        [
            ("❯", PROMPT, FONT_COMMAND),
            (" python evaluation.py", ACCENT, FONT_COMMAND),
            (" -dirA ./datasets/scratch/LLIE/data/lowlight/test/gt \\", TEXT, FONT_COMMAND),
        ],
        [
            ("  -dirB ./results/images/lowlight/lowlight_clean --use_gpu false", TEXT, FONT_COMMAND),
        ],
    ]


def main():
    canvas = Image.new("RGB", (WIDTH, 2000), "#1b1d23")
    draw = ImageDraw.Draw(canvas)

    output = output_lines(draw)
    height = (
        PADDING_Y * 2
        + PROMPT_LINE_HEIGHT
        + COMMAND_LINE_HEIGHT * 2
        + OUTPUT_LINE_HEIGHT * len(output)
        + PROMPT_LINE_HEIGHT
        + 80
    )

    window = Image.new("RGBA", (WIDTH, height), (0, 0, 0, 0))
    wdraw = ImageDraw.Draw(window)
    wdraw.rounded_rectangle(
        (0, 0, WIDTH - 1, height - 1),
        radius=WINDOW_RADIUS,
        fill=BG,
        outline=BORDER,
        width=3,
    )

    y = PADDING_Y
    draw_segments(wdraw, (PADDING_X, y), prompt_segments())
    y += PROMPT_LINE_HEIGHT

    for segments in command_segments():
        draw_segments(wdraw, (PADDING_X, y), segments)
        y += COMMAND_LINE_HEIGHT

    for line in output:
        wdraw.text((PADDING_X, y), line, fill=MUTED, font=FONT_OUTPUT)
        y += OUTPUT_LINE_HEIGHT

    y += 18
    draw_segments(wdraw, (PADDING_X, y), prompt_segments(with_time=True))
    y += PROMPT_LINE_HEIGHT
    wdraw.text((PADDING_X, y), "❯", fill=PROMPT, font=FONT_COMMAND)
    cursor_x = PADDING_X + measure(wdraw, "❯ ", FONT_COMMAND)
    wdraw.line((cursor_x, y + 3, cursor_x, y + COMMAND_LINE_HEIGHT - 6), fill=CURSOR, width=3)

    canvas.paste(window, (0, 0), window)
    canvas.crop((0, 0, WIDTH, height)).save(OUTPUT_IMAGE)


if __name__ == "__main__":
    main()
