#!/usr/bin/env python3
"""Compare the rendered search dialog with the design reference screenshot."""
import os
import sys

import numpy as np
from PIL import Image

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from kodi_renderer import Renderer, parse_po, STRINGS_PO  # noqa: E402
from render_dialog import BASE_PROPS, PROFILES, SEARCH_ITEMS  # noqa: E402

HERE = os.path.dirname(os.path.abspath(__file__))
REF_PATH = os.path.join(HERE, 'reference_search.png')
XML = os.path.join(HERE, '..', '..', 'resources', 'skins', 'Default', '1080i', 'search', 'DialogWcsSearch.xml')
OUT_DIR = os.path.join(HERE, 'search_compare')


def render_ours():
    props = dict(BASE_PROPS)
    props.update(PROFILES['search'])
    props['__items__'] = {50: SEARCH_ITEMS}
    renderer = Renderer(props, focus_ids=[50], strings=parse_po(STRINGS_PO))
    return renderer.render(XML, hidden_ids=[900])


def measure(img, label):
    a = np.asarray(img.convert('RGB')).astype(int)
    b = a.sum(axis=2) / 3.0
    sat = a.max(axis=2) - a.min(axis=2)
    out = {}

    def spikes_row(y, x0, x1, d=6):
        return [x for x in range(x0 + 1, x1 - 1) if b[y, x] - b[y, x - 1] > d and b[y, x] - b[y, x + 1] > d]

    out['card_edges_row400'] = spikes_row(400, 40, 1900)[:2] + spikes_row(400, 1600, 1900)[-1:]
    out['card_edges_row900'] = spikes_row(900, 40, 1900)

    # poster
    reg = (sat[250:640, 100:400] > 25) & (b[250:640, 100:400] > 60)
    ys, xs = np.where(reg)
    out['poster'] = (int(xs.min()) + 100, int(ys.min()) + 250, int(xs.max()) + 100, int(ys.max()) + 250) if len(xs) else None

    # text bands in left card
    txt = b[:, 400:960]
    rows = (txt > 140).any(axis=1)
    bands, start = [], None
    for y, v in enumerate(rows):
        if v and start is None:
            start = y
        if not v and start is not None:
            bands.append((start, y - 1))
            start = None
    merged = []
    for band in bands:
        if merged and band[0] - merged[-1][1] <= 4:
            merged[-1] = (merged[-1][0], band[1])
        else:
            merged.append(band)
    out['bands'] = []
    for y0, y1 in merged:
        if y1 - y0 < 5 or y0 > 900:
            continue
        cols = (b[y0:y1 + 1, 400:960] > 140).any(axis=0)
        xs2 = np.where(cols)[0]
        out['bands'].append((y0, y1, int(xs2.min()) + 400, int(xs2.max()) + 400))

    # left card buttons: pill fill brightness profile at x=350 (inside Info pill)
    col = b[:, 350]
    pill_rows = [y for y in range(700, 900) if col[y] > col[700] + 15]
    out['info_pill_y'] = (pill_rows[0], pill_rows[-1]) if pill_rows else None

    # right card rows: profile at x=1850 (right of play buttons)
    col2 = b[:, 1740]
    gaps = [y for y in range(300, 1000) if col2[y] < 55]
    out['row_gaps'] = gaps[:12]

    # focused row blue bbox
    blue = (a[..., 2] > a[..., 0] + 50) & (a[..., 2] > 130)
    blue[:, :970] = False
    blue[:250, :] = False
    blue[950:, :] = False
    ys, xs = np.where(blue)
    out['focus_row'] = (int(xs.min()), int(ys.min()), int(xs.max()), int(ys.max())) if len(xs) else None

    # header title/subtitle bands (right card, x 1130..1700)
    txtr = b[:, 1130:1700]
    rows = (txtr > 140).any(axis=1)
    bands, start = [], None
    for y, v in enumerate(rows):
        if v and start is None:
            start = y
        if not v and start is not None:
            bands.append((start, y - 1))
            start = None
    out['header_bands'] = [band for band in bands if band[1] - band[0] >= 3 and band[0] < 340]

    # chips of second row: horizontal profile at chip line
    row2_top = None
    # chip text band: find bright small text in x 1100..1500, y 460..500
    chip = b[455:510, 1100:1520]
    cols = (chip > 150).any(axis=0)
    xs3 = np.where(cols)[0]
    out['chip_text'] = (int(xs3.min()) + 1100, int(xs3.max()) + 1100) if len(xs3) else None

    print(f"--- {label} ---")
    for key, value in out.items():
        print(f"  {key}: {value}")
    return out


def main():
    os.makedirs(OUT_DIR, exist_ok=True)
    ref = Image.open(REF_PATH).convert('RGBA')
    ref1080 = ref.resize((1920, 1080), Image.LANCZOS)
    ours = render_ours()
    comp = ref1080.copy()
    comp.alpha_composite(ours)
    comp.convert('RGB').save(os.path.join(OUT_DIR, 'composite_1080.png'))

    ref_small = ref.convert('RGB').resize((1672, 941), Image.LANCZOS)
    our_small = comp.convert('RGB').resize((1672, 941), Image.LANCZOS)
    side = Image.new('RGB', (1672, 941 * 2 + 8), (255, 0, 0))
    side.paste(ref_small, (0, 0))
    side.paste(our_small, (0, 949))
    side.save(os.path.join(OUT_DIR, 'side_by_side.png'))

    base = np.asarray(ref1080.convert('RGB')).astype(int)
    our_arr = np.asarray(comp.convert('RGB')).astype(int)
    print(f"mean abs diff (1080p): {np.abs(base - our_arr).mean():.2f}")

    measure(ref1080, 'REFERENCE')
    measure(ours, 'OURS')
    print(f"outputs: {OUT_DIR}")


if __name__ == '__main__':
    main()
