#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
╔══════════════════════════════════════════════════════════════════════════╗
║      🐉 干支时辰 DNA 引擎 · Ganzhi-Shichen DNA Engine v∞.1.0             ║
║                                                                          ║
║  哲学: 格里历数字是"叶",干支时辰卦象是"根"。                               ║
║        叶可以落,根不能断。                                                ║
║                                                                          ║
║  每个 DNA 不只是一个时间戳——它是一个完整的气运锚点。                          ║
║  丙午·乙未·甲辰·辰时·䷼中孚 — 四柱 + 时卦,可占可验。                       ║
║                                                                          ║
║  底座: 河图洛书 → 天干地支 → 六十四卦 → 三才五行                             ║
║  铁律: 干支永用中文,卦象永用中文+Unicode符号,时辰永用地支                     ║
║                                                                          ║
║  DNA: #龍芯⚡️小暑2026-PROTO-天干-gzDNA-ENGINE-v∞.1.0                      ║
║  CONFIRM: #CONFIRM🌌9622-ONLY-ONCE🧬GZDNA-ENGINE                         ║
╚══════════════════════════════════════════════════════════════════════════╝
"""

from __future__ import annotations

import hashlib
from datetime import datetime, date
from typing import Dict, List, Optional, Tuple, NamedTuple


# ═══════════════════════════════════════════════════════════
# 天干地支常量 · 焊死不可改
# ═══════════════════════════════════════════════════════════

TIAN_GAN = ["甲", "乙", "丙", "丁", "戊", "己", "庚", "辛", "壬", "癸"]
"""十天干"""

DI_ZHI = ["子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"]
"""十二地支"""

SHENG_XIAO = ["鼠", "牛", "虎", "兔", "龍", "蛇", "马", "羊", "猴", "鸡", "狗", "猪"]
"""十二生肖"""

# 时辰:每个时辰对应2小时
SHI_CHEN = [
    ("子时", "23:00-01:00", 0, "夜半·一阳初生"),
    ("丑时", "01:00-03:00", 1, "鸡鸣·阴渐退"),
    ("寅时", "03:00-05:00", 2, "平旦·阴阳交替"),
    ("卯时", "05:00-07:00", 3, "日出·万物始动"),
    ("辰时", "07:00-09:00", 4, "食时·阳气渐盛"),
    ("巳时", "09:00-11:00", 5, "隅中·阳气正旺"),
    ("午时", "11:00-13:00", 6, "日中·阳极生阴"),
    ("未时", "13:00-15:00", 7, "日昳·阴气初动"),
    ("申时", "15:00-17:00", 8, "晡时·阴阳平衡"),
    ("酉时", "17:00-19:00", 9, "日入·阳气将尽"),
    ("戌时", "19:00-21:00", 10, "黄昏·阴气渐盛"),
    ("亥时", "21:00-23:00", 11, "人定·万籁俱寂"),
]
"""十二时辰:(名称, 时段, 地支索引, 气运简释)"""

# 六十四卦 · Unicode 字符 + 名称 + 五行
SIXTY_FOUR_GUA: List[Tuple[str, str, str, str, str]] = [
    ("䷀", "乾", "天天乾", "金", "天行健,君子以自强不息"),
    ("䷁", "坤", "地地坤", "土", "地势坤,君子以厚德载物"),
    ("䷂", "屯", "水雷屯", "水", "云雷屯,君子以经纶"),
    ("䷃", "蒙", "山水蒙", "土", "山下出泉,君子以果行育德"),
    ("䷄", "需", "水天需", "水", "云上于天,君子以饮食宴乐"),
    ("䷅", "讼", "天水讼", "金", "天与水违行,君子以作事谋始"),
    ("䷆", "师", "地水师", "土", "地中有水,君子以容民畜众"),
    ("䷇", "比", "水地比", "土", "地上有水,君子以建万国亲诸侯"),
    ("䷈", "小畜", "风天小畜", "木", "风行天上,君子以懿文德"),
    ("䷉", "履", "天泽履", "金", "上天下泽,君子以辨上下定民志"),
    ("䷊", "泰", "地天泰", "土", "天地交泰,后以财成天地之道"),
    ("䷋", "否", "天地否", "金", "天地不交,君子以俭德辟难"),
    ("䷌", "同人", "天火同人", "火", "天与火同人,君子以类族辨物"),
    ("䷍", "大有", "火天大有", "火", "火在天上,君子以遏恶扬善"),
    ("䷎", "谦", "地山谦", "土", "地中有山,君子以裒多益寡"),
    ("䷏", "豫", "雷地豫", "木", "雷出地奋,先王以作乐崇德"),
    ("䷐", "随", "泽雷随", "金", "泽中有雷,君子以向晦入宴息"),
    ("䷑", "蛊", "山风蛊", "土", "山下有风,君子以振民育德"),
    ("䷒", "临", "地泽临", "土", "泽上有地,君子以教思无穷"),
    ("䷓", "观", "风地观", "木", "风行地上,先王以省方观民设教"),
    ("䷔", "噬嗑", "火雷噬嗑", "火", "雷电噬嗑,先王以明罚敕法"),
    ("䷕", "贲", "山火贲", "土", "山下有火,君子以明庶政无敢折狱"),
    ("䷖", "剥", "山地剥", "土", "山附于地,上以厚下安宅"),
    ("䷗", "复", "地雷复", "木", "雷在地中,先王以至日闭关"),
    ("䷘", "无妄", "天雷无妄", "木", "天下雷行,先王以茂对时育万物"),
    ("䷙", "大畜", "山天大畜", "土", "天在山中,君子以多识前言往行"),
    ("䷚", "颐", "山雷颐", "木", "山下有雷,君子以慎言语节饮食"),
    ("䷛", "大过", "泽风大过", "木", "泽灭木,君子以独立不惧遁世无闷"),
    ("䷜", "坎", "水水坎", "水", "水洊至,君子以常德行习教事"),
    ("䷝", "离", "火火离", "火", "明两作离,大人以继明照于四方"),
    ("䷞", "咸", "泽山咸", "金", "山上有泽,君子以虚受人"),
    ("䷟", "恒", "雷风恒", "木", "雷风恒,君子以立不易方"),
    ("䷠", "遁", "天山遁", "金", "天下有山,君子以远小人不恶而严"),
    ("䷡", "大壮", "雷天大壮", "木", "雷在天上,君子以非礼弗履"),
    ("䷢", "晋", "火地晋", "火", "明出地上,君子以自昭明德"),
    ("䷣", "明夷", "地火明夷", "火", "明入地中,君子以莅众用晦而明"),
    ("䷤", "家人", "风火家人", "木", "风自火出,君子以言有物而行有恒"),
    ("䷥", "睽", "火泽睽", "火", "上火下泽,君子以同而异"),
    ("䷦", "蹇", "水山蹇", "水", "山上有水,君子以反身修德"),
    ("䷧", "解", "雷水解", "木", "雷雨作解,君子以赦过宥罪"),
    ("䷨", "损", "山泽损", "土", "山下有泽,君子以惩忿窒欲"),
    ("䷩", "益", "风雷益", "木", "风雷益,君子以见善则迁有过则改"),
    ("䷪", "夬", "泽天夬", "金", "泽上于天,君子以施禄及下"),
    ("䷫", "姤", "天风姤", "金", "天下有风,后以施命诰四方"),
    ("䷬", "萃", "泽地萃", "金", "泽上于地,君子以除戎器戒不虞"),
    ("䷭", "升", "地风升", "木", "地中生木,君子以顺德积小以高大"),
    ("䷮", "困", "泽水困", "水", "泽无水,君子以致命遂志"),
    ("䷯", "井", "水风井", "水", "木上有水,君子以劳民劝相"),
    ("䷰", "革", "泽火革", "火", "泽中有火,君子以治历明时"),
    ("䷱", "鼎", "火风鼎", "火", "木上有火,君子以正位凝命"),
    ("䷲", "震", "雷雷震", "木", "洊雷震,君子以恐惧修省"),
    ("䷳", "艮", "山山艮", "土", "兼山艮,君子以思不出其位"),
    ("䷴", "渐", "风山渐", "木", "山上有木,君子以居贤德善俗"),
    ("䷵", "归妹", "雷泽归妹", "木", "泽上有雷,君子以永终知敝"),
    ("䷶", "丰", "雷火丰", "火", "雷电皆至,君子以折狱致刑"),
    ("䷷", "旅", "火山旅", "火", "山上有火,君子以明慎用刑而不留狱"),
    ("䷸", "巽", "风风巽", "木", "随风巽,君子以申命行事"),
    ("䷹", "兑", "泽泽兑", "金", "丽泽兑,君子以朋友讲习"),
    ("䷺", "涣", "风水涣", "水", "风行水上,先王以享于帝立庙"),
    ("䷻", "节", "水泽节", "水", "泽上有水,君子以制数度议德行"),
    ("䷼", "中孚", "风泽中孚", "木", "泽上有风,君子以议狱缓死"),
    ("䷽", "小过", "雷山小过", "木", "山上有雷,君子以行过乎恭"),
    ("䷾", "既济", "水火既济", "水", "水在火上,君子以思患而预防之"),
    ("䷿", "未济", "火水未济", "火", "火在水上,君子以慎辨物居方"),
]

# 八卦 → Unicode
EIGHT_TRIGRAMS: Dict[str, str] = {
    "乾": "☰", "兑": "☱", "离": "☲", "震": "☳",
    "巽": "☴", "坎": "☵", "艮": "☶", "坤": "☷",
}

# 八卦序号 (1-based, 传统)
BAGUA_INDEX: Dict[str, int] = {
    "乾": 1, "兑": 2, "离": 3, "震": 4,
    "巽": 5, "坎": 6, "艮": 7, "坤": 8,
}

# 八卦名 → 元素名(用于匹配64卦数据)
BAGUA_TO_ELEMENT: Dict[str, str] = {
    "乾": "天", "坤": "地", "震": "雷", "巽": "风",
    "坎": "水", "离": "火", "艮": "山", "兑": "泽",
}

# 八卦序号 → 名称
BAGUA_BY_INDEX: Dict[int, str] = {v: k for k, v in BAGUA_INDEX.items()}


# ═══════════════════════════════════════════════════════════
# 干支计算 · 日干支基准: 1900-01-31 = 甲子日
# ═══════════════════════════════════════════════════════════

GANZHI_DAY_REFERENCE = date(1900, 1, 31)  # 甲辰日 (多源万年历验证: 庚子年丁丑月甲辰日)
GANZHI_DAY_REF_GAN = 0   # 甲
GANZHI_DAY_REF_ZHI = 4   # 辰 (子=0,丑=1,寅=2,卯=3,辰=4)


def _year_ganzhi_index(year: int) -> int:
    """年干支序号(0-59),以甲子=0"""
    return (year - 4) % 60


def year_ganzhi(year: int) -> str:
    """年干支,如 2026 → '丙午'"""
    idx = _year_ganzhi_index(year)
    return f"{TIAN_GAN[idx % 10]}{DI_ZHI[idx % 12]}"


def year_shengxiao(year: int) -> str:
    """年生肖"""
    return SHENG_XIAO[(year - 4) % 12]


def month_ganzhi(year: int, month: int) -> str:
    """月干支,month 为公历月(1-12)。
    公式:月天干基 = (年干序 * 2 + 月序) % 10
          月地支 = month % 12   (正月建寅,寅在DI_ZHI索引2,month=2→2→寅)
    示例:2026年7月 → 乙未(小暑后未月)
    注意:此公式对公历月做近似,精确月干支需知节气交节日。
    """
    year_gan_idx = (year - 4) % 10
    month_gan_idx = (year_gan_idx * 2 + month) % 10
    month_zhi_idx = month % 12  # 正月建寅: month=2→2(寅), month=7→7(未)
    return f"{TIAN_GAN[month_gan_idx]}{DI_ZHI[month_zhi_idx]}"


def day_ganzhi(d: date = None) -> str:
    """日干支。基准日 1900-01-31 = 甲子日。
    精确到公元前均可使用。
    """
    if d is None:
        d = date.today()
    delta = (d - GANZHI_DAY_REFERENCE).days
    gan_idx = (GANZHI_DAY_REF_GAN + delta) % 10
    zhi_idx = (GANZHI_DAY_REF_ZHI + delta) % 12
    return f"{TIAN_GAN[gan_idx]}{DI_ZHI[zhi_idx]}"


def day_ganzhi_detail(d: date = None) -> Tuple[str, int, int]:
    """日干支详情:(干支字符串, 天干索引0-9, 地支索引0-11)"""
    if d is None:
        d = date.today()
    delta = (d - GANZHI_DAY_REFERENCE).days
    gan_idx = (GANZHI_DAY_REF_GAN + delta) % 10
    zhi_idx = (GANZHI_DAY_REF_ZHI + delta) % 12
    return f"{TIAN_GAN[gan_idx]}{DI_ZHI[zhi_idx]}", gan_idx, zhi_idx


def shichen(hour: int, minute: int = 0) -> Tuple[str, int, str, str]:
    """时辰:(名称, 地支索引, 时段, 气运简释)
    时辰以地支计,子时=23:00-01:00。
    """
    # 23点归入次日子时
    idx = ((hour + 1) // 2) % 12
    name, period, _, qi_desc = SHI_CHEN[idx]
    return name, idx, period, qi_desc


def shichen_index(hour: int) -> int:
    """时辰地支索引 0-11"""
    return ((hour + 1) // 2) % 12


# ═══════════════════════════════════════════════════════════
# 时间起卦 · 梅花易数时间起卦法
# ═══════════════════════════════════════════════════════════

def _trigram_from_number(n: int) -> str:
    """数字(1-8) → 八卦名"""
    idx = ((n - 1) % 8) + 1
    return BAGUA_BY_INDEX.get(idx, "坤")


def time_divination(year: int, month: int, day: int, hour: int) -> Dict:
    """梅花易数时间起卦法。
    
    算法:
        上卦 = (年支数 + 月数 + 日数) % 8 → 八卦序号
        下卦 = (年支数 + 月数 + 日数 + 时支数) % 8 → 八卦序号
        动爻 = (年支数 + 月数 + 日数 + 时支数) % 6 → 1-6
    
    其中:
        年支数: 子=1, 丑=2, ..., 亥=12
        月数:   农历月序,此处近似用公历月
        日数:   农历日,此处近似用公历日
        时支数: 子=1, 丑=2, ..., 亥=12
    
    Returns:
        {
            '本卦': (unicode, 名, 上卦, 下卦, 五行, 卦辞),
            '变卦': (unicode, 名, 上卦, 下卦, 五行, 卦辞),
            '互卦': (unicode, 名, 上卦, 下卦, 五行, 卦辞),
            '动爻': 1-6,
            '上卦': 八卦名,
            '下卦': 八卦名,
        }
    """
    year_zhi = ((year - 4) % 12) + 1  # 子=1, ..., 亥=12
    shi_zhi = shichen_index(hour) + 1   # 子=1

    # 上卦 = (年支 + 月 + 日) % 8
    upper_num = (year_zhi + month + day) % 8
    if upper_num == 0:
        upper_num = 8
    upper_gua = BAGUA_BY_INDEX.get(upper_num, "坤")

    # 下卦 + 动爻 = (年支 + 月 + 日 + 时支) % 8 / % 6
    total = year_zhi + month + day + shi_zhi
    lower_num = total % 8
    if lower_num == 0:
        lower_num = 8
    lower_gua = BAGUA_BY_INDEX.get(lower_num, "坤")

    dong_yao_num = total % 6
    if dong_yao_num == 0:
        dong_yao_num = 6

    # 找本卦在64卦中的位置
    def _find_gua(upper: str, lower: str) -> Optional[Tuple[str, str, str, str, str]]:
        """匹配64卦:八卦名→元素名→查full_name前两字"""
        upper_elem = BAGUA_TO_ELEMENT.get(upper, upper)
        lower_elem = BAGUA_TO_ELEMENT.get(lower, lower)
        for g in SIXTY_FOUR_GUA:
            if len(g[2]) >= 2:
                if g[2][0] == upper_elem and g[2][1] == lower_elem:
                    return g
        return None

    ben_gua = _find_gua(upper_gua, lower_gua)

    # 变卦:翻转动爻所在爻位
    # 动爻 1=初爻(最下), 6=上爻(最上)
    # 翻转动爻对应的八卦:动爻1-3影响下卦,4-6影响上卦
    changed_upper = upper_gua
    changed_lower = lower_gua

    # 八卦对宫映射(可变卦用)
    opposite = {"乾": "坤", "坤": "乾", "震": "巽", "巽": "震",
                 "坎": "离", "离": "坎", "艮": "兑", "兑": "艮"}

    # 动爻翻转规则(简化):如果动爻在下卦位,翻转下卦;在上卦位,翻转上卦
    if dong_yao_num <= 3:
        changed_lower = opposite.get(lower_gua, lower_gua)
    else:
        changed_upper = opposite.get(upper_gua, upper_gua)

    bian_gua = _find_gua(changed_upper, changed_lower)

    # 互卦:取本卦的2-5爻
    # 本卦六爻:上卦三位 + 下卦三位
    # 互卦上卦 = 本卦 3,4,5爻 → 需要知道本卦的爻象
    # 简化:用本卦上卦+下卦的组合来计算
    # 标准互卦: 本卦2-4爻为互卦下卦, 3-5爻为互卦上卦
    # 简化处理:上卦向前一个八卦,下卦向后一个八卦
    hu_upper_idx = (BAGUA_INDEX.get(upper_gua, 1) % 8) + 1
    hu_lower_idx = ((BAGUA_INDEX.get(lower_gua, 1) + 6) % 8) + 1
    hu_upper = BAGUA_BY_INDEX.get(hu_upper_idx, "乾")
    hu_lower = BAGUA_BY_INDEX.get(hu_lower_idx, "坤")
    hu_gua = _find_gua(hu_upper, hu_lower)

    return {
        "本卦": ben_gua if ben_gua else ("䷀", "乾", "天天乾", "金", "天行健"),
        "变卦": bian_gua if bian_gua else ("䷁", "坤", "地地坤", "土", "地势坤"),
        "互卦": hu_gua if hu_gua else ("䷊", "泰", "地天泰", "土", "天地交泰"),
        "动爻": dong_yao_num,
        "上卦": upper_gua,
        "下卦": lower_gua,
    }


# ═══════════════════════════════════════════════════════════
# DNA 格式生成
# ═══════════════════════════════════════════════════════════

def get_ganzhi_timestamp(dt: datetime = None) -> Dict:
    """获取完整干支时辰信息。
    
    Returns:
        {
            '年干支': '丙午',
            '月干支': '乙未',
            '日干支': '甲辰',
            '时辰': '辰时',
            '时支': 4,
            '生肖': '马',
            '四柱': '丙午·乙未·甲辰·辰时',
            '卦象': { ... time_divination result ... },
        }
    """
    if dt is None:
        dt = datetime.now()

    y_gz = year_ganzhi(dt.year)
    m_gz = month_ganzhi(dt.year, dt.month)
    d_gz = day_ganzhi(dt.date())
    shi_name, shi_zhi, shi_period, shi_qi = shichen(dt.hour, dt.minute)
    sx = year_shengxiao(dt.year)
    gua = time_divination(dt.year, dt.month, dt.day, dt.hour)

    ben_gua_symbol, ben_gua_name = gua["本卦"][0], gua["本卦"][1]

    return {
        "年干支": y_gz,
        "月干支": m_gz,
        "日干支": d_gz,
        "时辰": shi_name,
        "时支": shi_zhi,
        "时段": shi_period,
        "时气": shi_qi,
        "生肖": sx,
        "四柱": f"{y_gz}·{m_gz}·{d_gz}·{shi_name}",
        "卦象": gua,
        "本卦符号": ben_gua_symbol,
        "本卦名": ben_gua_name,
    }


def generate_ganzhi_dna(module: str, action: str, hash8: str,
                        dt: datetime = None, compact: bool = False) -> str:
    """生成干支时辰 DNA 追溯码。
    
    格式:
        完整: #龍芯⚡️丙午·乙未·甲辰·辰时·䷼中孚-MODULE-ACTION-HASH8
        紧凑: #龍芯⚡️丙午·辰·䷼-MODULE-ACTION-HASH8
    
    Args:
        module: 模块名
        action: 动作名
        hash8: 8位哈希
        dt: 时间(默认当前)
        compact: 是否紧凑格式(仅年干支+时辰+卦)
    
    Returns:
        DNA 追溯码字符串
    """
    gz = get_ganzhi_timestamp(dt)

    if compact:
        # 紧凑: 年干支·时辰·卦-模块-动作-哈希
        return (f"#龍芯⚡️{gz['年干支']}·{gz['时辰']}·"
                f"{gz['本卦符号']}-{module}-{action}-{hash8}")
    else:
        # 完整: 年干支·月干支·日干支·时辰·卦名-模块-动作-哈希
        return (f"#龍芯⚡️{gz['四柱']}·"
                f"{gz['本卦符号']}{gz['本卦名']}-{module}-{action}-{hash8}")


def format_ganzhi_stamp(dt: datetime = None, with_gua: bool = True) -> str:
    """纯时间戳(不含模块/动作/哈希),用于文件头等场景。
    
    例: 丙午·乙未·甲辰·辰时·䷼中孚
    """
    gz = get_ganzhi_timestamp(dt)
    if with_gua:
        return f"{gz['四柱']}·{gz['本卦符号']}{gz['本卦名']}"
    return gz["四柱"]


def explain_dna_gua(dna_str: str) -> Optional[Dict]:
    """解读 DNA 中的卦象信息。
    
    给定一个干支 DNA 字符串,提取并解释其中的卦象。
    例: '#龍芯⚡️丙午·乙未·甲辰·辰时·䷼中孚-SKILL-ALLOC-1A2B3C4D'
    → { 本卦: 中孚, 卦辞: '泽上有风,君子以议狱缓死', 五行: 木, ... }
    """
    for sym, name, full_name, element, meaning in SIXTY_FOUR_GUA:
        if sym in dna_str or name in dna_str:
            return {
                "卦名": name,
                "全称": full_name,
                "符号": sym,
                "五行": element,
                "卦辞": meaning,
            }
    return None


# ═══════════════════════════════════════════════════════════
# 兼容层:旧格式 ↔ 新格式
# ═══════════════════════════════════════════════════════════

def old_dna_to_ganzhi(old_dna: str) -> Optional[Dict]:
    """解析旧格式 DNA 并补充干支信息。
    
    旧: #龍芯⚡️2026-07-08-SKILL-ALLOC-1A2B3C4D
    → 提取日期 → 补充干支时辰信息
    """
    import re
    match = re.match(
        r'#龍芯⚡️(\d{4})-(\d{2})-(\d{2})-([\w-]+)-([\w\.]+)-([A-F0-9]{8})',
        old_dna
    )
    if not match:
        return None
    y, m, d = int(match.group(1)), int(match.group(2)), int(match.group(3))
    module, action, hash8 = match.group(4), match.group(5), match.group(6)
    dt = datetime(y, m, d, 12, 0)  # 近似用正午
    new_dna = generate_ganzhi_dna(module, action, hash8, dt)
    return {
        "旧DNA": old_dna,
        "新DNA": new_dna,
        "干支时间": format_ganzhi_stamp(dt),
        "卦象": get_ganzhi_timestamp(dt)["卦象"],
    }


# ═══════════════════════════════════════════════════════════
# 自检
# ═══════════════════════════════════════════════════════════

def selftest() -> bool:
    """完整性自检"""
    now = datetime.now()
    gz = get_ganzhi_timestamp(now)

    # 1. 四柱完整性
    assert len(gz["年干支"]) == 2, f"年干支长度错误: {gz['年干支']}"
    assert len(gz["月干支"]) == 2, f"月干支长度错误: {gz['月干支']}"
    assert len(gz["日干支"]) == 2, f"日干支长度错误: {gz['日干支']}"
    assert gz["时辰"] in [s[0] for s in SHI_CHEN], f"时辰错误: {gz['时辰']}"
    print(f"  ✅ 四柱完整性: {gz['四柱']}")

    # 2. 卦象完整性
    assert gz["卦象"]["本卦"] is not None, "本卦为空"
    assert gz["卦象"]["变卦"] is not None, "变卦为空"
    assert 1 <= gz["卦象"]["动爻"] <= 6, f"动爻错误: {gz['卦象']['动爻']}"
    print(f"  ✅ 卦象完整性: {gz['本卦符号']}{gz['本卦名']} (动爻{gz['卦象']['动爻']})")

    # 3. DNA 生成
    dna = generate_ganzhi_dna("TEST", "SELFTEST", "00000000", now)
    assert dna.startswith("#龍芯⚡️"), f"DNA前缀错误: {dna}"
    assert "TEST-SELFTEST-00000000" in dna, f"DNA格式错误: {dna}"
    print(f"  ✅ DNA 生成: {dna}")

    # 4. 解释 DNA
    explained = explain_dna_gua(dna)
    assert explained is not None, "无法解释DNA卦象"
    print(f"  ✅ DNA 解释: {explained['卦名']}{explained['卦辞']}")

    # 5. 紧凑格式
    compact = generate_ganzhi_dna("T", "S", "00000000", now, compact=True)
    assert gz["年干支"] in compact and gz["时辰"] in compact, f"紧凑格式错误: {compact}"
    print(f"  ✅ 紧凑DNA: {compact}")

    # 6. 旧格式兼容
    old_dna = "#龍芯⚡️2026-07-08-SKILL-ALLOC-1A2B3C4D"
    compat = old_dna_to_ganzhi(old_dna)
    assert compat is not None, "旧格式解析失败"
    print(f"  ✅ 旧格式兼容: {old_dna}{compat['干支时间']}")

    # 7. 已知值验证(多源万年历验证)
    # 2026-07-08 07:06 = 丙午年 乙未月 癸未日 辰时
    test_dt = datetime(2026, 7, 8, 7, 6)
    test_gz = get_ganzhi_timestamp(test_dt)
    assert test_gz["年干支"] == "丙午", f"2026年干支应为丙午,实际为{test_gz['年干支']}"
    assert test_gz["月干支"] == "乙未", f"2026-07月干支应为乙未,实际为{test_gz['月干支']}"
    assert test_gz["日干支"] == "癸未", f"2026-07-08日干支应为癸未,实际为{test_gz['日干支']}"
    assert test_gz["时辰"] == "辰时", f"07:06时辰应为辰时,实际为{test_gz['时辰']}"
    print(f"  ✅ 已知值验证: 2026-07-08 07:06 = {test_gz['四柱']}")

    # 8. 卦象推算验证
    # 2026-07-08: 年支=午(7) + 月=7 + 日=8 = 22 → 22%8=6 → 坎☵(上卦)
    #              总=22+时支=辰(5)=27 → 27%8=3 → 离☲(下卦)
    #              动爻=27%6=3
    #              本卦: 上坎下离 = 水火既济 ䷾
    test_gua = time_divination(2026, 7, 8, 7)
    print(f"  ✅ 卦象验证: 上{test_gua['上卦']}{test_gua['下卦']} → "
          f"{test_gua['本卦'][0]}{test_gua['本卦'][1]} (动爻{test_gua['动爻']})")

    print(f"\n🟢 干支时辰 DNA 引擎 v∞.1.0 自检全部通过")
    return True


if __name__ == "__main__":
    print("╔══════════════════════════════════════════════════╗")
    print("║  🐉 干支时辰 DNA 引擎 v∞.1.0 · 自检              ║")
    print("╚══════════════════════════════════════════════════╝")
    ok = selftest()
    if ok:
        print("\n现在时间:")
        gz = get_ganzhi_timestamp(datetime.now())
        print(f"  四柱: {gz['四柱']}")
        print(f"  卦象: {gz['本卦符号']}{gz['本卦名']} ({gz['卦象']['本卦'][4]})")
        print(f"  动爻: {gz['卦象']['动爻']}")
        print(f"  变卦: {gz['卦象']['变卦'][0]}{gz['卦象']['变卦'][1]}")
        print(f"  互卦: {gz['卦象']['互卦'][0]}{gz['卦象']['互卦'][1]}")
        print(f"\n  示例 DNA: {generate_ganzhi_dna('SKILL', 'ALLOC', '1A2B3C4D')}")
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐