# -*- coding: utf-8 -*-
"""
长度单位转换器（全单位版）
------------------------------------------------------------
所有单位统一以"米 (m)"为基准，覆盖：
  · 国际单位制 (SI) 全量级：从 幺米(ym) 到 尧米(Ym)
  · 英制 / 美制
  · 中国市制
  · 航海 / 测地
  · 天文学单位
  · 物理学自然单位（原子、核物理、普朗克）
  · 印刷 / 排版单位（绝对单位，需参考基准）
  · 历史 / 传统单位
------------------------------------------------------------
用法：python length_converter.py   → 直接弹出图形窗口
依赖：Python 自带 tkinter，无需额外安装。
"""

import tkinter as tk
from tkinter import ttk

# =====================================================================
# 单位数据库
# 结构：分组 -> { "显示名": 换算成米的倍数 }
# 注：相对单位（像素/字符等）无法绝对换算，已标注说明并尽量给参考值。
# =====================================================================
UNITS = {
    "🔬 SI 国际单位制（公制全量级）": {
        "尧米 (Ym)": 1e24,
        "泽米 (Zm)": 1e21,
        "艾米 (Em)": 1e18,
        "拍米 (Pm)": 1e15,
        "太米 (Tm)": 1e12,
        "京米/吉米 (Gm)": 1e9,
        "兆米 (Mm)": 1e6,
        "千米/公里 (km)": 1e3,
        "百米 (hm)": 1e2,
        "十米 (dam)": 1e1,
        "米 (m)": 1.0,
        "分米 (dm)": 1e-1,
        "厘米 (cm)": 1e-2,
        "毫米 (mm)": 1e-3,
        "忽米/丝 (cmm)": 1e-5,
        "微米 (μm)": 1e-6,
        "纳米 (nm)": 1e-9,
        "皮米 (pm)": 1e-12,
        "飞米/费米 (fm)": 1e-15,
        "阿米 (am)": 1e-18,
        "仄米 (zm)": 1e-21,
        "幺米 (ym)": 1e-24,
    },
    "🇬🇧 英制 / 美制": {
        "英里 (mi)": 1609.344,
        "码 (yd)": 0.9144,
        "英尺 (ft)": 0.3048,
        "英寸 (in)": 0.0254,
        "密耳/千分之一英寸 (mil)": 2.54e-5,
        "英寻/寻 (fathom)": 1.8288,
        "浪/弗隆 (fur)": 201.168,
        "链 (chain)": 20.1168,
        "杆 (rod)": 5.0292,
        "令 (league, 法定)": 4828.032,
        "掌/手 (hand)": 0.1016,
    },
    "🇨🇳 中国市制": {
        "市里": 500.0,
        "市引": 33.333333333333336,
        "市丈": 3.3333333333333335,
        "市尺": 0.3333333333333333,
        "市寸": 0.03333333333333333,
        "市分": 0.0033333333333333335,
        "市厘": 0.0003333333333333333,
        "市毫": 3.333333333333333e-05,
    },
    "🌊 航海 / 测地": {
        "海里/浬 (nmi, 国际)": 1852.0,
        "海里 (UK, 英制)": 1853.184,
        "链(海军) (cable)": 185.2,
        "英尺(美测量) (ft-US)": 0.3048006096012192,
    },
    "🚢 中国传统长度": {
        "里(古, 1800尺)": 576.0,
        "引(10丈)": 31.2,
        "丈(10尺)": 3.12,
        "尺(清营造尺≈32cm)": 0.32,
        "寸": 0.032,
        "分": 0.0032,
        "厘": 0.00032,
        "毫": 3.2e-05,
    },
    "🔭 天文学单位": {
        "哈勃半径/可观测宇宙": 4.4e26,
        "吉秒差距 (Gpc)": 3.08567758128e25,
        "兆秒差距 (Mpc)": 3.08567758128e22,
        "千秒差距 (kpc)": 3.08567758128e19,
        "秒差距 (pc)": 3.08567758128e16,
        "光年 (ly)": 9.4607304725808e15,
        "拍米 (Pm, 天文)": 1e15,
        "光月": 7.71731480518e15,
        "光日": 2.59020683712e13,
        "光时": 1.0792528488e12,
        "光分": 1.798754748e10,
        "光秒": 299792458.0,
        "天文单位 (AU)": 149597870700.0,
        "月球距离 (LD)": 384402000.0,
        "地球半径 (R⊕)": 6371000.0,
    },
    "⚛ 物理学自然单位": {
        "普朗克长度 (lₚ)": 1.616255e-35,
        "埃 (Å)": 1e-10,
        "玻尔半径 (a₀)": 5.29177210903e-11,
        "X单位 (Xu)": 1.002e-13,
        "电子经典半径 (rₑ)": 2.8179403227e-15,
        "核子作用长度 (fm, 费米)": 1e-15,
    },
    "🖨 印刷 / 排版（绝对长度）": {
        "派卡/十二点 (pc)": 0.004233333333333333,
        "点/磅 (pt)": 0.00035277777777777776,
        "像素 (px, 96 DPI)": 0.0002645833333333333,
        "缇 (twip)": 1.763888888888889e-05,
    },
    "📜 历史 / 传统单位": {
        "肘/腕尺 (cubit, 约)": 0.4572,
        "掌距 (span)": 0.2286,
        "掌宽 (palm)": 0.0762,
        "指宽 (digit)": 0.01905,
        "步 (pace, 古罗马约)": 1.48,
        "仞 (周制, 约1.6m)": 1.6,
        "咫 (周制, 约20cm)": 0.2,
        "寻 (xun, 8尺)": 2.56,
    },
}

# 相对单位说明（无法绝对换算）
RELATIVE_UNITS = {
    "em": "相对单位：等于当前元素的字体大小，无绝对米值",
    "rem": "相对单位：等于根元素(html)字体大小，默认 16px",
    "%": "相对单位：相对于父元素大小的百分比",
    "vw": "相对单位：1vw = 视口宽度的 1%",
    "vh": "相对单位：1vh = 视口高度的 1%",
    "字符 (ch)": "相对单位：约等于 '0' 字形的宽度",
    "ex": "相对单位：约等于小写字母 'x' 的高度",
}

# 把分组结构展开成平铺字典 + 下拉列表顺序
ALL_UNITS = {}
CATEGORIES = {}
for cat, units in UNITS.items():
    CATEGORIES[cat] = list(units.keys())
    ALL_UNITS.update(units)

# 下拉框显示顺序：按类别分组
DROPDOWN_ORDER = [u for cat in UNITS for u in UNITS[cat]]


# =====================================================================
# 工具函数
# =====================================================================
def format_number(value):
    """智能格式化：极大/极小数用科学计数法，普通数去多余0"""
    if value == 0:
        return "0"
    abs_val = abs(value)
    if abs_val >= 1e12 or abs_val < 1e-9:
        return f"{value:.6e}"
    text = f"{value:.10f}".rstrip("0").rstrip(".")
    return text


def short_name(unit_key):
    """取显示名中的中文/简称部分用于结果展示"""
    return unit_key.split(" ")[0]


# =====================================================================
# 转换逻辑
# =====================================================================
def convert():
    from_unit = combo_from.get()
    to_unit = combo_to.get()

    # 相对单位提示
    if from_unit in RELATIVE_UNITS or to_unit in RELATIVE_UNITS:
        label_result.config(text="⚠ 选中了相对单位（em/rem/%/vw…），无法做绝对换算，请选其他单位")
        return

    try:
        value = float(entry_value.get())
    except ValueError:
        label_result.config(text="⚠ 请输入有效的数字")
        return

    # 统一基准：先转成米，再转目标单位
    meters = value * ALL_UNITS[from_unit]
    result = meters / ALL_UNITS[to_unit]

    label_result.config(
        text=f"{format_number(value)} {short_name(from_unit)} = {format_number(result)} {short_name(to_unit)}"
    )


# =====================================================================
# 图形界面
# =====================================================================
root = tk.Tk()
root.title("📐 长度单位转换器（全单位版）")
root.geometry("620x380")
root.resizable(False, False)

style = ttk.Style()
try:
    style.theme_use("clam")
except Exception:
    pass

main = ttk.Frame(root, padding=15)
main.pack(fill=tk.BOTH, expand=True)

# 标题
ttk.Label(main, text="📐 长度单位转换器", font=("Microsoft YaHei", 17, "bold")).grid(
    row=0, column=0, columnspan=4, pady=(0, 2)
)
ttk.Label(main, text=f"共 {len(ALL_UNITS)} 个绝对单位 · 覆盖 SI / 英制 / 市制 / 天文 / 物理 / 排版",
          font=("Microsoft YaHei", 8), foreground="#888").grid(
    row=1, column=0, columnspan=4, pady=(0, 12))

# 数值输入
ttk.Label(main, text="数值:", font=("Microsoft YaHei", 11)).grid(row=2, column=0, sticky="e", padx=5, pady=5)
entry_value = ttk.Entry(main, font=("Consolas", 13), width=14, justify="center")
entry_value.grid(row=2, column=1, sticky="w", padx=5)
entry_value.insert(0, "1")
entry_value.bind("<Return>", lambda e: convert())

# 来源单位
ttk.Label(main, text="从:", font=("Microsoft YaHei", 11)).grid(row=2, column=2, sticky="e", padx=5)
combo_from = ttk.Combobox(main, values=DROPDOWN_ORDER, font=("Microsoft YaHei", 9), width=22, state="readonly")
combo_from.grid(row=2, column=3, sticky="w", padx=5)
combo_from.set("米 (m)")

# 目标单位
ttk.Label(main, text="到:", font=("Microsoft YaHei", 11)).grid(row=3, column=2, sticky="e", padx=5, pady=8)
combo_to = ttk.Combobox(main, values=DROPDOWN_ORDER, font=("Microsoft YaHei", 9), width=22, state="readonly")
combo_to.grid(row=3, column=3, sticky="w", padx=5, pady=8)
combo_to.set("千米/公里 (km)")

# 转换按钮
btn = ttk.Button(main, text="🔄 转换", command=convert)
btn.grid(row=4, column=0, columnspan=4, pady=10, ipadx=20)

# 结果
label_result = ttk.Label(main, text="", font=("Consolas", 13, "bold"), foreground="#2E86AB")
label_result.grid(row=5, column=0, columnspan=4, pady=5)

# 底部提示：列出类别
cat_text = "  |  ".join(f"{cat}" for cat in UNITS.keys())
ttk.Label(main, text="类别：", font=("Microsoft YaHei", 8), foreground="#666").grid(
    row=6, column=0, columnspan=4, sticky="w", pady=(15, 0))
ttk.Label(main, text=cat_text, font=("Microsoft YaHei", 7), foreground="#999",
          wraplength=580, justify="left").grid(
    row=7, column=0, columnspan=4, sticky="w")

# 默认先算一次
convert()

root.mainloop()
