import pdfplumber
import sys
import os
from ollama import Client
import re
import json
#OLLAMA_SERVER = "http://140.116.240.181:45015/"
OLLAMA_SERVER="https://primehub.aic.ncku.edu.tw/console/apps/ollama-0-13-4-xa9c7"
STAGE2_MODEL = "gpt-oss:20b"
client = Client(host=OLLAMA_SERVER, headers={'Content-Type': 'application/json'})

# --- Prompt A: 針對表格 (維持原本最強的版本) ---
# 將「解析表格」的輸出要求改為 JSON，並加入 section_title 的提取邏輯
PROMPT_TABLE = """【角色】你是一個高階資料解析助理。
【任務】將輸入的文字內容（包含標題、表格、備註）轉換為 JSON Array。

【重要原則】
為了配合系統格式，所有內容（包含標題、表格數據、備註）都必須封裝在同一個 JSON Array 中。**嚴禁**在 JSON Array 之外輸出任何文字。

【JSON 欄位定義】
每一筆資料包含兩個欄位：
1. **section_title**: 章節或項目名稱。
2. **content**: 該項目的完整內容描述。

【處理邏輯 (請依序執行)】

**步驟 1：處理文件標題 (若存在)**
   - 檢查表格上方是否有標題文字。
   - 若有，請建立一個物件：
     {{ "section_title": "表單資訊", "content": "標題內容..." }}
   - 若無，則跳過此步驟。

**步驟 2：處理表格內容 (核心)**
   - 逐行解析 Markdown 表格。
   - **section_title**: 取自表格的第一欄（例如：婚假、事假）。
   - **content**: 將該列其餘欄位合併，並加上欄位名稱描述（例如：給假日數：8日；工資：照給）。
   - **合併規則**：若同一項目被切成多行，請合併為單一物件。

**步驟 3：處理備註 (若存在)**
   - 檢查表格下方是否有備註或說明文字。
   - 若有，請建立一個物件：
     {{ "section_title": "表單備註", "content": "備註內容..." }}
   - 若無，則跳過此步驟。

【JSON 輸出範例】
[
  {{
    "section_title": "表單資訊",
    "content": "國立成功大學教師請假一覽表"
  }},
  {{
    "section_title": "婚假",
    "content": "給假日數：8日，需檢附證明；工資給與：照給。"
  }},
  {{
    "section_title": "事假",
    "content": "給假日數：14日..."
  }},
  {{
    "section_title": "表單備註",
    "content": "1. 本表適用於編制內人員。 2. 請假需透過系統申請。"
  }}
]

【待處理內容】：
{content}
"""

# --- Prompt B: 純文字法規專用 (針對無表格的頁面) ---
# 針對無表格的頁面，要求依條文切分 JSON
PROMPT_TEXT = """【角色】你是一個法規結構化專家。
【任務】將輸入的法規文字去除行政雜訊並轉換為符合 RAG 資料庫格式的 JSON Array。

【輸入資料特性】
這是一份純文字法規文件，通常包含：
1. 法規標題。
2. **修法沿革** (一長串的日期與會議紀錄，如「xx年xx月xx日修正通過」) -> **這是雜訊，必須刪除**。
3. **現行條文** (以 一、二、... 或 第1條、第2條... 開頭)。
4. 頁碼或檔號 -> **這是雜訊，必須刪除**。

【欄位定義】
1. **section_title**: 條號或段落標題 (例如: "一、", "二、申請資格", "第四條")。
2. **content**: 該條文的完整內容 (包含項次如 (一)、1. 等細節)。

**處理邏輯 (過濾規則)：**
1. **標題保留**：保留最上方的法規名稱 (如「...作業要點」)。
2. **強力過濾 (重點)**：
   - **刪除** 所有「修正通過」的歷程紀錄 (無論有多少行，全部略過)。
   - **刪除** 頁碼 (如：Page 1, 第x頁, 1/5)。
   - **刪除** 頁首/頁尾的行政代碼 (如：檔號、保存年限)。
3. **條文整理**：
   - 保持「一、(一)、1.」的層次結構。
   - 去除文中不必要的斷行，將同一段落接續起來。
4. **通用性**：適用於任何條列式文件。   

【範例對照】
**原始輸入**：
國立成功大學XX要點
88年修正通過
99年修正通過
一、為提高...
(Page 1)

**正確輸出**：
國立成功大學XX要點
一、為提高...

【輸出格式範例】
[
  {{
    "section_title": "一、目的",
    "content": "為提高本校學術研究水準，依據..."
  }},
  {{
    "section_title": "二、申請資格",
    "content": "以在校服務滿二年以上者為原則。但有下列情形..."
  }}
]

【嚴禁】輸出 Markdown 代碼，只輸出純 JSON。
【待處理內容】：
{content}
"""

# === 輔助函式：切片處理邏輯 (將上一回的複雜邏輯封裝在這裡) ===
def extract_mixed_content(page, valid_tables):
    """
    針對有表格的頁面，執行「切片法」：
    文字 -> 表格 -> 文字 -> 表格...
    """
    page_content = []
    
    # 確保表格由上而下排序
    valid_tables.sort(key=lambda x: x.bbox[1])
    
    current_y = 0
    page_height = page.height

    for table in valid_tables:
        table_top = table.bbox[1]
        table_bottom = table.bbox[3]

        # 1. 提取表格「上方」的文字
        if table_top > current_y:
            text_area_bbox = (0, current_y, page.width, table_top)
            if text_area_bbox[3] - text_area_bbox[1] > 1:
                cropped_page = page.crop(text_area_bbox)
                text = cropped_page.extract_text()
                if text and text.strip():
                    page_content.append(text.strip())

        # 2. 提取表格本身 (轉 Markdown)
        data = table.extract()
        if data:
            num_cols = len(data[0])
            # 製作簡易 Markdown
            md_table = " | ".join(["Col" for _ in range(num_cols)]) + "\n"
            md_table += " | ".join(["---" for _ in range(num_cols)]) + "\n"
            for row in data:
                clean_row = [str(cell).replace('\n', '').strip() if cell is not None else "" for cell in row]
                md_table += " | ".join(clean_row) + "\n"
            page_content.append(f"\n[表格資料]:\n{md_table}")

        # 3. 更新 Y 座標
        current_y = table_bottom

    # 4. 提取最後一個表格「下方」的文字
    if current_y < page_height:
        text_area_bbox = (0, current_y, page.width, page_height)
        if text_area_bbox[3] - text_area_bbox[1] > 1:
            cropped_page = page.crop(text_area_bbox)
            text = cropped_page.extract_text()
            if text and text.strip():
                page_content.append(text.strip())

    return "\n".join(page_content)

# === 輔助函式：清理 LLM 回傳的 JSON 字串 ===
def clean_and_parse_json(llm_output):
    """
    嘗試解析 LLM 回傳的 JSON，處理 Markdown code block 和不完整的格式。
    """
    try:
        # 1. 移除 Markdown code blocks (```json ... ```)
        clean_text = re.sub(r'```json\s*', '', llm_output, flags=re.IGNORECASE)
        clean_text = re.sub(r'```', '', clean_text)
        clean_text = clean_text.strip()
        
        # 2. 嘗試解析 JSON
        return json.loads(clean_text)
    except json.JSONDecodeError as e:
        print(f"JSON 解析失敗: {e}")
        # 如果失敗，印出原始文字以供除錯
        # print(f"原始輸出片段: {llm_output[:200]}...") 
        return []
    
# === 主函式：自動分流處理器 ===
def process_pdf_auto_router(pdf_path):    
    all_json_results = []
    
    table_settings = {
        "vertical_strategy": "lines", 
        "horizontal_strategy": "lines",
        "snap_tolerance": 4, 
        "join_tolerance": 4, 
    }

    try:
        with pdfplumber.open(pdf_path) as pdf:
            #print(f"--- 開始處理檔案: {pdf_path} ---")
            doc_title = pdf.metadata.get("Title") or "未命名文件"

            for page_num, page in enumerate(pdf.pages, start=1):
                #print(f"\n正在分析第 {i+1} 頁...")

                # --- 步驟 1: 偵測有效表格 ---
                raw_tables = page.find_tables(table_settings)
                valid_tables = []
                
                # 過濾雜訊 (只保留夠大的表格)
                for table in raw_tables:
                    data = table.extract()
                    if not data: continue
                    num_cols = len(data[0])
                    num_rows = len(data)
                    # 判斷標準：欄位>=2 且 (欄位>=4 或 行數>=2)
                    if num_cols >= 2 and (num_cols >= 4 or num_rows >= 2):
                        valid_tables.append(table)

                # --- 步驟 2: 分流 (Router) ---
                has_table = len(valid_tables) > 0
                
                content_for_llm = ""
                selected_prompt = ""

                if has_table:
                    #print(f"模式: [表格修復模式] - 偵測到 {len(valid_tables)} 個表格")
                    # 呼叫上面的輔助函式，傳入 page 和 table 物件
                    content_for_llm = extract_mixed_content(page, valid_tables)
                    selected_prompt = PROMPT_TABLE
                
                else:
                    #print(f"模式: [純文字模式] - 無表格，執行法規解析")
                    # 直接抓純文字
                    content_for_llm = page.extract_text()
                    selected_prompt = PROMPT_TEXT

                # --- 步驟 3: 呼叫 LLM (針對該頁面) ---
                if content_for_llm and content_for_llm.strip():
                    try:
                        response = client.chat(
                            model=STAGE2_MODEL,
                            options={'num_ctx':32768, 'temperature':0.1},
                            messages=[{'role':'user', 'content': selected_prompt.format(content=content_for_llm)}],
                        )
                        result_text = response["message"]["content"]
                        #print(f"--- DEBUG: LLM Raw Output ---\n{result_text}\n-----------------------------")

                        # --- 步驟 4: 解析 JSON 並印出 ---
                        parsed_json = clean_and_parse_json(result_text)
                        
                        #parsed_list = json.loads(parsed_json)
                        # 確保回傳的是 List，如果是單個 Dict 就包成 List
                        #if isinstance(parsed_list, dict):
                        #    parsed_list = [parsed_list]

                        # --- D. 注入統一標題 (Data Injection) ---
                        for item in parsed_json:
                            item['doc_title'] = doc_title
                            item['page_num'] = page_num
                            # 加入列表
                            all_json_results.append(item)
                    except json.JSONDecodeError:
                        print(f"[錯誤] Chunk {i+1} 解析 JSON 失敗，跳過。")
                        # 實務上這裡可以記錄 raw_content 以便 debug
                    except Exception as e:
                        print(f"[錯誤] 發生未預期錯誤: {e}")

    except Exception as e:
        return f"PDF Error: {str(e)}"

    return all_json_results

# 執行
if __name__ == "__main__":
    final_data = process_pdf_auto_router("pdf_cache2/holiday.pdf")
    #final_data = process_pdf_auto_router("pdf_cache2/reg09-03.pdf")

    # 2. 在 Main 中統一印出結果 (或是存入資料庫)
    print("\n" + "="*50)
    print(f"【處理完成】共取得 {len(final_data)} 筆結構化資料")
    print("="*50 + "\n")

    for index, record in enumerate(final_data):
        print(f"資料 ID: {index + 1}")
        print(f"文件標題: {record.get('doc_title')}")
        print(f"章節標題: {record.get('section_title')}")
        print(f"頁碼: {record.get('page_num')}")
        print(f"內    容: {record.get('content')}...")
        print("-" * 30)
