"""PROOF-OF-CONCEPT: detect the printed grey separator rules on a newspaper page
using classical CV (no ML, no API). Horizontal + vertical thin straight lines are
extracted by morphological opening with long thin kernels, then overlaid on the
page so we can see whether they recover article boundaries.

Usage: venv/bin/python3 _detect_rules.py <page_png> [out_png]
"""
import sys
from pathlib import Path

import cv2
import numpy as np


def detect_rules(gray, min_frac=0.10, thickness=9):
    """Return (h_lines, v_lines) as lists of (x1,y1,x2,y2).
    min_frac: a rule must be at least this fraction of page width/height long.
    """
    H, W = gray.shape
    # The rules are mid-grey on white. Invert + threshold so lines become white.
    # Use a gentle adaptive-ish binarisation: anything clearly darker than paper.
    blur = cv2.GaussianBlur(gray, (3, 3), 0)
    bw = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

    def extract(kernel_len, horizontal):
        if horizontal:
            k = cv2.getStructuringElement(cv2.MORPH_RECT, (kernel_len, 1))
        else:
            k = cv2.getStructuringElement(cv2.MORPH_RECT, (1, kernel_len))
        opened = cv2.morphologyEx(bw, cv2.MORPH_OPEN, k, iterations=1)
        # thicken slightly so near-collinear fragments merge
        opened = cv2.dilate(opened, cv2.getStructuringElement(
            cv2.MORPH_RECT, (thickness, thickness)))
        cnts, _ = cv2.findContours(opened, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        lines = []
        for c in cnts:
            x, y, w, h = cv2.boundingRect(c)
            if horizontal and w >= min_frac * W and h <= 60:
                lines.append((x, y + h // 2, x + w, y + h // 2, w))
            if (not horizontal) and h >= min_frac * H and w <= 60:
                lines.append((x + w // 2, y, x + w // 2, y + h, h))
        return lines

    h_lines = extract(int(min_frac * W), horizontal=True)
    v_lines = extract(int(min_frac * H), horizontal=False)
    return h_lines, v_lines


def main(png_path, out_path=None):
    png_path = Path(png_path)
    out_path = Path(out_path) if out_path else Path(f"/tmp/rules_{png_path.stem}.png")
    img = cv2.imread(str(png_path))
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    H, W = gray.shape
    h_lines, v_lines = detect_rules(gray)

    print(f"page {png_path.name}  {W}x{H}")
    print(f"  horizontal rules: {len(h_lines)}")
    for x1, y1, x2, y2, ln in sorted(h_lines, key=lambda L: L[1]):
        print(f"    y={y1:>5}  x[{x1:>4}..{x2:>4}]  len={ln}")
    print(f"  vertical rules: {len(v_lines)}")
    for x1, y1, x2, y2, ln in sorted(v_lines, key=lambda L: L[0]):
        print(f"    x={x1:>5}  y[{y1:>4}..{y2:>4}]  len={ln}")

    for x1, y1, x2, y2, ln in h_lines:
        cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 6)      # red = horizontal
    for x1, y1, x2, y2, ln in v_lines:
        cv2.line(img, (x1, y1), (x2, y2), (255, 0, 0), 6)      # blue = vertical
    cv2.imwrite(str(out_path), img)
    print(f"\noverlay written: {out_path}")


if __name__ == "__main__":
    main(sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else None)
