#!/usr/bin/env python3

import pathlib
import subprocess
import sys

import gi

gi.require_version("Gtk", "4.0")
gi.require_version("Gdk", "4.0")
from gi.repository import Gdk, GLib, Gtk  # noqa: E402


CSS = """
window#blacksite-splash {
    background: #111418;
    color: #edf0f2;
    border: 1px solid #4b535c;
}

.top-rule { background: #d7a83c; min-height: 4px; }
.eyebrow { color: #d7a83c; font-family: monospace; font-size: 11px; font-weight: 700; }
.brand { color: #f4f5f6; font-family: sans-serif; font-size: 48px; font-weight: 800; }
.edition { color: #9da6ae; font-family: monospace; font-size: 12px; }
.monogram { color: #313840; font-family: monospace; font-size: 88px; font-weight: 800; }
.build-chip {
    background: #242a30; color: #c7cdd2; border: 1px solid #3e464e;
    border-radius: 2px; font-family: monospace; font-size: 10px; padding: 5px 9px;
}
.footer { background: #1a1f24; border-top: 1px solid #353d45; }
.phase { color: #f0f2f4; font-size: 14px; font-weight: 700; }
.detail { color: #9da6ae; font-family: monospace; font-size: 11px; }
.crate-count {
    color: #c7cdd2; font-family: monospace; font-size: 12px; font-weight: 700;
    min-width: 74px;
}
.percentage { color: #d7a83c; font-family: monospace; font-size: 12px; font-weight: 700; }
progressbar trough { background: #30373e; border: 0; border-radius: 0; min-height: 5px; }
progressbar progress { background: #d7a83c; border: 0; border-radius: 0; min-height: 5px; }
progressbar.error progress { background: #d55b55; }
.error-text { color: #ef8b84; }
button {
    background: #293038; color: #eef0f2; border: 1px solid #4a535c;
    border-radius: 3px; padding: 6px 14px; font-weight: 600;
}
button:hover { background: #343d45; }
button.suggested-action { background: #b98b2f; color: #101317; border-color: #d7a83c; }
"""


class BlacksiteSplash(Gtk.Application):
    def __init__(self, status_path: pathlib.Path, log_path: pathlib.Path) -> None:
        super().__init__(application_id="com.fallingmetal.BlacksiteSplash")
        self.status_path = status_path
        self.log_path = log_path
        self.last_status = None

    def do_activate(self) -> None:
        provider = Gtk.CssProvider()
        provider.load_from_data(CSS.encode("utf-8"))
        Gtk.StyleContext.add_provider_for_display(
            Gdk.Display.get_default(), provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        )
        self.window = Gtk.ApplicationWindow(application=self)
        self.window.set_name("blacksite-splash")
        self.window.set_title("Blacksite Editor")
        self.window.set_decorated(False)
        self.window.set_resizable(False)
        self.window.set_default_size(760, 410)

        root = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        self.window.set_child(root)
        top_rule = Gtk.Box()
        top_rule.add_css_class("top-rule")
        root.append(top_rule)

        content = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
        content.set_margin_top(34)
        content.set_margin_start(44)
        content.set_margin_end(44)
        content.set_vexpand(True)
        root.append(content)

        header = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        content.append(header)
        brand_stack = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=7)
        brand_stack.set_hexpand(True)
        header.append(brand_stack)
        eyebrow = Gtk.Label(label="FALLING METAL INTERACTIVE")
        eyebrow.set_halign(Gtk.Align.START)
        eyebrow.add_css_class("eyebrow")
        brand_stack.append(eyebrow)
        brand = Gtk.Label()
        brand.set_markup("<span letter_spacing='4300'>BLACKSITE</span>")
        brand.set_halign(Gtk.Align.START)
        brand.add_css_class("brand")
        brand_stack.append(brand)
        edition = Gtk.Label(label="PROJECT EDITOR / DEVELOPMENT BUILD")
        edition.set_halign(Gtk.Align.START)
        edition.add_css_class("edition")
        brand_stack.append(edition)
        monogram = Gtk.Label(label="B/S")
        monogram.set_halign(Gtk.Align.END)
        monogram.add_css_class("monogram")
        header.append(monogram)
        spacer = Gtk.Box()
        spacer.set_vexpand(True)
        content.append(spacer)
        chip = Gtk.Label(label="BEVY ENGINE  /  EDITOR RUNTIME")
        chip.set_halign(Gtk.Align.START)
        chip.add_css_class("build-chip")
        content.append(chip)

        footer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=9)
        footer.set_margin_top(25)
        footer.set_margin_bottom(26)
        footer.set_margin_start(44)
        footer.set_margin_end(44)
        footer.add_css_class("footer")
        root.append(footer)
        status_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=12)
        status_row.set_margin_top(20)
        footer.append(status_row)
        labels = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=3)
        labels.set_hexpand(True)
        status_row.append(labels)
        self.phase = Gtk.Label(label="Preparing workspace")
        self.phase.set_halign(Gtk.Align.START)
        self.phase.add_css_class("phase")
        labels.append(self.phase)
        self.detail = Gtk.Label(label="Reading project configuration")
        self.detail.set_halign(Gtk.Align.START)
        self.detail.set_ellipsize(3)
        self.detail.add_css_class("detail")
        labels.append(self.detail)

        self.crate_count = Gtk.Label(label="")
        self.crate_count.set_valign(Gtk.Align.CENTER)
        self.crate_count.add_css_class("crate-count")
        self.crate_count.set_visible(False)
        status_row.append(self.crate_count)
        self.percentage = Gtk.Label(label="05%")
        self.percentage.set_valign(Gtk.Align.CENTER)
        self.percentage.add_css_class("percentage")
        status_row.append(self.percentage)
        self.actions = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
        self.actions.set_visible(False)
        status_row.append(self.actions)
        open_log = Gtk.Button(label="Open Log")
        open_log.connect("clicked", self.open_log)
        self.actions.append(open_log)
        close = Gtk.Button(label="Close")
        close.add_css_class("suggested-action")
        close.connect("clicked", lambda _button: self.quit())
        self.actions.append(close)
        self.progress = Gtk.ProgressBar()
        self.progress.set_fraction(0.05)
        footer.append(self.progress)
        GLib.timeout_add(100, self.poll_status)
        self.window.present()

    def open_log(self, _button: Gtk.Button) -> None:
        if not self.log_path.exists():
            return
        try:
            subprocess.Popen(
                ["xdg-open", str(self.log_path)],
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,
            )
        except OSError:
            pass

    def poll_status(self) -> bool:
        try:
            raw_status = self.status_path.read_text(encoding="utf-8")
        except OSError:
            return GLib.SOURCE_CONTINUE
        if raw_status == self.last_status:
            return GLib.SOURCE_CONTINUE
        self.last_status = raw_status
        lines = raw_status.splitlines()
        if len(lines) < 4:
            return GLib.SOURCE_CONTINUE
        phase, detail, progress_text, state = lines[:4]
        crate_count = lines[4] if len(lines) >= 5 else ""
        try:
            progress = max(0, min(100, int(progress_text)))
        except ValueError:
            progress = 0
        if state == "close":
            self.quit()
            return GLib.SOURCE_REMOVE
        self.phase.set_label(phase)
        self.detail.set_label(detail)
        self.progress.set_fraction(progress / 100.0)
        self.percentage.set_label(f"{progress:02d}%")
        self.crate_count.set_label(f"({crate_count})" if crate_count else "")
        self.crate_count.set_visible(bool(crate_count))
        if state == "error":
            self.phase.add_css_class("error-text")
            self.progress.add_css_class("error")
            self.percentage.set_visible(False)
            self.actions.set_visible(True)
        return GLib.SOURCE_CONTINUE


def main() -> int:
    if len(sys.argv) != 3:
        print("usage: splash.py STATUS_FILE LOG_FILE", file=sys.stderr)
        return 2
    app = BlacksiteSplash(pathlib.Path(sys.argv[1]), pathlib.Path(sys.argv[2]))
    return app.run([sys.argv[0]])


if __name__ == "__main__":
    raise SystemExit(main())
