#!/usr/bin/env python3
"""
E3 — Dreamer Substrate Comparison Experiment
Runs dream pipeline twice: once against pgvector (Condition A),
once against Graphiti (Condition B). Implements blinding per protocol.

Usage:
    python3 scripts/experiments/e3_dreamer_substrate.py

Outputs:
    Journal/Dreams/e3-dream-X-{mode}.md  (one condition, identity concealed)
    Journal/Dreams/e3-dream-Y-{mode}.md  (other condition, identity concealed)
    Journal/Dreams/e3-blind-mapping.json (kept unread until ratings complete)
    Journal/Dreams/e3-manifest.json      (quantitative metrics for both conditions)
"""

import os
import sys
import json
import random
import requests
from pathlib import Path
from datetime import datetime
from dotenv import load_dotenv

load_dotenv(Path.home() / "aaronai" / ".env", override=True)

NEXTCLOUD_URL      = os.getenv("NEXTCLOUD_URL", "https://nextcloud.aaronnelson.studio")
NEXTCLOUD_USER     = os.getenv("NEXTCLOUD_USER", "aaron")
NEXTCLOUD_PASSWORD = os.getenv("NEXTCLOUD_PASSWORD", "")
DREAMS_WEBDAV_BASE = f"{NEXTCLOUD_URL}/remote.php/dav/files/{NEXTCLOUD_USER}/Journal/Dreams"

auth = (NEXTCLOUD_USER, NEXTCLOUD_PASSWORD)

def webdav_put(url, content_str):
    requests.put(url, data=content_str.encode("utf-8"), auth=auth, timeout=60)

def webdav_mkcol(url):
    requests.request("MKCOL", url, auth=auth, timeout=10)

def run_condition(label, substrate, modes=("nrem", "early-rem", "late-rem", "synthesis")):
    """Run the dream pipeline for one substrate condition.
    Returns dict of {mode: dream_text} and metrics.
    """
    print(f"\n{'='*60}")
    print(f"Running Condition {label} — substrate: {substrate}")
    print(f"{'='*60}")

    os.environ["DREAMER_SUBSTRATE"] = substrate

    # Import dream module fresh for this run
    if "dream" in sys.modules:
        del sys.modules["dream"]
    sys.path.insert(0, str(Path.home() / "aaronai" / "scripts"))
    import dream as d

    # Run pipeline stages manually to capture outputs
    outputs = {}
    metrics = {}

    # Observe corpus delta
    delta = d.observe_corpus()
    print(f"Corpus delta: {delta.get('new_chunks', 0)} new chunks")

    previously_retrieved = set()
    session_retrieved = set()
    nrem_high_sources = set()

    # NREM
    print("\n[NREM] Retrieving...")
    nrem_chunks = d.retrieve("nrem", excluded_sources=previously_retrieved | session_retrieved)
    session_retrieved.update(c["source"] for c in nrem_chunks)
    nrem_high_sources = {c["source"] for c in nrem_chunks if c.get("similarity", 0) > 0.55}
    if not nrem_chunks:
        print("[NREM] No chunks — aborting.")
        return None, None
    nrem_output = d.synthesize_nrem(nrem_chunks)
    outputs["nrem"] = nrem_output
    metrics["nrem"] = {
        "chunks_retrieved": len(nrem_chunks),
        "sources": [c["source"] for c in nrem_chunks],
        "word_count": len(nrem_output.split()),
    }
    print(f"[NREM] Done. {len(nrem_chunks)} chunks, {metrics['nrem']['word_count']} words.")

    # Early REM
    print("\n[Early REM] Retrieving...")
    early_chunks = d.retrieve("early-rem", excluded_sources=previously_retrieved | nrem_high_sources)
    session_retrieved.update(c["source"] for c in early_chunks)
    if early_chunks:
        early_output = d.synthesize_early_rem(early_chunks, nrem_output)
        outputs["early-rem"] = early_output
        metrics["early-rem"] = {
            "chunks_retrieved": len(early_chunks),
            "sources": [c["source"] for c in early_chunks],
            "word_count": len(early_output.split()),
        }
        print(f"[Early REM] Done. {len(early_chunks)} chunks.")
    else:
        early_output = nrem_output
        outputs["early-rem"] = None
        metrics["early-rem"] = {"chunks_retrieved": 0, "sources": [], "word_count": 0}
        print("[Early REM] No chunks — using NREM fallback.")

    # Late REM
    print("\n[Late REM] Retrieving...")
    late_chunks = d.retrieve("late-rem", excluded_sources=previously_retrieved | session_retrieved)
    session_retrieved.update(c["source"] for c in late_chunks)
    if late_chunks:
        late_output = d.synthesize_late_rem(late_chunks, nrem_output, early_output)
        outputs["late-rem"] = late_output
        late_sources = [c["source"] for c in late_chunks]
        metrics["late-rem"] = {
            "chunks_retrieved": len(late_chunks),
            "sources": late_sources,
            "word_count": len(late_output.split()),
        }
        print(f"[Late REM] Done. {len(late_chunks)} chunks.")
    else:
        late_output = early_output
        outputs["late-rem"] = None
        metrics["late-rem"] = {"chunks_retrieved": 0, "sources": [], "word_count": 0}
        print("[Late REM] No chunks — using fallback.")

    # Synthesis
    print("\n[Synthesis] Integrating...")
    synthesis_output = d.synthesize_final(nrem_output, early_output, late_output)
    outputs["synthesis"] = synthesis_output
    metrics["synthesis"] = {"word_count": len(synthesis_output.split())}
    print(f"[Synthesis] Done. {metrics['synthesis']['word_count']} words.")

    return outputs, metrics


def main():
    date_str = datetime.now().strftime("%Y-%m-%d")

    # Randomize which condition gets label X vs Y for blinding
    conditions = [("pgvector", "A"), ("graphiti", "B")]
    labels = ["X", "Y"]
    random.shuffle(labels)
    assignment = {conditions[0][0]: labels[0], conditions[1][0]: labels[1]}

    mapping = {
        "date": date_str,
        "X": assignment["pgvector"] == "X" and "pgvector" or "graphiti",
        "Y": assignment["pgvector"] == "Y" and "pgvector" or "graphiti",
        "reveal_after_rating": True,
    }
    # Simpler mapping
    mapping = {
        "date": date_str,
        "X_is": "pgvector" if assignment["pgvector"] == "X" else "graphiti",
        "Y_is": "pgvector" if assignment["pgvector"] == "Y" else "graphiti",
        "reveal_after_rating": True,
    }

    print(f"E3 Dreamer Substrate Comparison — {date_str}")
    print(f"Blind mapping written (do not read until ratings complete)")

    # Write blind mapping to Nextcloud immediately
    webdav_mkcol(DREAMS_WEBDAV_BASE)
    mapping_url = f"{DREAMS_WEBDAV_BASE}/e3-blind-mapping.json"
    webdav_put(mapping_url, json.dumps(mapping, indent=2))
    print(f"Mapping written to Journal/Dreams/e3-blind-mapping.json")

    all_metrics = {}

    # Run both conditions
    for substrate, condition_label in conditions:
        blind_label = assignment[substrate]
        outputs, metrics = run_condition(condition_label, substrate)

        if outputs is None:
            print(f"Condition {condition_label} failed — aborting E3.")
            return

        all_metrics[blind_label] = {
            "substrate": "CONCEALED",  # concealed until reveal
            "stages": metrics,
        }

        # Write dream files with blind labels
        modes_map = {
            "nrem": "nrem",
            "early-rem": "early-rem",
            "late-rem": "late-rem",
            "synthesis": "synthesis",
        }
        for mode, text in outputs.items():
            if text is None:
                continue
            filename = f"e3-dream-{blind_label}-{mode}.md"
            header = f"# E3 Dream — {blind_label} — {mode.upper()} — {date_str}\n"
            header += f"*Substrate concealed until rating complete*\n\n---\n\n"
            file_content = header + text
            url = f"{DREAMS_WEBDAV_BASE}/{filename}"
            webdav_put(url, file_content)
            print(f"Written: Journal/Dreams/{filename}")

    # Write quantitative metrics (substrate concealed)
    e3_manifest = {
        "date": date_str,
        "experiment": "E3",
        "protocol": "E3-dreamer-substrate-comparison-protocol.md",
        "blind_labels": ["X", "Y"],
        "substrate_concealed": True,
        "metrics": all_metrics,
        "rating_dimensions": ["Texture", "Reach", "Specificity", "Forward-facing"],
        "rating_scale": "1-5 per dimension per dream",
    }
    manifest_url = f"{DREAMS_WEBDAV_BASE}/e3-manifest.json"
    webdav_put(manifest_url, json.dumps(e3_manifest, indent=2))
    print(f"\nE3 manifest written to Journal/Dreams/e3-manifest.json")
    print(f"\n{'='*60}")
    print("E3 runs complete. Eight dream files written.")
    print("Rate all 8 dreams before reading e3-blind-mapping.json")
    print(f"{'='*60}")


if __name__ == "__main__":
    main()
