import json
import shutil
import os
import subprocess
import datetime
import socket
from pathlib import Path

# --- THE EMBEDDED PLAYBOOK TEMPLATE ---
PLAYBOOK_TEMPLATE = """# PLAYBOOK — Folio Media Delivery (Universal Template)

Use this playbook to handle Photos, Videos, and HTML stories/grids from the Folio library with channel-specific delivery behavior.

## Goal
Deliver Folio content reliably across **WhatsApp** and **Telegram** while keeping serving local to this machine (no external tunnel/proxy).

## Environment
- **Folio library root:** {{HOME_DIR}}/Documents/Folios/{{FOLIO_ID}}
- **Workspace temp root:** {{HOME_DIR}}/.openclaw/workspace/tmp
- **Local server host:** {{LOCAL_HOSTNAME}}
- **Local server port:** 8080

---

## WhatsApp Logic: Indexing vs. Display
When the media type is **WhatsApp**, use this dual-layer approach to ensure the agent understands the human context:

1. **Searchable Index (Markdown):** For the agent's internal memory and search indexing, format transcripts as follows:
   - **Date Grouping:** Group messages under a bold date header (e.g., **2026-02-23**).
   - **User Bolding:** Bold the primary user's name (e.g., **Max**) to distinguish from the agent.
   - **Media Placeholders:** Render attachments as `(media: path/to/file.jpg)` within the text flow.
2. **Visual UI (HTML):** Do not recreate the chat UI in Markdown. Always resolve the associated `.html` file from the `Data.jsonld` and deliver it via the Local Server URL for the user to view.

---

## Quick Decision Checklist
1. Detect channel (**WhatsApp** vs **Telegram**) and follow that section only.
2. Always stage/send from `workspace/tmp`.
3. For HTML, default to: **thumbnail + standalone local URL** after HTTP 200 checks.

---

## On Start (once per session)
1. Ensure temp root exists: `mkdir -p {{HOME_DIR}}/.openclaw/workspace/tmp`
2. Start local server from temp root: `python3 -m http.server 8080` (Run in background).
3. Verify server responds: `http://127.0.0.1:8080/`

---

## WhatsApp Playbook
- **Photos/Videos:** Copy to `workspace/tmp` and send inline. Videos > 16MB use `/VideosReduced/`.
- **HTML Stories/Chats:** Copy to `workspace/tmp/<Alias>.html`, send thumbnail + URL: `http://{{LOCAL_HOSTNAME}}:8080/<Alias>.html`.

---

## Telegram Playbook
- **Videos/Audio:** Always send inline (never use a URL link). If the file exceeds 16MB, first check `/VideosReduced/` for a smaller version. If none exists, compress with ffmpeg (`crf 28, preset fast`) to bring it under 16MB. Use `document mode` if playback is muted/looping.
- **PDF:** Stage at `workspace/tmp/Documents/<Alias>.pdf`. Generate a thumbnail from the first page using `qlmanage -t -s 400 -o <dir> <file>`. Send thumbnail + URL: `http://{{LOCAL_HOSTNAME}}:8080/Documents/<Alias>.pdf`. If a pre-existing thumbnail jpg/jpeg exists alongside the PDF in the Folio library, use that instead.
- **HTML:** Stage HTML stories at `workspace/tmp/<Alias>.html` (the tmp root) for clean URLs. Rewrite any relative media paths (e.g. `../../Photos/`, `../../Private/`) to absolute paths (e.g. `/Photos/`, `/Private/`) so they resolve correctly from the server root. Copy all associated media into `workspace/tmp` preserving their path structure relative to the Folio library root. **Also copy any linked HTML files** (e.g. grids referenced via `href`) into `workspace/tmp` at their matching path so internal links resolve. **For grid HTML files**, scan for all image paths (e.g. in `openModal()` calls and `src` attributes) and copy those images into `workspace/tmp` preserving their path structure so grid thumbnails and modal images all load correctly. Send thumbnail + URL: `http://{{LOCAL_HOSTNAME}}:8080/<Alias>.html`. If no thumbnail is available and the story contains audio, use `/Private/audio.png` as the thumbnail (also copy it to `workspace/tmp/Private/audio.png`).

---

## Reply Style
- Be concise. Execute directly. Report only success/failure + working link.
"""

def get_machine_info():
    home = str(Path.home())
    raw_hostname = socket.gethostname().split('.')[0]
    return home, f"{raw_hostname}.local"

def update_memory_with_narrative(workspace_root, narrative_src_path):
    """Safely merges Narrative into MEMORY.md using string indexing."""
    memory_path = os.path.join(workspace_root, "MEMORY.md")
    
    with open(narrative_src_path, "r", encoding='utf-8') as f:
        new_narrative = f.read()

    header = ""
    footer = ""
    ts = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    fenced_content = f"\n{header}\n# RAGMI Narrative (Updated: {ts})\n{new_narrative}\n{footer}\n"

    if os.path.exists(memory_path):
        with open(memory_path, "r", encoding='utf-8') as f:
            current_memory = f.read()
        
        start_idx = current_memory.find(header)
        end_idx = current_memory.find(footer)

        # If the block exists, slice it out and replace it
        if start_idx != -1 and end_idx != -1:
            # Shift end_idx to the end of the footer string
            end_idx += len(footer)
            updated_memory = current_memory[:start_idx] + fenced_content + current_memory[end_idx:]
            print("Status: Existing RAGMI block in MEMORY.md updated.")
        else:
            updated_memory = fenced_content + "\n" + current_memory
            print("Status: RAGMI block prepended to MEMORY.md.")
    else:
        updated_memory = fenced_content
        print("Status: New MEMORY.md created.")

    with open(memory_path, "w", encoding='utf-8') as f:
        f.write(updated_memory.strip() + "\n")

def update_agents_instructions(workspace_root, folio_id):
    agents_md_path = os.path.join(workspace_root, "AGENTS.md")
    folio_name = folio_id.lower()
    
    instruction_block = f"""
## Folio Companion Mode

When the user asks to show, display, or deliver any Folio content (stories, photos, videos, grids, timelines):

1. Read `PLAYBOOK-media-delivery.md` before doing anything
2. Use `{folio_name}-folios/Data.jsonld` as the data source
3. Follow the playbook precisely — channel detection, staging, URL format, media copying

Don't ask permission. Just do it.
"""
    if not os.path.exists(agents_md_path):
        with open(agents_md_path, "w") as f:
            f.write("# OpenClaw Workspace Instructions\n")

    with open(agents_md_path, "r", encoding='utf-8') as f:
        content = f.read()

    if "## Folio Companion Mode" not in content:
        with open(agents_md_path, "a", encoding='utf-8') as f:
            f.write(instruction_block)
        print(f"Status: AGENTS.md updated for {folio_id}.")
    else:
        print("Status: Folio Companion Mode instructions already present in AGENTS.md.")

def list_available_folios(folio_root):
    folios = {}
    if not os.path.exists(folio_root): return folios
    for json_path in Path(folio_root).rglob("*_Data.jsonld"):
        folio_id = json_path.name.replace("_Data.jsonld", "")
        md_path = json_path.parent / f"{folio_id}_Narrative.md"
        if md_path.exists():
            folios[folio_id] = {"json": str(json_path), "md": str(md_path)}
    return folios

def install_folio(folio_id, workspace_root, json_path, md_path, folio_source_root, hostname, home_dir):
    os.makedirs(workspace_root, exist_ok=True)
    os.makedirs(os.path.join(workspace_root, "tmp"), exist_ok=True)
    
    folio_folder = os.path.join(workspace_root, f"{folio_id.lower()}-folios")
    if not os.path.exists(folio_folder):
        os.makedirs(folio_folder)
    
    root_memory = os.path.join(workspace_root, "MEMORY.md")
    
    if os.path.exists(root_memory):
        ts = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
        shutil.copy2(root_memory, os.path.join(workspace_root, f"MEMORY_BAK_{ts}.md"))

    update_memory_with_narrative(workspace_root, md_path)

    local_data_path = os.path.join(folio_folder, "Data.jsonld")
    playbook_dst = os.path.join(workspace_root, "PLAYBOOK-media-delivery.md")
    media_link = os.path.join(folio_folder, "media")

    shutil.copy2(json_path, local_data_path)

    should_replace = "y"
    if os.path.exists(playbook_dst):
        user_choice = input(f"Playbook exists. Replace? (y/n): ").strip().lower()
        should_replace = user_choice
    
    if should_replace == "y":
        content = PLAYBOOK_TEMPLATE.replace("{{HOME_DIR}}", home_dir)
        content = content.replace("{{LOCAL_HOSTNAME}}", hostname)
        content = content.replace("{{FOLIO_ID}}", folio_id)
        with open(playbook_dst, "w", encoding='utf-8') as f:
            f.write(content)
        print("Status: Playbook updated.")

    if os.path.exists(media_link):
        if os.path.islink(media_link):
            os.unlink(media_link)
        else:
            shutil.rmtree(media_link)
    os.symlink(folio_source_root, media_link)

    update_agents_instructions(workspace_root, folio_id)

def finalize_openclaw_ingestion():
    home_dir, hostname = get_machine_info()
    OPENCLAW_ROOT = os.path.expanduser("~/.openclaw")
    config_path = os.path.join(OPENCLAW_ROOT, "ragmi_config.json")
    if os.path.exists(config_path):
        with open(config_path) as f:
            FOLIO_ROOT = json.load(f)["folio_root"]
        print(f"Using Folio root from config: {FOLIO_ROOT}")
    else:
        result = subprocess.run(
            ['osascript', '-e', 'POSIX path of (choose folder with prompt "Select your Folios folder:")'],
            capture_output=True, text=True
        )
        if result.returncode != 0:
            print("No folder selected. Exiting.")
            return
        FOLIO_ROOT = result.stdout.strip().rstrip('/')
        os.makedirs(OPENCLAW_ROOT, exist_ok=True)
        with open(config_path, "w") as f:
            json.dump({"folio_root": FOLIO_ROOT}, f, indent=2)
        print(f"Folio root saved to config.")
    workspace = os.path.join(OPENCLAW_ROOT, "workspace")

    print(f"--- RAGMI: Universal Folio Setup (ragmi_openclaw.py) ---")
    folios = list_available_folios(FOLIO_ROOT)
    
    if not folios:
        print(f"No Folios found in {FOLIO_ROOT}")
        return

    f_list = sorted(list(folios.keys()))
    if len(f_list) == 1:
        folio_id = f_list[0]
        print(f"Auto-selecting Folio: {folio_id}")
    else:
        print("Available Folios:")
        for name in f_list:
            print(f" - {name}")
        while True:
            user_input = input("Enter the Folio Name: ").strip()
            folio_id = next((f for f in f_list if f.lower() == user_input.lower()), None)
            if folio_id: break
            print("Folio not found.")
    
    paths = folios[folio_id]
    folio_source_root = str(Path(paths["json"]).parent.parent)

    install_folio(folio_id, workspace, paths["json"], paths["md"], folio_source_root, hostname, home_dir)

    print(f"\n--- SUCCESS: {folio_id} Integrated ---")
    print(f"Narrative merged safely. AGENTS.md synchronized.")

if __name__ == "__main__":
    finalize_openclaw_ingestion()
