#!/usr/bin/env python3
"""Annotate the captured WHIMS stock screens with callouts, boxes and arrows."""
import math
from PIL import Image, ImageDraw, ImageFont

FB = "/usr/share/fonts/open-sans/OpenSans-Bold.ttf"
RED, AMBER, BLUE, GREEN, GREY = (198, 40, 40), (216, 120, 12), (18, 64, 110), (26, 122, 76), (90, 102, 117)
WHITE = (255, 255, 255)

def font(s): return ImageFont.truetype(FB, s)
def load(name, W=1500):
    im = Image.open(f"shots/{name}.png").convert("RGB")
    w, h = im.size
    return im.resize((W, int(h * W / w)), Image.LANCZOS)
def P(im, fx, fy): return (int(fx * im.size[0]), int(fy * im.size[1]))
def box(im, f1, f2): return [P(im, *f1)[0], P(im, *f1)[1], P(im, *f2)[0], P(im, *f2)[1]]

def arrow(d, p1, p2, color=RED, w=5):
    d.line([p1, p2], fill=color, width=w)
    a = math.atan2(p2[1]-p1[1], p2[0]-p1[0]); L = 20
    for t in (a+math.radians(152), a-math.radians(152)):
        d.line([p2, (p2[0]+L*math.cos(t), p2[1]+L*math.sin(t))], fill=color, width=w)

def ellipse(d, c, rx, ry, color=RED, w=5):
    d.ellipse([c[0]-rx, c[1]-ry, c[0]+rx, c[1]+ry], outline=color, width=w)

def rrect(d, b, color=RED, w=5, rad=10): d.rounded_rectangle(b, radius=rad, outline=color, width=w)

def badge(d, c, n, color=RED, r=19):
    x, y = c
    d.ellipse([x-r, y-r, x+r, y+r], fill=color, outline=WHITE, width=3)
    f = font(int(r*1.15)); s = str(n)
    tb = d.textbbox((0, 0), s, font=f)
    d.text((x-(tb[2]-tb[0])/2-tb[0], y-(tb[3]-tb[1])/2-tb[1]), s, fill=WHITE, font=f)

def pill(d, anchor, text, color=AMBER, fsz=20, align="left"):
    f = font(fsz); tb = d.textbbox((0, 0), text, font=f)
    tw, th = tb[2]-tb[0], tb[3]-tb[1]; pad = 9
    x, y = anchor
    if align == "right":  x -= tw + 2*pad
    if align == "center": x -= (tw + 2*pad)//2
    d.rounded_rectangle([x, y, x+tw+2*pad, y+th+2*pad], radius=7, fill=color)
    d.text((x+pad-tb[0], y+pad-tb[1]), text, fill=WHITE, font=f)
    return (x, y, x+tw+2*pad, y+th+2*pad)

def save(im, name):
    im.save(f"shots/{name}.png"); print("  ", name, im.size)

# ------------------------------------------------------------------ figures --
def f_stock_levels():
    im = load("s03-stock-levels"); d = ImageDraw.Draw(im)
    badge(d, P(im, .793, .150), 1)
    badge(d, P(im, .892, .150), 2)
    badge(d, P(im, .921, .256), 3, BLUE)
    badge(d, P(im, .778, .315), 4, BLUE)
    badge(d, P(im, .243, .394), 5, BLUE)
    rrect(d, box(im, (.905, .448), (.978, .481)), AMBER, 4, 7)
    pill(d, P(im, .900, .560), 'This column always reads "Add Stock"', AMBER, 19, align="right")
    arrow(d, P(im, .888, .562), P(im, .930, .488), AMBER, 4)
    save(im.crop((0, 0, im.size[0], int(im.size[1]*.78))), "fig-stock-levels")

def f_actions_menu():
    im = load("s04-stock-actions-open"); d = ImageDraw.Draw(im)
    rrect(d, box(im, (.893, .143), (.988, .186)), RED, 4, 8)
    rrect(d, box(im, (.836, .190), (.990, .330)), BLUE, 4, 8)
    arrow(d, P(im, .70, .105), P(im, .90, .152), RED, 4)
    pill(d, P(im, .69, .075), "1. Click Stock Actions", RED, 20, align="right")
    pill(d, P(im, .655, .205), "ADD stock", GREEN, 19, align="right")
    arrow(d, P(im, .665, .213), P(im, .845, .213), GREEN, 4)
    pill(d, P(im, .655, .272), "CORRECT stock", AMBER, 19, align="right")
    arrow(d, P(im, .665, .280), P(im, .845, .280), AMBER, 4)
    save(im.crop((0, 0, im.size[0], int(im.size[1]*.52))), "fig-actions-menu")

def f_stock_take():
    im = load("s06-stock-take-filled"); d = ImageDraw.Draw(im)
    for i, fy in enumerate([.288, .376, .464], start=1):
        badge(d, P(im, .232, fy), i, BLUE)
    badge(d, P(im, .232, .580), 4, BLUE)
    badge(d, P(im, .505, .580), 5, BLUE)
    badge(d, P(im, .232, .696), 6, BLUE)
    rrect(d, box(im, (.212, .855), (.275, .885)), GREEN, 4, 7)
    pill(d, P(im, .330, .858), "7. Submit saves the movement", GREEN, 19)
    save(im, "fig-stock-take")

def f_stock_take_validation():
    im = load("s07-stock-take-validation"); d = ImageDraw.Draw(im)
    ellipse(d, P(im, .305, .380), 122, 17, RED, 4)
    ellipse(d, P(im, .308, .613), 122, 17, RED, 4)
    pill(d, P(im, .60, .355), "Fix every red message, then Submit again", RED, 19)
    arrow(d, P(im, .595, .372), P(im, .435, .381), RED, 4)
    save(im.crop((0, 0, im.size[0], int(im.size[1]*.80))), "fig-validation")

def f_product_stock():
    im = load("s14-product-stock-tab"); d = ImageDraw.Draw(im)
    rrect(d, box(im, (.415, .700), (.800, .748)), BLUE, 4, 9)
    pill(d, P(im, .415, .655), "Three tabs on every product", BLUE, 19)
    rrect(d, box(im, (.912, .925), (.988, .962)), RED, 4, 7)
    arrow(d, P(im, .80, .880), P(im, .925, .928), RED, 4)
    pill(d, P(im, .79, .852), "Adjust = add or remove here", RED, 19, align="right")
    save(im, "fig-product-stock")

def f_adjust():
    im = load("s15-adjust-modal-add"); d = ImageDraw.Draw(im)
    badge(d, P(im, .332, .292), 1)
    badge(d, P(im, .332, .374), 2)
    badge(d, P(im, .332, .460), 3)
    rrect(d, box(im, (.363, .552), (.415, .585)), GREEN, 4, 7)
    pill(d, P(im, .435, .552), "4. Submit", GREEN, 19)
    pill(d, P(im, .648, .190), "Shows the location and the quantity you have now", BLUE, 18)
    arrow(d, P(im, .640, .207), P(im, .478, .207), BLUE, 4)
    save(im, "fig-adjust")

def f_insufficient():
    im = load("s17-insufficient-stock"); d = ImageDraw.Draw(im)
    rrect(d, box(im, (.728, .012), (.992, .118)), RED, 5, 10)
    pill(d, P(im, .715, .150), "Nothing was saved — lower the quantity and try again",
         RED, 19, align="right")
    arrow(d, P(im, .720, .150), P(im, .800, .122), RED, 4)
    save(im.crop((0, 0, im.size[0], int(im.size[1]*.42))), "fig-insufficient")

def f_location_buttons():
    im = load("s19-location-view"); d = ImageDraw.Draw(im)
    rrect(d, box(im, (.780, .145), (.878, .190)), GREEN, 4, 8)
    rrect(d, box(im, (.884, .145), (.988, .190)), RED, 4, 8)
    pill(d, P(im, .770, .245), "1. Always export first", GREEN, 19, align="right")
    arrow(d, P(im, .775, .248), P(im, .820, .196), GREEN, 4)
    pill(d, P(im, .995, .245), "2. Then empty (cannot be undone)", RED, 19, align="right")
    arrow(d, P(im, .930, .248), P(im, .930, .196), RED, 4)
    save(im.crop((0, 0, im.size[0], int(im.size[1]*.62))), "fig-location-buttons")

def f_empty_1():
    im = load("s20-empty-location-1"); d = ImageDraw.Draw(im)
    rrect(d, box(im, (.213, .355), (.795, .500)), RED, 4, 9)
    ellipse(d, P(im, .223, .551), 16, 14, AMBER, 4)
    pill(d, P(im, .470, .600), "You must tick this before Next becomes usable", AMBER, 19)
    arrow(d, P(im, .465, .607), P(im, .240, .565), AMBER, 4)
    save(im.crop((0, 0, im.size[0], int(im.size[1]*.70))), "fig-empty-1")

def f_stock_history():
    im = load("s22-stock-history"); d = ImageDraw.Draw(im)
    rrect(d, box(im, (.552, .285), (.625, .870)), BLUE, 4, 8)
    rrect(d, box(im, (.700, .285), (.762, .870)), AMBER, 4, 8)
    pill(d, P(im, .552, .225), "What happened", BLUE, 18)
    pill(d, P(im, .690, .225), "+ added / − removed", AMBER, 18)
    save(im, "fig-stock-history")

for fn in (f_stock_levels, f_actions_menu, f_stock_take, f_stock_take_validation,
           f_product_stock, f_adjust, f_insufficient, f_location_buttons,
           f_empty_1, f_stock_history):
    fn()
print("ALL DONE")
