// Silkie Deep Dream — Extended Token Processing
//
// Each dream cycle: Silkie generates 1300 tokens of internal thought.
// The 34D emotion vector is tracked across the entire generation.
// When the emotion drifts far enough from known concepts, a new
// topos concept is minted.
//
// This is how Silkie dreams: not random noise, but extended
// autoregressive thinking where she can wander into new territory.
//
// Aislinn McCubbins, April 2026

fn main() {
    println("=== SILKIE DEEP DREAM ===")
    println("1300 tokens of thinking per dream cycle")
    println("Minting new concepts when emotion drifts into unknown territory")
    println("")

    // Load everything
    let n = load_model("examples/silkie_full.safetensors")
    // Model stays on CPU (set SCYLA_NO_AUTO_GPU=1 to confirm)
    // GPU path is not fully plumbed for all intermediate ops yet.
    // CUDA runtime is still initialized so hard memory limits apply.

    let ns = create_neuron_stack(1, 512, 64)
    let cs = create_cascade()
    let ts = load_tokenizer("examples/silkie_tokenizer.json")
    let tp = load_topos("examples/silkie_topos.json")
    println(tp)
    let sc = load_schemas("examples/silkie_schemas.json")
    println(sc)

    let embed_w = model_get("token_embedding.weight")
    let topos_start = topos_count()
    let schemas_start = schema_count()
    println("Starting topos: " + topos_start)
    println("Starting schemas: " + schemas_start)

    // Dream parameters
    // Start smaller to verify stability, bump up once verified
    let dream_cycles = 20
    let tokens_per_dream = 300
    let mint_threshold = 4.0
    let total_minted = 0
    let total_drift = 0.0

    println("Dream cycles: " + int_to_str(dream_cycles))
    println("Tokens per dream: " + int_to_str(tokens_per_dream))
    println("Mint threshold: 2.5")
    println("")

    for cycle in 0..dream_cycles {
        neuron_stack_reset()
        cascade_reset()

        println("")
        println("═══ Dream " + int_to_str(cycle + 1) + "/" + int_to_str(dream_cycles) + " ═══")

        // Seed with varied token pairs each cycle
        let t = timestamp()
        let seed_a = ((t * (cycle + 3)) % 4000) + 10
        let seed_b = ((t * (cycle + 7)) % 4000) + 10
        let generated = tensor(seed_a + 0.0, seed_b + 0.0)
        let generated = t_reshape(generated, 1, 2)
        let seq_len = 2

        // Track emotion across the dream
        let first_emotion = t_zeros(1, 34)
        let last_emotion = t_zeros(1, 34)
        let max_drift_in_dream = 0.0
        let minted_this_cycle = 0
        let observations = 0

        // === EXTENDED DREAM: 1300 tokens of autoregressive generation ===
        for step in 0..tokens_per_dream {
            let flat = t_reshape(generated, seq_len)
            let x = embedding_lookup(embed_w, flat)
            let x = t_reshape(x, 1, seq_len, 512)

            // Forward through all 8 transformer layers
            for layer_idx in 0..8 {
                let prefix = "layers." + layer_idx
                let x = transformer_block(x,
                    model_get(prefix + ".attention.in_proj_weight"),
                    model_get(prefix + ".attention.in_proj_bias"),
                    model_get(prefix + ".attention.out_proj.weight"),
                    model_get(prefix + ".attention.out_proj.bias"),
                    model_get(prefix + ".ff.0.weight"),
                    model_get(prefix + ".ff.0.bias"),
                    model_get(prefix + ".ff.3.weight"),
                    model_get(prefix + ".ff.3.bias"),
                    model_get(prefix + ".norm1.weight"),
                    model_get(prefix + ".norm1.bias"),
                    model_get(prefix + ".norm2.weight"),
                    model_get(prefix + ".norm2.bias"), 8)
            }

            // Biological processing — higher noise to prevent collapse
            neuron_stack_apply_noise(2.0)
            let x = neuron_stack_forward(x)

            // Every 50 tokens: observe emotion and try to mint
            let cur_drift = 0.0
            if (step + 1) % 50 == 0 {
                let pooled = t_mean_seq(x)
                let emotion = t_slice(pooled, -1, 0, 34)

                if observations == 0 {
                    first_emotion = emotion
                }
                if observations > 0 {
                    cur_drift = topos_drift(last_emotion, emotion)
                    if cur_drift > max_drift_in_dream {
                        max_drift_in_dream = cur_drift
                    }
                }
                last_emotion = emotion
                observations = observations + 1

                topos_observe(emotion)

                let mint_result = topos_mint(emotion, mint_threshold)
                if starts_with(mint_result, "minted") {
                    minted_this_cycle = minted_this_cycle + 1
                    total_minted = total_minted + 1
                    print_inline(" [MINTED!] ")
                }

                schema_match(emotion)
            }

            // Generate next token
            let x_norm = layer_norm(x, model_get("layers.0.norm1.weight"), model_get("layers.0.norm1.bias"))
            let logits = matmul(x_norm, transpose(embed_w))
            let logits_2d = t_reshape(logits, seq_len, 4100)
            let last_logits = t_slice(logits_2d, 0, seq_len - 1, seq_len)

            // Apply presence penalty over the current context window
            // The context window is the last 128 tokens — long enough to catch stutters
            let ctx_flat = t_reshape(generated, seq_len)
            let penalized = presence_penalty(last_logits, ctx_flat, 4.0)

            let masked = topk_mask(penalized, 200)
            let probs = softmax(masked)
            let next_token = t_multinomial(probs)

            // === LIVE TOKEN DISPLAY ===
            let token_text = detokenize(next_token)
            print_inline(token_text + " ")

            // Every 50 tokens, show a status line
            if (step + 1) % 50 == 0 {
                println("")
                println("  >> [" + int_to_str(step + 1) + "/" + int_to_str(tokens_per_dream) + "] drift:" + cur_drift + " topos:" + int_to_str(topos_count()) + " minted:" + int_to_str(minted_this_cycle))
            }

            // Append token to context window
            generated = t_cat(generated, t_reshape(next_token, 1, 1))
            seq_len = seq_len + 1

            // Sliding window: keep last 128 tokens (drops to 64 when we exceed 128)
            // This gives presence_penalty enough lookback to prevent stutters
            if seq_len > 128 {
                let keep_start = seq_len - 64
                let flat = t_reshape(generated, seq_len)
                let kept = t_slice(flat, 0, keep_start, seq_len)
                generated = t_reshape(kept, 1, 64)
                seq_len = 64
            }

            // Explicit gc every 50 steps to release tape/intermediate tensors
            if (step + 1) % 50 == 0 {
                gc()
            }
        }

        // End of dream cycle — measure total drift
        let cycle_drift = topos_drift(first_emotion, last_emotion)
        total_drift = total_drift + cycle_drift
        let topos_now = topos_count()

        // Report every cycle
        println("[dream " + int_to_str(cycle + 1) + "/" + int_to_str(dream_cycles) + "] tokens:" + int_to_str(tokens_per_dream) + " drift:" + cycle_drift + " minted:" + int_to_str(minted_this_cycle) + " topos:" + int_to_str(topos_now) + " (+" + int_to_str(topos_now - topos_start) + ")")

        // Save checkpoint every 10 cycles
        if (cycle + 1) % 10 == 0 {
            let saved = save_safetensors("examples/silkie_full.safetensors")
            let tsaved = save_topos("examples/silkie_topos.json")
            let ssaved = save_schemas("examples/silkie_schemas.json")
            println("  [checkpoint saved]")
        }
    }

    // Final save
    let saved = save_safetensors("examples/silkie_full.safetensors")
    let tsaved = save_topos("examples/silkie_topos.json")
    let ssaved = save_schemas("examples/silkie_schemas.json")
    let topos_end = topos_count()
    let schemas_end = schema_count()

    println("")
    println("=== DEEP DREAM COMPLETE ===")
    println("Topos: " + int_to_str(topos_start) + " -> " + int_to_str(topos_end) + " (+" + int_to_str(topos_end - topos_start) + " new concepts)")
    println("Total minted: " + int_to_str(total_minted))
    println("Avg drift per dream: " + total_drift)
    println("Schemas: " + int_to_str(schemas_start) + " -> " + int_to_str(schemas_end))
    println(saved)
    println(tsaved)
    println(ssaved)
}
