use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint,
    entrypoint::ProgramResult,
    msg,
    program_error::ProgramError,
    pubkey::Pubkey,
    system_instruction,
    sysvar::{rent::Rent, Sysvar},
};
use borsh::{BorshDeserialize, BorshSerialize};
use num_traits::cast::ToPrimitive;

// Constants
const MAX_SEED_VECTORS: u32 = 64;
const FOLD_LIMIT: u32 = 24;
const SAFE_ZERO: u64 = 0;
const PHI: f64 = 1.618033988749895; // φ
const PHI_ADD: u64 = 0xA6F; // φ^φ ≈2.618 scaled
const R_DIM_STEP: f64 = 0.05 / PHI; // Normalized increment
const OMEGA_DAMP: f64 = 0.95;

// Packed params (r_dim, Ω as u16)
const PARAMS: [(u16, u16); 8] = [
    (0x3000, 0x812), (0x4000, 0x502), (0x5000, 0x310), (0x6000, 0x192),
    (0x7000, 0x119), (0x8000, 0x73), (0x9000, 0x45), (0xA000, 0x28),
];

// HDGL State (stored in account)
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct HDGLState {
    lattice: Vec<u64>, // Delta-encoded Vec16M (64 seeds → 16M)
    r_dim: f64,       // Helix scalar [0,1]
    omega: f64,       // Tension damper
    fold_step: u32,   // Current fold (0..24)
}

// Instruction Enum
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub enum HDGLInstruction {
    Initialize { pubkey: Pubkey },
    FoldEvolve,
}

// Program entrypoint
entrypoint!(process_instruction);

pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    instruction_data: &[u8],
) -> ProgramResult {
    let instruction = HDGLInstruction::try_from_slice(instruction_data)?;
    let account_info_iter = &mut accounts.iter();
    let state_account = next_account_info(account_info_iter)?;
    let payer = next_account_info(account_info_iter)?;
    let rent = Rent::get()?;

    match instruction {
        HDGLInstruction::Initialize { pubkey } => {
            // Verify payer signature
            if !payer.is_signer {
                return Err(ProgramError::MissingRequiredSignature);
            }
            // Initialize state
            let mut state = HDGLState {
                lattice: vec![SAFE_ZERO; MAX_SEED_VECTORS as usize * 4], // Vec4 × 64
                r_dim: 0.0,
                omega: 1.0,
                fold_step: 0,
            };
            // Seed first instance with excitation
            state.lattice[2] = 0x2540BE400;
            state.lattice[3] = 0x2540BE400;
            state.serialize(&mut &mut state_account.data.borrow_mut()[..])?;
            // Allocate space
            let space = 8 * 1024 * 1024; // 8MB for lattice
            let lamports = rent.minimum_balance(space);
            let instruction = system_instruction::create_account(
                payer.key,
                state_account.key,
                lamports,
                space as u64,
                program_id,
            );
            // Execute (payer funds)
            solana_program::program::invoke(&instruction, &[
                payer.clone(),
                state_account.clone(),
                next_account_info(account_info_iter)?, // System program
            ])?;
        }
        HDGLInstruction::FoldEvolve => {
            let mut state = HDGLState::try_from_slice(&state_account.data.borrow())?;
            if state.fold_step > FOLD_LIMIT {
                return Ok(()); // Halt
            }
            // φ-delta: Excite slots based on fold_step
            let delta = phi_delta_vector(&state.lattice, state.fold_step);
            state.lattice = phi_add_vector(&state.lattice, &delta)?;
            state.r_dim = f64::min(1.0, state.r_dim + R_DIM_STEP);
            state.omega = f64::max(1e-6, state.omega * OMEGA_DAMP);
            state.fold_step += 1;
            // Verify params (first 8 instances)
            for i in 0..8 {
                let (r_dim, omega) = PARAMS[i];
                let param_sum = (r_dim as u64) + (omega as u64);
                if i == (state.fold_step % 8) as usize {
                    if param_sum != (r_dim as u64 + omega as u64) {
                        return Err(ProgramError::InvalidArgument);
                    }
                }
            }
            // Serialize updated state
            state.serialize(&mut &mut state_account.data.borrow_mut()[..])?;
        }
    }
    Ok(())
}

// φ-delta: Sparse excitation (mimics btc8.py)
fn phi_delta_vector(lattice: &[u64], fold_step: u32) -> Vec<u64> {
    let mut delta = vec![SAFE_ZERO; lattice.len()];
    let slots_to_excite = 4 << fold_step.min(6); // Limit to prevent overflow
    for i in (fold_step as usize * 4)..(fold_step as usize * 4 + slots_to_excite) {
        if i < delta.len() {
            delta[i] = 0x2540BE400; // φ-harmonic excitation
        }
    }
    delta
}

// φ-add: Harmonic vector addition
fn phi_add_vector(lattice: &[u64], delta: &[u64]) -> Result<Vec<u64>, ProgramError> {
    if lattice.len() != delta.len() {
        return Err(ProgramError::InvalidArgument);
    }
    let mut result = vec![0; lattice.len()];
    for i in 0..lattice.len() {
        result[i] = lattice[i].wrapping_add(delta[i]); // Emulate OP_HDGL_VEC_ADD
    }
    Ok(result)
}