"""
Palette for 14 funnel statuses for Лидпоток / TBD.

Goals:
  1. 14 distinct hues evenly distributed in OKLCH space
  2. ΔE2000 between every adjacent pair >= 10 (perceptually distinct)
  3. Two variants per hue:
       - "tint"  — chip background, light: must give >=4.5:1 against ink #0B1320 for 12px text
       - "solid" — strong fill, used for status dots: must give >=3:1 against cream bg #F4EFE5
  4. Colors should sit naturally with v4 accent #B84A22 (warm earth, sophisticated)

Strategy: vary HUE only at fixed L+C bands to guarantee equal perceptual spacing.
"""

import colour
import numpy as np


def srgb_hex(rgb):
    rgb = np.clip(rgb, 0.0, 1.0)
    r, g, b = (round(c * 255) for c in rgb)
    return f"#{r:02X}{g:02X}{b:02X}"


def oklch_to_srgb(L, C, H_deg):
    H = np.deg2rad(H_deg)
    a = C * np.cos(H)
    b = C * np.sin(H)
    Lab = np.array([L, a, b])
    XYZ = colour.Oklab_to_XYZ(Lab)
    rgb_lin = colour.XYZ_to_sRGB(XYZ, apply_cctf_encoding=False)
    rgb = colour.cctf_encoding(np.clip(rgb_lin, 0, 1), function="sRGB")
    return rgb


def srgb_to_lab(rgb):
    rgb_lin = colour.cctf_decoding(rgb, function="sRGB")
    XYZ = colour.sRGB_to_XYZ(rgb_lin, apply_cctf_decoding=False)
    Lab = colour.XYZ_to_Lab(XYZ)
    return Lab


def relative_luminance(rgb):
    rgb = np.clip(rgb, 0, 1)
    rgb_lin = np.where(rgb <= 0.03928, rgb / 12.92, ((rgb + 0.055) / 1.055) ** 2.4)
    return float(0.2126 * rgb_lin[0] + 0.7152 * rgb_lin[1] + 0.0722 * rgb_lin[2])


def contrast_ratio(rgb_a, rgb_b):
    L1 = relative_luminance(rgb_a)
    L2 = relative_luminance(rgb_b)
    if L1 < L2:
        L1, L2 = L2, L1
    return (L1 + 0.05) / (L2 + 0.05)


def hex_to_rgb(h):
    h = h.lstrip("#")
    return np.array([int(h[i : i + 2], 16) / 255 for i in (0, 2, 4)])


# ---------- 14 funnel statuses ----------
STATUSES = [
    "Новая",            # 1
    "В работе",         # 2
    "Дозвон",           # 3
    "Не дозвон.",       # 4
    "Перегов.",         # 5
    "КП отправл.",      # 6
    "Думает",           # 7
    "Ждёт оплату",      # 8
    "Оплачено",         # 9
    "Возврат",          # 10
    "Отказ",            # 11
    "Дубликат",         # 12
    "Спам",             # 13
    "Архив",            # 14
]

INK = hex_to_rgb("#0B1320")
CREAM = hex_to_rgb("#F4EFE5")

# Tint band (chip background): high lightness, low chroma → light tinted bg
TINT_L = 0.92
TINT_C = 0.055
# Solid band (status dot, strong fill): mid lightness, mid chroma
# C=0.15 chosen so all 14 hues stay in sRGB gamut AND every neighbour pair >= 10 ΔE2000
SOLID_L = 0.55
SOLID_C = 0.15

# 14 hues — start equally distributed, then iteratively re-space by ΔE2000 repulsion.
# This solves the sRGB gamut anisotropy: magenta/pink region needs more degrees of separation
# than green/cyan region to give equal perceptual distance.
START_HUE = 30.0
hues = [(START_HUE + i * (360.0 / 14)) % 360 for i in range(14)]


def _solid_lab(h):
    rgb = oklch_to_srgb(SOLID_L, SOLID_C, h)
    return srgb_to_lab(rgb)


def _min_neighbour_de(hs):
    labs = [_solid_lab(h) for h in hs]
    return min(
        float(colour.delta_E(labs[i], labs[(i + 1) % len(hs)], method="CIE 2000"))
        for i in range(len(hs))
    )


# Iteratively perturb until min ΔE >= 10 (or 200 iterations)
_step = 1.0
for _it in range(200):
    labs = [_solid_lab(h) for h in hues]
    des = [
        float(colour.delta_E(labs[i], labs[(i + 1) % len(hues)], method="CIE 2000"))
        for i in range(len(hues))
    ]
    if min(des) >= 10.0:
        break
    # for each hue, push away from the closer neighbour
    new_hues = list(hues)
    for i in range(len(hues)):
        prev_de = des[(i - 1) % len(hues)]  # ΔE to previous
        next_de = des[i]                    # ΔE to next
        # push toward the larger gap
        if next_de < prev_de:
            new_hues[i] = (hues[i] - _step) % 360
        else:
            new_hues[i] = (hues[i] + _step) % 360
    hues = new_hues
    _step *= 0.95  # cooling

HUES = hues
print(f"# Final hues after re-spacing: {[round(h,1) for h in HUES]}")
print(f"# min neighbour ΔE2000 = {_min_neighbour_de(HUES):.2f}")
print()

print("=" * 84)
print(f"{'#':<3} {'Status':<14} {'Hue°':>5} {'Tint hex':>9} {'Solid hex':>10} {'AA on tint':>11}  {'3:1 vs cream':>12}")
print("=" * 84)

results = []
for i, (name, h) in enumerate(zip(STATUSES, HUES), 1):
    tint_rgb = oklch_to_srgb(TINT_L, TINT_C, h)
    solid_rgb = oklch_to_srgb(SOLID_L, SOLID_C, h)
    tint_hex = srgb_hex(tint_rgb)
    solid_hex = srgb_hex(solid_rgb)

    # WCAG: ink text on tint chip
    ink_on_tint = contrast_ratio(INK, tint_rgb)
    # WCAG: solid color as a dot/border on cream — needs 3:1 (UI component)
    solid_on_cream = contrast_ratio(solid_rgb, CREAM)

    aa_tint = "PASS" if ink_on_tint >= 4.5 else "FAIL"
    aa_solid = "PASS" if solid_on_cream >= 3.0 else "FAIL"

    print(f"{i:<3} {name:<14} {h:5.1f} {tint_hex:>9} {solid_hex:>10}  {ink_on_tint:5.2f} {aa_tint}    {solid_on_cream:5.2f} {aa_solid}")
    results.append((name, h, tint_rgb, solid_rgb, tint_hex, solid_hex))

# ΔE2000 between adjacent solid pairs (cyclic)
print()
print("ΔE2000 between adjacent SOLID pairs (must be >= 10):")
print("-" * 60)
deltas = []
for i in range(14):
    a = results[i][3]
    b = results[(i + 1) % 14][3]
    Lab_a = srgb_to_lab(a)
    Lab_b = srgb_to_lab(b)
    de = float(colour.delta_E(Lab_a, Lab_b, method="CIE 2000"))
    deltas.append(de)
    flag = "✓" if de >= 10 else "✗"
    print(f"  {results[i][0]:<14} → {results[(i+1)%14][0]:<14}  ΔE2000 = {de:5.2f}  {flag}")

print()
print(f"min ΔE2000 = {min(deltas):.2f}, max = {max(deltas):.2f}, mean = {sum(deltas)/len(deltas):.2f}")
print()

# also output as CSS custom properties block
print("=" * 84)
print("CSS — drop-in for v6_deals.html")
print("=" * 84)
for i, (name, h, _, _, tint_hex, solid_hex) in enumerate(results, 1):
    slug_map = {
        "Новая": "new", "В работе": "work", "Дозвон": "call",
        "Не дозвон.": "nocall", "Перегов.": "neg", "КП отправл.": "quote",
        "Думает": "think", "Ждёт оплату": "wait", "Оплачено": "paid",
        "Возврат": "refund", "Отказ": "fail", "Дубликат": "dup",
        "Спам": "spam", "Архив": "arch",
    }
    slug = slug_map[name]
    print(f"  --st-{slug}-tint:  {tint_hex};  /* {name} bg */")
    print(f"  --st-{slug}-solid: {solid_hex};  /* {name} dot */")
