#!/usr/bin/python3
import gi, time
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Pango, GLib

SENTENCES = [
    "The quick brown fox jumps over the lazy dog",
    "Pack my box with five dozen liquor jugs",
    "How vexingly quick daft zebras jump",
    "The five boxing wizards jump quickly",
    "Sphinx of black quartz judge my vow",
    "Bright vixens jump dozy fowl quack",
    "Waltz nymph for quick jigs vex Bud",
    "Glib jocks quiz nymph to vex dwarf",
]

class App(Gtk.Window):
    def __init__(self):
        super().__init__(title='Typing Tutor')
        self.set_default_size(600, 360)
        self.sentence_idx = 0
        self.start_time = None
        self.done = False
        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10)
        vbox.set_margin_top(16); vbox.set_margin_bottom(16)
        vbox.set_margin_start(16); vbox.set_margin_end(16)
        self.add(vbox)
        self.progress = Gtk.Label(label='Sentence 1/8')
        vbox.pack_start(self.progress, False, False, 0)
        frame = Gtk.Frame(label='Type this:')
        self.target_lbl = Gtk.Label()
        self.target_lbl.set_line_wrap(True)
        self.target_lbl.override_font(Pango.FontDescription('18'))
        self.target_lbl.set_margin_top(10); self.target_lbl.set_margin_bottom(10)
        self.target_lbl.set_margin_start(10); self.target_lbl.set_margin_end(10)
        frame.add(self.target_lbl)
        vbox.pack_start(frame, False, False, 0)
        self.entry = Gtk.Entry()
        self.entry.override_font(Pango.FontDescription('16'))
        self.entry.connect('changed', self.on_type)
        vbox.pack_start(self.entry, False, False, 0)
        self.feedback = Gtk.Label(label='Start typing when ready...', xalign=0)
        vbox.pack_start(self.feedback, False, False, 0)
        stats_box = Gtk.Box(spacing=20)
        self.wpm_lbl = Gtk.Label(label='WPM: —')
        self.acc_lbl = Gtk.Label(label='Accuracy: —')
        self.score_lbl = Gtk.Label(label='Score: 0/0')
        stats_box.pack_start(self.wpm_lbl, True, True, 0)
        stats_box.pack_start(self.acc_lbl, True, True, 0)
        stats_box.pack_start(self.score_lbl, True, True, 0)
        vbox.pack_start(stats_box, False, False, 0)
        self.next_btn = Gtk.Button(label='Next →')
        self.next_btn.connect('clicked', self.next_sentence)
        self.next_btn.set_sensitive(False)
        vbox.pack_start(self.next_btn, False, False, 0)
        self.correct = 0; self.total = 0
        self.load_sentence()
    def load_sentence(self):
        self.target = SENTENCES[self.sentence_idx % len(SENTENCES)]
        self.target_lbl.set_text(self.target)
        self.entry.set_text('')
        self.start_time = None; self.done = False
        self.next_btn.set_sensitive(False)
        self.progress.set_text(f'Sentence {self.sentence_idx+1}/{len(SENTENCES)}')
        self.entry.grab_focus()
    def on_type(self, *_):
        typed = self.entry.get_text()
        if not typed: return
        if self.start_time is None: self.start_time = time.time()
        target = self.target
        # feedback markup
        markup = ''
        correct_chars = 0
        for i, ch in enumerate(typed):
            if i < len(target):
                if ch == target[i]:
                    markup += f'<span foreground="green">{GLib.markup_escape_text(ch)}</span>'
                    correct_chars += 1
                else:
                    markup += f'<span foreground="red" underline="error">{GLib.markup_escape_text(ch)}</span>'
            else:
                markup += f'<span foreground="orange">{GLib.markup_escape_text(ch)}</span>'
        elapsed = time.time() - self.start_time
        words = len(typed.split())
        wpm = int(words / (elapsed / 60)) if elapsed > 0 else 0
        acc = int(correct_chars / len(typed) * 100) if typed else 100
        self.wpm_lbl.set_text(f'WPM: {wpm}')
        self.acc_lbl.set_text(f'Accuracy: {acc}%')
        self.feedback.set_markup(markup)
        if typed == target and not self.done:
            self.done = True
            self.correct += 1; self.total += 1
            self.score_lbl.set_text(f'Score: {self.correct}/{self.total}')
            self.feedback.set_markup('<span foreground="green" weight="bold">✓ Correct!</span>')
            self.next_btn.set_sensitive(True)
        elif len(typed) >= len(target) and typed != target and not self.done:
            self.done = True; self.total += 1
            self.score_lbl.set_text(f'Score: {self.correct}/{self.total}')
            self.next_btn.set_sensitive(True)
    def next_sentence(self, *_):
        self.sentence_idx += 1
        self.load_sentence()

win = App()
win.connect('destroy', Gtk.main_quit)
win.show_all()
Gtk.main()
