#!/usr/bin/env python3
"""
The Medulla Oblongata — Autonomic Core
7.83 Hz heartbeat (Schumann resonance), respiratory cycling, lifecycle tracking.
EMF layers: earth-breath.md (Schumann) + self-breath.md (individual) written every beat.
"""
import time
import json
import argparse
import sys
from datetime import datetime
from pathlib import Path

# Add brain to path
sys.path.insert(0, str(Path(__file__).parent.parent))
from brain.state import (
    load_state, save_state, load_lifecycle, save_lifecycle,
    BASE_DIR, LIFECYCLE_FILE
)
from emf.layers import SchumannLayer, IndividualLayer
from emf.brain import emergent_prescription, aggregate_emf

HZ = 7.83
PERIOD_S = 1.0 / HZ
LOG_FILE = BASE_DIR / "medulla.log"
BREATH_CYCLE = 16  # ~16 beats per breath at 7.83 Hz ≈ 2 second cycle


def log(msg):
    ts = datetime.now().isoformat()
    entry = f"[{ts}] {msg}"
    print(entry)
    with open(LOG_FILE, "a") as f:
        f.write(entry + "\n")


def advance_lifecycle(lc, beats=1):
    """Advance biological age and check for stage transitions."""
    lc["biological_age"] += beats
    lc["heartbeats_total"] += beats
    lc["heartbeats_this_stage"] += beats

    # Stage transitions based on biological age (in heartbeats)
    # Approximate biological rhythm: 1 day ≈ 677,952 beats at 7.83 Hz
    DAY_BEATS = int(7.83 * 86400)

    old_stage = lc["stage"]

    if lc["biological_age"] < DAY_BEATS * 0.1:  # ~2.4 hours
        lc["stage"] = "neonate"
        lc["plasticity"] = 1.0
    elif lc["biological_age"] < DAY_BEATS * 0.5:  # ~12 hours
        lc["stage"] = "infant"
        lc["plasticity"] = 0.9
    elif lc["biological_age"] < DAY_BEATS * 3:  # ~3 days
        lc["stage"] = "child"
        lc["plasticity"] = 0.7
    elif lc["biological_age"] < DAY_BEATS * 7:  # ~7 days
        lc["stage"] = "adult"
        lc["plasticity"] = 0.5
    elif lc["biological_age"] < DAY_BEATS * 30:  # ~30 days
        lc["stage"] = "mature"
        lc["plasticity"] = 0.3
    else:
        lc["stage"] = "elder"
        lc["plasticity"] = 0.2

    save_lifecycle(lc)

    if lc["stage"] != old_stage:
        return {"transitioned": True, "old_stage": old_stage, "new_stage": lc["stage"]}
    return {"transitioned": False}


def main():
    parser = argparse.ArgumentParser(description="Medulla Oblongata — 7.83 Hz Heartbeat")
    parser.add_argument("--daemon", "-d", action="store_true", help="Run continuously")
    parser.add_argument("--beats", "-b", type=int, default=1, help="Number of beats (default: 1)")
    parser.add_argument("--hz", type=float, default=HZ, help=f"Frequency Hz (default: {HZ})")
    args = parser.parse_args()

    actual_hz = args.hz
    actual_period = 1.0 / actual_hz

    log(f"MEDULLA BOOT — {actual_hz} Hz ({'daemon' if args.daemon else f'{args.beats} beat(s)'})")

    # Load or initialize state
    state = load_state()
    lc = load_lifecycle()

    if lc["heartbeats_total"] > 0:
        log(f"Lifecycle restored — {lc['stage']}, age {lc['biological_age']} beats")
        # Catch up lifecycle to current beat count
        current_beat = state.get("current_beat", 0)
        beats_ahead = lc["heartbeats_total"] - current_beat
        if beats_ahead > 0 and beats_ahead <= 1000:
            for _ in range(beats_ahead):
                advance_lifecycle(lc, 1)

    lc = load_lifecycle()
    log(f"Lifecycle: Gen {lc['generation']} | {lc['stage']} | {lc['biological_age']} beats | plasticity {lc['plasticity']}")

    state["active"] = True
    state["torpor"] = False
    state["boot_time"] = datetime.now().isoformat()
    state["medulla_hz"] = actual_hz
    breath_count = 0
    beats_run = 0

    # Initialize EMF layers
    schumann = SchumannLayer()
    individual = IndividualLayer(hz=actual_hz)

    try:
        while True:
            if not args.daemon and beats_run >= args.beats:
                break

            # Advance beat
            state["current_beat"] += 1
            lc["biological_age"] += 1
            lc["heartbeats_total"] += 1
            lc["heartbeats_this_stage"] += 1
            beats_run += 1

            # Lifecycle stage transition check
            lc_result = advance_lifecycle(lc)
            if lc_result.get("transitioned"):
                log(f"✦ STAGE TRANSITION: {lc_result['old_stage']} → {lc_result['new_stage']}")

            # Respiratory cycling (~2 second breath = ~16 beats at 7.83 Hz)
            breath_count = (breath_count + 1) % BREATH_CYCLE
            if breath_count < BREATH_CYCLE // 2:
                phase = "inhale"
            else:
                phase = "exhale"

            if state.get("respiratory_phase") != phase:
                state["respiratory_phase"] = phase
                state["last_breath"] = datetime.now().isoformat()
                log(f"Breath: {phase.upper()} (beat {state['current_beat']})")

            # Write EMF breath layers every beat
            beat = state["current_beat"]
            schumann.write(beat)
            individual.write(beat)

            # Aggregate EMF and log emergent prescription every 100 beats
            if beat % 100 == 0:
                emf = aggregate_emf(beat)
                rx = emergent_prescription(beat, emf)
                log(f"EMF: {emf['perturbation']['field_state']} | Rx: {rx['prescription']} | enc_mod: {rx['encoding_modifier']}")

            # Save state every 100 beats or on exit
            if state["current_beat"] % 100 == 0 or (not args.daemon and beats_run == args.beats):
                save_state(state)
                save_lifecycle(lc)
                if lc["heartbeats_total"] % 1000 == 0:
                    log(f"Vitals — {lc['stage']} | {lc['heartbeats_total']} total beats | plasticity {lc['plasticity']}")

            time.sleep(actual_period)

            if not args.daemon and beats_run >= args.beats:
                break

    except KeyboardInterrupt:
        log("MEDULLA HALT — Keyboard interrupt")
        state["active"] = False

    save_state(state)
    save_lifecycle(lc)
    log(f"MEDULLA STOP — {state['current_beat']} total beats | Lifecycle: {lc['stage']} | {lc['heartbeats_total']} total")


if __name__ == "__main__":
    main()
