# -*- coding: utf-8 -*-
"""
Office 文件（docx/xlsx/pptx）解压提取明文，用于提供给 AI（如 RAG、摘要等）。
本质为 ZIP+XML，不依赖 Office。
"""
import io
import logging
import os
import zipfile
import xml.etree.ElementTree as ET

from django.conf import settings

from django_base_ai.system.models import FileList

logger = logging.getLogger(__name__)


def get_file_stream_from_request(request):
    """
    从 request 获取可读文件流：优先 file_id（从 FileList 读路径），否则从 FILES 取 file。
    返回 (file_like, name)，file_like 为 BytesIO；无文件时返回 (None, None)。
    """
    file_id = request.data.get("file_id") or request.query_params.get("file_id")
    if file_id:
        file_obj = FileList.objects.filter(id=file_id).first()
        if not file_obj:
            logger.debug("get_file_stream file_id=%s 未找到", file_id)
            return None, None
        path = os.path.join(settings.BASE_DIR, file_obj.file_url.lstrip("/"))
        if not os.path.isfile(path):
            logger.warning("get_file_stream 文件不存在 path=%s", path)
            return None, None
        with open(path, "rb") as f:
            return io.BytesIO(f.read()), file_obj.name or ""
    uploaded = request.FILES.get("file")
    if not uploaded:
        logger.debug("get_file_stream 无 file_id 且无 FILES.file")
        return None, None
    buf = io.BytesIO()
    for chunk in uploaded.chunks():
        buf.write(chunk)
    buf.seek(0)
    return buf, getattr(uploaded, "name", "") or ""


def extract_docx_text(file_like):
    """从 docx (ZIP) 中读取 word/document.xml，提取所有 w:t 节点文本。"""
    texts = []
    with zipfile.ZipFile(file_like, "r") as z:
        try:
            xml_bytes = z.read("word/document.xml")
        except KeyError as e:
            logger.debug("extract_docx_text 无 word/document.xml: %s", e)
            return ""
        root = ET.fromstring(xml_bytes)
        for elem in root.iter():
            if "}" in elem.tag and elem.tag.split("}")[-1] == "t":
                if elem.text:
                    texts.append(elem.text)
                if elem.tail and elem.tail.strip():
                    texts.append(elem.tail)
    return "".join(texts).strip()


def extract_xlsx_text(file_like):
    """从 xlsx (ZIP) 中读取 sharedStrings 与各 sheet，提取可见文本。"""
    with zipfile.ZipFile(file_like, "r") as z:
        shared_strings = []
        try:
            sst_bytes = z.read("xl/sharedStrings.xml")
            sst = ET.fromstring(sst_bytes)
            ns = {"main": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"}
            for si in sst.findall(".//main:si", ns):
                t = si.find("main:t", ns)
                if t is not None and t.text:
                    shared_strings.append(t.text)
                else:
                    parts = []
                    for r in si.findall(".//main:t", ns):
                        if r.text:
                            parts.append(r.text)
                        if r.tail:
                            parts.append(r.tail)
                    shared_strings.append("".join(parts))
        except KeyError as e:
            logger.debug("extract_xlsx_text 无 sharedStrings: %s", e)
        all_text = []
        for name in sorted(z.namelist()):
            if name.startswith("xl/worksheets/sheet") and name.endswith(".xml"):
                try:
                    sheet_bytes = z.read(name)
                    root = ET.fromstring(sheet_bytes)
                    ns = {"main": "http://schemas.openxmlformats.org/spreadsheetml/2006/main"}
                    for c in root.findall(".//main:c", ns):
                        v = c.find("main:v", ns)
                        if v is not None and v.text:
                            t_attr = "{http://schemas.openxmlformats.org/spreadsheetml/2006/main}t"
                            if c.get(t_attr) == "s":
                                idx = int(v.text)
                                if 0 <= idx < len(shared_strings):
                                    all_text.append(shared_strings[idx])
                            else:
                                all_text.append(v.text)
                except (ET.ParseError, ValueError) as e:
                    logger.debug("extract_xlsx_text 解析 sheet %s 跳过: %s", name, e)
                    continue
        return " ".join(shared_strings + all_text).strip()


def extract_pptx_text(file_like):
    """从 pptx (ZIP) 中读取各 slide 的 XML，提取 a:t 节点文本。"""
    texts = []
    with zipfile.ZipFile(file_like, "r") as z:
        slide_names = sorted(
            [n for n in z.namelist() if n.startswith("ppt/slides/slide") and n.endswith(".xml")]
        )
        for name in slide_names:
            try:
                xml_bytes = z.read(name)
                root = ET.fromstring(xml_bytes)
                for elem in root.iter():
                    if "}" in elem.tag and elem.tag.split("}")[-1] == "t":
                        if elem.text:
                            texts.append(elem.text)
            except (ET.ParseError, KeyError) as e:
                logger.debug("extract_pptx_text 解析 %s 跳过: %s", name, e)
                continue
    return "".join(texts).strip()
