use anchor_lang::prelude::*;

declare_id!("7qWbfWrNVhGa9poR5DkwYyYwepBm4kQ3uJuDsxF5YMAo");

// Solana limits each individual PDA seed to 32 bytes. Keep the accepted
// user-controlled key within that limit because it is used directly as a seed.
const MAX_BELIEF_KEY_SEED_BYTES: usize = 32;

#[program]
pub mod belief_attestation_verifier {
    use super::*;

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        let deployment_authorized = false;
        require!(deployment_authorized, BeliefError::BootstrapDisabled);
        let state = &mut ctx.accounts.verifier_state;
        state.authority = ctx.accounts.authority.key();
        state.total_attestations = 0;
        state.active = true;
        state.created_at = Clock::get()?.unix_timestamp;
        Ok(())
    }

    pub fn submit_attestation(
        ctx: Context<SubmitAttestation>,
        belief_key: String,
        belief_value: String,
    ) -> Result<()> {
        require!(
            belief_key.len() <= MAX_BELIEF_KEY_SEED_BYTES,
            BeliefError::KeyTooLong
        );
        require!(belief_value.len() <= 256, BeliefError::ValueTooLong);

        let state = &mut ctx.accounts.verifier_state;
        require!(state.active, BeliefError::VerifierNotActive);

        let attestation = &mut ctx.accounts.attestation;
        attestation.agent = ctx.accounts.agent.key();
        attestation.belief_key = belief_key.clone();
        attestation.belief_value = belief_value.clone();
        attestation.verified = false;
        attestation.attested_at = Clock::get()?.unix_timestamp;

        state.total_attestations = state
            .total_attestations
            .checked_add(1)
            .ok_or(BeliefError::ArithmeticOverflow)?;

        emit!(AttestationSubmitted {
            agent: attestation.agent,
            belief_key,
            belief_value,
            attested_at: attestation.attested_at,
        });
        Ok(())
    }

    pub fn verify_attestation(ctx: Context<VerifyAttestation>, approved: bool) -> Result<()> {
        let attestation = &mut ctx.accounts.attestation;
        attestation.verified = approved;

        emit!(AttestationVerified {
            agent: attestation.agent,
            belief_key: attestation.belief_key.clone(),
            approved,
            verified_at: Clock::get()?.unix_timestamp,
        });
        Ok(())
    }
}

#[derive(Accounts)]
pub struct Initialize<'info> {
    #[account(
        init,
        payer = authority,
        space = 8 + 32 + 8 + 1 + 8,
        seeds = [b"belief_verifier"],
        bump
    )]
    pub verifier_state: Account<'info, VerifierState>,
    #[account(mut)]
    pub authority: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
#[instruction(belief_key: String, belief_value: String)]
pub struct SubmitAttestation<'info> {
    #[account(
        mut,
        seeds = [b"belief_verifier"],
        bump
    )]
    pub verifier_state: Account<'info, VerifierState>,
    #[account(
        init,
        payer = agent,
        space = 8 + 32 + 4 + 64 + 4 + 256 + 1 + 8,
        seeds = [b"belief", agent.key().as_ref(), belief_key.as_bytes()],
        bump
    )]
    pub attestation: Account<'info, BeliefAttestation>,
    #[account(mut)]
    pub agent: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct VerifyAttestation<'info> {
    #[account(
        seeds = [b"belief_verifier"],
        bump,
        has_one = authority
    )]
    pub verifier_state: Account<'info, VerifierState>,
    #[account(mut)]
    pub attestation: Account<'info, BeliefAttestation>,
    pub authority: Signer<'info>,
}

#[account]
pub struct VerifierState {
    pub authority: Pubkey,
    pub total_attestations: u64,
    pub active: bool,
    pub created_at: i64,
}

#[account]
pub struct BeliefAttestation {
    pub agent: Pubkey,
    pub belief_key: String,
    pub belief_value: String,
    pub verified: bool,
    pub attested_at: i64,
}

#[event]
pub struct AttestationSubmitted {
    pub agent: Pubkey,
    pub belief_key: String,
    pub belief_value: String,
    pub attested_at: i64,
}

#[event]
pub struct AttestationVerified {
    pub agent: Pubkey,
    pub belief_key: String,
    pub approved: bool,
    pub verified_at: i64,
}

#[error_code]
pub enum BeliefError {
    #[msg("Belief key exceeds the 32-byte PDA seed limit")]
    KeyTooLong,
    #[msg("Belief value exceeds maximum length of 256 characters")]
    ValueTooLong,
    #[msg("Belief verifier is not active")]
    VerifierNotActive,
    #[msg("Arithmetic overflow")]
    ArithmeticOverflow,
    #[msg("Bootstrap is disabled until a source-backed partner authority design is approved")]
    BootstrapDisabled,
}
