ns = params_kw.copy()
doc_id = ns.get('doc_id', '')
kb_id = ns.get('kb_id', '')
folder_id = ns.get('folder_id', '')
folder_label = ns.get('folder_label', '全部文件')

if not doc_id:
    return json.dumps({"status": "error", "error": "doc_id required"}, ensure_ascii=False)

env = request._run_ns
userorgid = await env.get_userorgid()

async with get_sor_context(env, 'rag') as sor:
    recs = await sor.sqlExe(
        "SELECT file_path, file_size, kb_id FROM documents WHERE id=${id}$",
        {"id": doc_id})
    if not recs:
        return json.dumps({"status": "error", "error": "file not found"}, ensure_ascii=False)
    doc = recs[0]
    file_path = doc.file_path
    file_size = doc.file_size

    # Delete document + chunks
    await sor.sqlExe("DELETE FROM document_chunks WHERE doc_id=${doc_id}$", {"doc_id": doc_id})
    await sor.sqlExe("DELETE FROM documents WHERE id=${id}$", {"id": doc_id})

    # Update KB stats
    await sor.sqlExe(
        "UPDATE knowledge_bases SET doc_count=GREATEST(doc_count-1, 0), total_size=GREATEST(total_size-${size}$, 0) WHERE id=${kb_id}$",
        {"size": file_size, "kb_id": kb_id})

# Delete physical file via env.realpath
if file_path and file_path.startswith("/idfile/"):
    try:
        real_path = env.realpath(file_path)
        if os.path.exists(real_path):
            os.remove(real_path)
    except Exception:
        pass

# Re-query and return refreshed file list
db = DBPools()
dbname = get_module_dbname('rag')
rows = []
async with db.sqlorContext(dbname) as sor:
    if folder_id and folder_id != '__root__':
        recs = await sor.sqlExe(
            "SELECT id, file_name, file_type, file_size, file_path, status, chunk_count, created_at FROM documents WHERE kb_id=${kb_id}$ AND folder_id=${folder_id}$ ORDER BY created_at DESC",
            {"kb_id": kb_id, "folder_id": folder_id})
    else:
        recs = await sor.sqlExe(
            "SELECT id, file_name, file_type, file_size, file_path, status, chunk_count, created_at FROM documents WHERE kb_id=${kb_id}$ AND (folder_id IS NULL OR folder_id='') ORDER BY created_at DESC",
            {"kb_id": kb_id})
    for r in recs:
        rows.append({
            "id": r.id, "file_name": r.file_name, "file_type": r.file_type or '',
            "file_size": r.file_size or 0, "file_path": r.file_path or '',
            "status": r.status or '', "chunk_count": r.chunk_count or 0,
            "created_at": str(r.created_at)[:16] if r.created_at else ''
        })

def fmt_size(sz):
    if sz < 1024: return str(sz) + "B"
    elif sz < 1024*1024: return str(round(sz/1024, 1)) + "KB"
    else: return str(round(sz/(1024*1024), 1)) + "MB"

header = {
    "widgettype": "HBox",
    "options": {"width": "100%", "padding": "10px 0", "borderBottom": "1px solid #e0e0e0", "alignItems": "center"},
    "subwidgets": [
        {"widgettype": "Text", "options": {"text": "📄 " + folder_label, "cfontsize": 14, "fontWeight": "bold", "color": "#333"}},
        {"widgettype": "Text", "options": {"text": "（" + str(len(rows)) + " 个文件）", "cfontsize": 12, "color": "#999", "marginLeft": "8px"}},
        {"widgettype": "Text", "options": {"text": "", "css": "filler"}}
    ]
}

file_widgets = [header]
if not rows:
    file_widgets.append({"widgettype": "Text", "options": {"text": "暂无文件", "cfontsize": 13, "color": "#aaa", "halign": "center", "marginTop": "40px"}})
else:
    del_url_base = entire_url('./delete_file.dspy')
    for f in rows:
        sc = "#50b86c"; st = "已完成"
        if f["status"] == "pending": sc = "#e6a23c"; st = "处理中"
        elif f["status"] == "error": sc = "#f56c6c"; st = "失败"
        file_url = entire_url(f["file_path"])
        durl = del_url_base + "?kb_id=" + kb_id + "&doc_id=" + f["id"] + "&folder_id=" + folder_id + "&folder_label=" + folder_label
        row = {
            "widgettype": "HBox",
            "options": {"width": "100%", "padding": "8px 12px", "borderBottom": "1px solid #f0f0f0", "alignItems": "center"},
            "subwidgets": [
                {"widgettype": "Text", "options": {"text": "📄 " + f["file_name"], "cfontsize": 13, "color": "#333", "textAlign": "left", "css": "filler"}},
                {"widgettype": "Text", "options": {"text": f["file_type"].upper(), "cfontsize": 11, "color": "#999", "marginRight": "8px", "cwidth": 5, "textAlign": "center"}},
                {"widgettype": "Text", "options": {"text": fmt_size(f["file_size"]), "cfontsize": 11, "color": "#999", "marginRight": "8px", "cwidth": 8, "textAlign": "right"}},
                {"widgettype": "Text", "options": {"text": st, "cfontsize": 11, "color": sc, "marginRight": "8px", "cwidth": 6, "textAlign": "center"}},
                {"widgettype": "Text", "options": {"text": f["created_at"], "cfontsize": 11, "color": "#999", "marginRight": "8px", "cwidth": 12}},
                {"widgettype": "HBox", "options": {"spacing": "4px"}, "subwidgets": [
                    {"widgettype": "Text", "options": {"text": "👁", "cfontsize": 14, "css": "clickable", "color": "#4a90d9", "title": "查看"},
                     "binds": [{"wid": "self", "event": "click", "actiontype": "script", "target": "self",
                         "script": "window.open(" + json.dumps(file_url) + ",'_blank')"}]},
                    {"widgettype": "Text", "options": {"text": "⬇", "cfontsize": 14, "css": "clickable", "color": "#50b86c", "title": "下载"},
                     "binds": [{"wid": "self", "event": "click", "actiontype": "script", "target": "self",
                         "script": "var a=document.createElement('a');a.href=" + json.dumps(file_url) + ";a.download='';document.body.appendChild(a);a.click();document.body.removeChild(a)"}]},
                    {"widgettype": "Text", "options": {"text": "🗑", "cfontsize": 14, "css": "clickable", "color": "#f56c6c", "title": "删除"},
                     "binds": [{"wid": "self", "event": "click", "actiontype": "urlwidget", "target": "file_list_panel", "mode": "replace",
                         "options": {"url": durl}}]}
                ]}
            ]}
        file_widgets.append(row)

result = {"widgettype": "VBox", "options": {"width": "100%", "spacing": "0"}, "subwidgets": file_widgets}
return result
