# -*- coding: utf-8 -*-
"""手抄报风格生成流水线
用法:
  python3 poster.py color [key ...]   生成彩色高清图（无文字）
  python3 poster.py line  [key ...]   由彩色图生图得到线条图
  python3 poster.py title             用 Pillow 叠加标题（彩色=红字黄边；线稿=空心字）
"""
import base64, glob, json, os, re, sys, time, requests
from PIL import Image, ImageDraw, ImageFont
from concurrent.futures import ThreadPoolExecutor

CFG = json.load(open('/data/www/files/LhyjdesignPro/config.json'))
API_KEY, BASE, MODEL = CFG['api_key'], CFG['base_url'], CFG['models']['image_gen']
OUT = '/data/www/files/pandaReadArt/poster'
os.makedirs(OUT, exist_ok=True)
SIZE = '2400x1600'          # 3:2 横版，满足 seedream5 最小像素
FONT = '/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc'

TITLES = {'01': '长征胜利90周年', '02': '建党105周年', '03': '书香伴我成长'}

NOTEXT = (" Absolutely NO TEXT anywhere in the whole image: no letters, no Chinese characters, no numbers, no "
          "calligraphy, no captions, no titles, no labels, no writing on any plaque, banner, sign, monument or "
          "flag, no logos, no watermarks, no signature, no seals. Every banner, plaque, sign and flag must be "
          "completely blank and plain. ")

COMMON = (" A children's hand-copied newspaper poster (school poster artwork) in bold marker style: thick uniform "
          "black outlines with flat bright marker colouring neatly filled inside, crisp clean boundaries, no "
          "shading, no gradients, no texture rendering, cheerful, bold and eye-catching. Landscape composition, "
          "wider than tall, about 3:2. LAYOUT: the top 20 percent of the poster is a blank decorative title band "
          "— an empty horizontal ribbon-shaped area with light blue sky behind it, white clouds and small red "
          "five-pointed stars scattered around it, kept completely blank with no writing. The whole poster is "
          "enclosed by a decorative red ribbon border frame. The bottom edge is filled with stylized white "
          "curling auspicious clouds. A large yellow five-pointed star with a thick red outline sits in the "
          "bottom-left corner. Light blue sky with white clouds, small red stars and two white doves flying. "
          "Flat bright palette of red, sky blue, bright yellow, grass green, white and grey. ")

T = {}

T['01'] = ("Colourful school poster about the Long March. Middle ground, from left to right: on the left four cute "
           "chibi cartoon children dressed as young Red Army soldiers in blue-grey uniforms, blue caps with a red "
           "star and grey puttees, marching forward in a line, the leading boy holding up one large red flag on a "
           "pole, the child behind him raising a clenched fist in cheer; in the centre a grey three-arch stone "
           "bridge with a blank plain plaque above its central arch, crossing a bright blue river with white "
           "waves; on the right a green grassy hill with a bright yellow winding path curving from the lower "
           "left up to the hilltop; on the distant hilltop a tall grey monument topped with a large red star. "
           "Small red triangular flags planted along the winding yellow path, a few green pine trees, red star "
           "shaped flowers on the grass. ") + NOTEXT + COMMON

T['02'] = ("Colourful school poster about the founding of the Communist Party of China. Middle ground, from left "
           "to right: on the left a red wooden boat with a traditional curved Chinese roof and one bright red "
           "flag on its bow, floating on calm blue lake water surrounded by green lotus leaves and pink lotus "
           "flowers; beside the boat four cute chibi cartoon children wearing white shirts and red neckerchiefs "
           "stand in a row saluting, with a bright yellow sun and golden rays rising behind them; in the centre "
           "a tall grey stone gate building with an arched doorway and a completely blank plain plaque above the "
           "arch; on the right rolling green hills with a bright yellow winding path leading up, and on the "
           "distant hilltop the silhouette of modern city towers beside a red five-pointed star. Small red "
           "triangular flags along the yellow path, green trees, white doves flying. ") + NOTEXT + COMMON

T['03'] = ("Colourful school poster about reading and red heritage. Middle ground: in the centre a giant open "
           "book standing upright, its two open pages forming a bright stage; on the open pages sits a big cute "
           "chibi giant panda wearing a red neckerchief, holding a small red flag, with a tall stack of colourful "
           "books beside it; on the left four cute chibi cartoon children wearing white shirts and red "
           "neckerchiefs sit cross-legged in a row on the grass, each holding an open book of a different "
           "colour, smiling; on the right a green grassy hill with a bright yellow winding path curving up to "
           "the hilltop where a nine-tier pagoda with a red star on top stands, and further away the silhouette "
           "of snow-capped mountains; a tall red flag on a pole beside the path, small red triangular flags "
           "along the way, green trees, scattered colourful books and red star shaped flowers on the grass, "
           "white doves flying. ") + NOTEXT + COMMON

LINE_PROMPT = ("Convert this exact poster into a pure black-and-white LINE DRAWING for a children's colouring "
               "template. Keep EXACTLY the same shapes, the same positions, the same proportions, the same number "
               "of objects and the same composition — do not add, remove, move or redraw anything. Reproduce it "
               "as uniform bold black outlines only on a pure white background: no colour at all, no grey tones, "
               "no shading, no cross-hatching, no stippling, no gradients, no filled dark areas — every region "
               "left pure white with clean closed outlines. The thin red border frame and the bottom clouds should "
               "also be drawn as simple black outlines. Keep the title band at the top completely blank. "
               "ABSOLUTELY NO TEXT of any kind: no letters, no Chinese characters, no numbers, no calligraphy, no "
               "writing on any banner, plaque, flag or monument, no logos, no watermarks, no signature. Every "
               "banner, plaque and sign must be blank.")


def api(prompt, size=SIZE, image=None, strength=None, retries=3):
    body = {"model": MODEL, "prompt": prompt, "size": size, "n": 1, "watermark": False}
    if image:
        body["image"] = image
        body["strength"] = strength if strength is not None else 0.65
    for a in range(retries):
        try:
            r = requests.post(f"{BASE}/images/generations",
                headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"},
                json=body, timeout=300)
            d = r.json()
            if d.get('data'):
                return requests.get(d['data'][0]['url'], timeout=200).content
            print(f"  ERR #{a}: {json.dumps(d, ensure_ascii=False)[:200]}", flush=True)
        except Exception as e:
            print(f"  EXC #{a}: {e}", flush=True)
        time.sleep(6)
    return None


def gen_color(key):
    data = api(T[key])
    if not data:
        return None
    p = os.path.join(OUT, f"{key}_{TITLES[key]}_彩色高清.jpg")
    Image.open(__import__('io').BytesIO(data)).save(p, quality=95)
    print(f"OK color {p}", flush=True)
    return p


def gen_line(key):
    src = os.path.join(OUT, f"{key}_{TITLES[key]}_彩色高清.jpg")
    b64 = base64.b64encode(open(src, 'rb').read()).decode()
    data = api(LINE_PROMPT, image=f"data:image/jpeg;base64,{b64}", strength=0.65)
    if not data:
        return None
    p = os.path.join(OUT, f"{key}_{TITLES[key]}_线条图.jpg")
    Image.open(__import__('io').BytesIO(data)).save(p, quality=95)
    print(f"OK line  {p}", flush=True)
    return p


def draw_title(path, title, mode):
    """mode: 'color' 红字黄描边 ; 'line' 白底黑边空心字（便于涂色）"""
    im = Image.open(path).convert('RGB')
    W, H = im.size
    d = ImageDraw.Draw(im)
    base = int(H * 0.085)
    segs = re.findall(r'\d+|\D+', title)
    fonts, widths = [], []
    for s in segs:
        sz = int(base * 1.45) if s.isdigit() else base
        f = ImageFont.truetype(FONT, sz)
        fonts.append(f)
        bb = d.textbbox((0, 0), s, font=f, anchor='ls')
        widths.append(bb[2] - bb[0])
    gap = int(base * 0.06)
    total = sum(widths) + gap * (len(segs) - 1)
    x = (W - total) / 2
    y = int(H * 0.145)                      # 标题基线，落在顶部20%区域
    for s, f, w in zip(segs, fonts, widths):
        if mode == 'color':
            d.text((x, y), s, font=f, fill=(200, 26, 26), anchor='ls',
                   stroke_width=max(4, base // 9), stroke_fill=(255, 214, 64))
        else:
            d.text((x, y), s, font=f, fill=(255, 255, 255), anchor='ls',
                   stroke_width=max(3, base // 12), stroke_fill=(20, 20, 20))
        x += w + gap
    im.save(path, quality=95)
    print(f"TITLE  {os.path.basename(path)}  <- {title}", flush=True)


if __name__ == '__main__':
    cmd = sys.argv[1]
    keys = sys.argv[2:] or list(TITLES)
    keys = [k for k in keys if k in TITLES]
    if cmd == 'color':
        with ThreadPoolExecutor(max_workers=3) as ex:
            print(list(ex.map(gen_color, keys)))
    elif cmd == 'line':
        with ThreadPoolExecutor(max_workers=3) as ex:
            print(list(ex.map(gen_line, keys)))
    elif cmd == 'title':
        for k in keys:
            for suffix, mode in (('彩色高清', 'color'), ('线条图', 'line')):
                p = os.path.join(OUT, f"{k}_{TITLES[k]}_{suffix}.jpg")
                if os.path.exists(p):
                    draw_title(p, TITLES[k], mode)
