#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
修复项目中因编码损坏产生的 U+FFFD 替换字符及未闭合字符串。
遍历 src 下所有 .vue .ts .js 文件，应用预定义的替换规则。
"""
import os
import sys

# U+FFFD 替换字符
R = '\ufffd'

# 替换规则：(错误片段, 正确文本)  错误片段中含 R 表示 U+FFFD
# 顺序：长的、具体的放前面，避免短规则误替换
REPLACEMENTS = [
    # content="列设? placement= 未闭合
    ('content="列设' + R + '? placement="top"', 'content="列设置" placement="top"'),
    # 筛选条件
    ('筛选条' + R + '?', '筛选条件'),
    # 列表/条件
    ('助学金批次列' + R + '?', '助学金批次列表'),
    ('学生处分列' + R + '?', '学生处分列表'),
    ('勤工助学考勤列' + R + '?', '勤工助学考勤列表'),
    ('评优评先奖项列' + R + '?', '评优评先奖项列表'),
    # 列设置
    ('列设' + R + '?', '列设置'),
    # 表格列配置
    ('表格列配' + R + '?', '表格列配置'),
    # 日期 placeholder
    ('start-placeholder="开始日' + R + '?', 'start-placeholder="开始日期'),
    ('end-placeholder="结束日' + R + '?', 'end-placeholder="结束日期'),
    ('开始日' + R + '?', '开始日期'),
    ('到期日' + R + '?', '到期日'),
    ('结束日' + R + '?', '结束日期'),
    # range-separator
    ('range-separator="' + R + '?', 'range-separator="至'),
    ('range-separator="' + R + R, 'range-separator="至'),
    # 格式化学期/季度/类别
    ('格式化学' + R + '?', '格式化学期'),
    ('格式化季' + R + '?', '格式化季度'),
    ('格式化类' + R + '?', '格式化类别'),
    # 负责人/所属类别
    ('负责' + R + '?', '负责人'),
    ('所属类' + R + '?', '所属类别'),
    # placeholder 未闭合 (缺结尾引号)
    ('请选择所属类' + R + '? ', '请选择所属类别" '),
    ('请输入姓' + R + '? ', '请输入姓名" '),
    ('请输入学' + R + '? ', '请输入学号" '),
    ('请输入班' + R + '? ', '请输入班号" '),
    # 班主任
    ('班主任姓' + R + '?', '班主任姓名'),
    ('班主任电' + R + '?', '班主任电话'),
    # 注释：用于图标
    ('用于图标' + R + '?）', '用于图标显示）'),
    ('用于图标' + R + '?', '用于图标显示'),
    # 初始化/数据
    ('初始' + R + '?', '初始化'),
    ('自动获取数' + R + '?', '自动获取数据'),
    # 删除批次
    ('删除批' + R + '?"', '删除批次"'),
    ('删除批' + R + '?', '删除批次'),
    # 特殊模板 注释
    ('学期列特殊模' + R + '?-->', '学期列特殊模板 -->'),
    ('人数列特殊模' + R + '?-->', '人数列特殊模板 -->'),
    ('成立时间列特殊模' + R + '?-->', '成立时间列特殊模板 -->'),
    ('需关爱类型列特殊模' + R + '?-->', '需关爱类型列特殊模板 -->'),
    ('记录时间列特殊模' + R + '?-->', '记录时间列特殊模板 -->'),
    ('干预结果列特殊模' + R + '?-->', '干预结果列特殊模板 -->'),
    ('考勤类型列特殊模' + R + '?-->', '考勤类型列特殊模板 -->'),
    ('落实情况列特殊模' + R + '?-->', '落实情况列特殊模板 -->'),
    # tableColumns label 未闭合
    ("label: '班主任姓" + R + "? },", "label: '班主任姓名' }, "),
    ("label: '班主任电" + R + "? },", "label: '班主任电话' }, "),
    ("label: '开始日" + R + "?, icon:", "label: '开始日期', icon:"),
    # 宿舍/班级/状态等
    ('宿舍' + R + '?', '宿舍号'),
    ('班级简' + R + '?', '班级简称'),
    ('操行平均' + R + '?', '操行平均分'),
    ('总评成绩平均' + R + '?', '总评成绩平均分'),
    ('处分状' + R + '?', '处分状态'),
    ('待审' + R + '?', '待审核'),
    ('审' + R + '状态', '审核状态'),
    # 更多常见
    ('请输入团员编' + R + '? ', '请输入团员编号" '),
    ('教学楼管理列' + R + '?', '教学楼管理列表'),
    ('原班' + R + '?', '原班级'),
    ("label: '请假开始时" + R + "?', icon:", "label: '请假开始时间', icon:"),
    ('类型列特殊模' + R + '?-->', '类型列特殊模板 -->'),
    ('入团时间列特殊模' + R + '?-->', '入团时间列特殊模板 -->'),
    ('考核时间列特殊模' + R + '?-->', '考核时间列特殊模板 -->'),
    # 确定要删除...吗？
    ('教学楼吗' + R + '?)', '教学楼吗？)'),
    # label 请假开始时间（逗号结尾变体）
    ("label: '请假开始时" + R + "?,", "label: '请假开始时间',"),
    # range-separator 双替换符
    ('range-separator="' + R + R + '"', 'range-separator="至"'),
    ('range-separator="' + R + R + '\n', 'range-separator="至"\n'),
    # range/start/end placeholder 缺结尾引号
    ('range-separator="至\n              start-placeholder="开始日期\n', 'range-separator="至"\n              start-placeholder="开始日期"\n'),
    ('start-placeholder="开始日期\n              end-placeholder="结束日期"', 'start-placeholder="开始日期"\n              end-placeholder="结束日期"'),
    # 工学交替/带班教师 列特殊模板
    ('工学交替结束时间列特殊模' + R + '?-->', '工学交替结束时间列特殊模板 -->'),
    ('带班教师列特殊模' + R + '?-->', '带班教师列特殊模板 -->'),
    # 班级简称 缺引号
    ("label: '班级简称 ", "label: '班级简称', "),
    ("label: '工学交替开始时" + R + "?, width:", "label: '工学交替开始时间', width:"),
    # 确定要删除这条记录吗？
    ('这条记录吗' + R + ')', '这条记录吗？)'),
    # 音/频 等（多字符损坏）
    ('播放' + R + R + R + '频', '播放音频'),
    # 团内职务/异动时间/附件列特殊模板
    ('团内职务列特殊模' + R + '?-->', '团内职务列特殊模板 -->'),
    ('异动时间列特殊模' + R + '?-->', '异动时间列特殊模板 -->'),
    ('附件列特殊模' + R + '?-->', '附件列特殊模板 -->'),
    # 现班号/格式化日期/异动类型/转制类型
    ("label: '现班" + R + "? },", "label: '现班号' },"),
    ('现班' + R + '?', '现班号'),
    ('格式化日' + R + '?', '格式化日期'),
    ('格式化异动类' + R + '?', '格式化异动类型'),
    ('格式化转制类' + R + '?', '格式化转制类型'),
    # 按钮文字：导出/新增
    ('导' + R + '出', '导出'),
    ('新' + R + '增', '新增'),
    # 班主任（label 等）
    ("label: '班主" + R + "?,", "label: '班主任',"),
    ("label: '班主" + R + "? ", "label: '班主任' "),
    # 将文件拖到此处，<em>（R?em 或 Rem）
    ('将文件拖到此处，' + R + '?em>', '将文件拖到此处，<em>'),
    ('将文件拖到此处，' + R + 'em>', '将文件拖到此处，<em>'),
    # 取消/确定 按钮（>??</el-button>）
    ('= false">' + R + R + '</el-button>', '= false">取消</el-button>'),
    ('importLoading">' + R + R + '</el-button>', 'importLoading">确定</el-button>'),
    (':loading="importLoading">' + R + R + '</el-button>', ':loading="importLoading">确定</el-button>'),
    ('取' + R + '消</el-button>', '取消</el-button>'),
    ('确' + R + '定</el-button>', '确定</el-button>'),
    # confirm 记录吗？）（R? 或 R）
    ('记录吗' + R + '?)', "记录吗？')"),
    ('记录吗' + R + ')', '记录吗？)'),
    # 注释与文案
    ('不实' + R + '?', '不实现'),
    ('只能上传一个文' + R + '?', '只能上传一个文件'),
    ('文件不存' + R + '?', '文件不存在'),
    # 时间
    ('日期时' + R + '?', '日期时间'),
    ('和时' + R + '?', '和时间'),
    ("label: '开始时" + R + "?,", "label: '开始时间',"),
    ('开始时' + R + '?', '开始时间'),
]

# 字面问号乱码（非 U+FFFD）的通用替换，仅用于明确无歧义的
LITERAL_QUESTION_REPLACEMENTS = [
    ('content="???" placement="top"', 'content="列设置" placement="top"'),
    ("col.prop !== '??'", "col.prop !== '操作'"),
    ('<el-table-column type="index" label="??" width="70"', '<el-table-column type="index" label="序号" width="70"'),
    ('<el-table-column label="??" width="150"', '<el-table-column label="操作" width="150"'),
    ('<el-table-column label="??" width="200"', '<el-table-column label="操作" width="200"'),
    ('<el-table-column label="??" width="250"', '<el-table-column label="操作" width="250"'),
    ('<span style="margin-left: 4px">??</span>\n            </template>', '<span style="margin-left: 4px">操作</span>\n            </template>'),
    ('@click="handleEdit(scope.row)">\n                ??\n              </el-button>', '@click="handleEdit(scope.row)">\n                编辑\n              </el-button>'),
    ('@click="handleDelete(scope.row)">\n                ??\n              </el-button>', '@click="handleDelete(scope.row)">\n                删除\n              </el-button>'),
    ('<!-- ?? -->\n        <el-table', '<!-- 表格 -->\n        <el-table'),
    ('<!-- ?? -->\n        <div class="pagination-wrapper">', '<!-- 分页 -->\n        <div class="pagination-wrapper">'),
    ('<el-button @click="importDialogVisible = false">??</el-button>', '<el-button @click="importDialogVisible = false">取消</el-button>'),
    ('@click="confirmInit" :loading="initLoading">??</el-button>', '@click="confirmInit" :loading="initLoading">确定</el-button>'),
    (':disabled="!importFile || importLoading">??</el-button>', ':disabled="!importFile || importLoading">确定</el-button>'),
    # label + prop 上下文
    ('label="??" prop="schoolYear"', 'label="学年" prop="schoolYear"'),
    ('label="??" prop="schoolTerm"', 'label="学期" prop="schoolTerm"'),
    ('label="??" prop="deptCode"', 'label="学院" prop="deptCode"'),
    ('label="??" prop="classCode"', 'label="班级" prop="classCode"'),
    ('label="??" prop="realName"', 'label="姓名" prop="realName"'),
    ('label="??" prop="gradeCurr"', 'label="年级" prop="gradeCurr"'),
    ('label="??" prop="year"', 'label="学年" prop="year"'),
    ('label="??" prop="period"', 'label="学期" prop="period"'),
    ('label="??" prop="buildNo"', 'label="楼号" prop="buildNo"'),
    ('label="??" prop="conductType"', 'label="类型" prop="conductType"'),
    ('label="??" prop="stuNo"', 'label="学号" prop="stuNo"'),
    ('label="??" prop="source"', 'label="来源" prop="source"'),
    ('label="??" prop="termId"', 'label="学期" prop="termId"'),
    ('label="???" prop="roomNo"', 'label="宿舍号" prop="roomNo"'),
    ('label="????" prop="grade"', 'label="入学年份" prop="grade"'),
    ('label="????" prop="checkStatus"', 'label="审核状态" prop="checkStatus"'),
    ('label="????" prop="effectiveMoney"', 'label="可用余额" prop="effectiveMoney"'),
    ('label="????" prop="isLiveNum"', 'label="在住人数" prop="isLiveNum"'),
    ('label="????" prop="costMoney"', 'label="补贴金额" prop="costMoney"'),
    ('label="????" prop="punlishMonth"', 'label="处分月份" prop="punlishMonth"'),
    ('label="????" prop="punlishLevel"', 'label="处分级别" prop="punlishLevel"'),
    ('label="????" prop="ruleName"', 'label="奖项名称" prop="ruleName"'),
    # placeholder 按上下文（需避免误替换，用较长片段）
    ('placeholder="?????" \n              clearable\n              filterable', 'placeholder="请选择学年" \n              clearable\n              filterable'),
    ('placeholder="?????" \n              clearable\n              style="width: 200px">', 'placeholder="请选择学期" \n              clearable\n              style="width: 200px">'),
    ('placeholder="?????" \n              clearable\n              filterable\n              style="width: 200px">', 'placeholder="请选择学院" \n              clearable\n              filterable\n              style="width: 200px">'),
    ('placeholder="?????" \n              clearable\n              style="width: 200px" />', 'placeholder="请输入姓名" \n              clearable\n              style="width: 200px" />'),
    ('placeholder="??????" \n              clearable', 'placeholder="请输入宿舍号" \n              clearable'),
    ('placeholder="???????" \n              clearable', 'placeholder="请输入奖项名称" \n              clearable'),
    ('placeholder="??????" \n              clearable', 'placeholder="请输入年级" \n              clearable'),
    ('placeholder="???????" \n              clearable', 'placeholder="请选择审核状态" \n              clearable'),
    ('placeholder="??????" \n              :min="0"', 'placeholder="请输入可用余额" \n              :min="0"'),
    ('placeholder="???" \n              clearable', 'placeholder="请输入人数" \n              clearable'),
    ('placeholder="?????" \n              clearable\n              filterable\n              style="width: 200px"\n              @change', 'placeholder="请选择学院" \n              clearable\n              filterable\n              style="width: 200px"\n              @change'),
    ('placeholder="??????" \n              style="width: 100%"', 'placeholder="请输入补贴金额" \n              style="width: 100%"'),
    ('placeholder="??????" \n              clearable\n              style="width: 200px">', 'placeholder="请选择处分月份" \n              clearable\n              style="width: 200px">'),
    ('placeholder="???????" \n              clearable\n              style="width: 200px">', 'placeholder="请选择处分级别" \n              clearable\n              style="width: 200px">'),
    # 按钮文字
    ('@click="handleSearch">??</el-button>', '@click="handleSearch">查询</el-button>'),
    ('@click="handleReset">??</el-button>', '@click="handleReset">重置</el-button>'),
    # 选项
    ('<el-option label="????" value="history"', '<el-option label="历史数据" value="history"'),
    ('<el-option label="??" value="attendance"', '<el-option label="考勤" value="attendance"'),
]

def fix_file(filepath):
    try:
        with open(filepath, 'r', encoding='utf-8', errors='replace') as f:
            content = f.read()
    except Exception as e:
        print(f"  [SKIP] read error: {e}", file=sys.stderr)
        return False
    original = content
    for wrong, right in REPLACEMENTS:
        if wrong in content:
            content = content.replace(wrong, right)
    for wrong, right in LITERAL_QUESTION_REPLACEMENTS:
        if wrong in content:
            content = content.replace(wrong, right)
    if content != original:
        try:
            with open(filepath, 'w', encoding='utf-8') as f:
                f.write(content)
            return True
        except Exception as e:
            print(f"  [SKIP] write error: {e}", file=sys.stderr)
            return False
    return False

def main():
    root = os.path.join(os.path.dirname(__file__), '..', 'src')
    root = os.path.abspath(root)
    exts = ('.vue', '.ts', '.js')
    modified = []
    for dirpath, _dirnames, filenames in os.walk(root):
        for name in filenames:
            if not name.endswith(exts):
                continue
            path = os.path.join(dirpath, name)
            rel = os.path.relpath(path, root)
            if fix_file(path):
                modified.append(rel)
    if modified:
        print(f"Fixed {len(modified)} file(s):")
        for p in sorted(modified):
            print(f"  {p}")
    else:
        print("No files needed fixing.")
    return 0

if __name__ == '__main__':
    sys.exit(main())
