#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
check_mdx.py — 检查 mdx 源文件(.txt) 中的重复条目与循环引用

规则（简化版）：
    按 “</>” 分割成若干段；每段第一行 = 关键字，其余行 = 内容；
    内容不以 “@” 开头的段，直接丢弃（只检查内容以 @ 开头的重定向条目）；
    重定向内容形如 “@@@LINK=目标”，目标取 “=” 之后的部分。

检查：
    1) 重复条目：关键字 + 目标 完全相同的条目出现了多次。
    2) 循环引用：重定向链成环，如 a->b->c->a，或 a->a 自指。

无异常：打印提示；有异常：在源文件同目录生成 mdx_check_report_<时间戳>.txt。
"""

import os
import datetime
from collections import defaultdict, OrderedDict


def parse_entries(text):
    """按 </> 分割；返回 [(keyword, target), ...]（只保留内容以 @ 开头的段）。"""
    entries = []
    for part in text.split("\n</>\n"):
        lines = part.strip().splitlines()
        if not lines:
            continue
        keyword = lines[0].strip()                  # 第一行 = 关键字
        content = "\n".join(lines[1:]).strip()      # 其余 = 内容
        if not content.startswith("@"):             # 内容不以 @ 开头 -> 丢弃
            continue
        target = ""
        if "=" in content:                          # 目标 = “=” 之后
            target = content.split("=", 1)[1].strip().splitlines()[0].strip()
        if keyword:
            entries.append((keyword, target))
    return entries


def find_duplicates(entries):
    """返回 {(keyword, target): 次数}，仅出现 >=2 次的。"""
    count = OrderedDict()
    for e in entries:
        count[e] = count.get(e, 0) + 1
    return {k: v for k, v in count.items() if v > 1}


def find_cycles(entries):
    """在有向图 keyword -> target 上找环，返回环列表（首尾相同）。"""
    graph = defaultdict(list)
    for kw, tgt in entries:
        if tgt:
            graph[kw].append(tgt)

    state = {}          # 0/未访问, 1/访问中, 2/已完成
    cycles = []

    def dfs(u, path):
        state[u] = 1
        path.append(u)
        for v in graph.get(u, []):
            if v == u:
                cycles.append([u, u])
            elif state.get(v, 0) == 1:
                cycles.append(path[path.index(v):] + [v])
            elif state.get(v, 0) == 0:
                dfs(v, path)
        path.pop()
        state[u] = 2

    for kw in list(graph):
        if state.get(kw, 0) == 0:
            dfs(kw, [])

    # 去重
    seen = set()
    unique = []
    for c in cycles:
        core = c[:-1]
        if not core:
            continue
        m = min(range(len(core)), key=lambda i: core[i])
        key = tuple(core[m:] + core[:m])
        if key not in seen:
            seen.add(key)
            unique.append(c)
    return unique


def build_report(path, entries, duplicates, cycles):
    now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    L = []
    L.append("=" * 60)
    L.append("MDX 源文件检查报告")
    L.append("=" * 60)
    L.append("检查时间 : %s" % now)
    L.append("源文件   : %s" % os.path.abspath(path))
    L.append("检查条目 : %d 条（内容以 @ 开头的重定向条目）" % len(entries))
    L.append("")

    if duplicates:
        L.append("【重复条目】（关键字 + 目标 完全相同）")
        for (kw, tgt), n in duplicates.items():
            L.append("  %s@@@LINK=%s   出现 %d 次" % (kw, tgt, n))
        L.append("")
    else:
        L.append("【重复条目】未发现。")
        L.append("")

    if cycles:
        L.append("【循环引用】（重定向链成环）")
        for i, c in enumerate(cycles, 1):
            L.append("  环 %d: %s" % (i, " -> ".join(c)))
        L.append("")
    else:
        L.append("【循环引用】未发现。")
        L.append("")

    L.append("=" * 60)
    L.append("结论: %s" % ("未发现重复条目或循环引用。" if not duplicates and not cycles
                          else "存在上述问题，请核查。"))
    L.append("=" * 60)
    return "\n".join(L)


def main():
    print("=== MDX 源文件检查工具 ===")
    path = input("请输入 mdx 源文件路径 (.txt): ")
    path = path[3:-1] if path.startswith('&') else path
    if not path or not os.path.isfile(path):
        print("错误: 文件不存在: %s" % path)
        return

    with open(path, "r", encoding="utf-8", errors="replace") as f:
        text = f.read()

    entries = parse_entries(text)
    duplicates = find_duplicates(entries)
    cycles = find_cycles(entries)

    if not duplicates and not cycles:
        print("✓ 检查完成：未发现重复条目或循环引用。")
        print("  检查了 %d 条重定向条目。" % len(entries))
        return

    report = build_report(path, entries, duplicates, cycles)
    ts = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    report_path = os.path.join(os.path.dirname(os.path.abspath(path)),
                               "mdx_check_report_%s.txt" % ts)
    with open(report_path, "w", encoding="utf-8") as f:
        f.write(report)
    print("✗ 检查发现问题，报告已生成:\n  %s" % report_path)
    print("-" * 50)
    print(report)


if __name__ == "__main__":
    while True:
        main()