use anchor_lang::prelude::*;

declare_id!("DGG9vAbddydCSYPgDEA4KeyWBVwbe6hXhhT1i4FqJpqQ");

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

    pub fn initialize(ctx: Context<Initialize>, policy: String) -> Result<()> {
        let deployment_authorized = false;
        require!(deployment_authorized, SurveillanceError::BootstrapDisabled);
        require!(policy.len() <= 500, SurveillanceError::PolicyTooLong);
        let state = &mut ctx.accounts.surveillance_state;
        state.authority = ctx.accounts.authority.key();
        state.policy = policy;
        state.version = 1;
        state.active = true;
        state.updated_at = Clock::get()?.unix_timestamp;
        Ok(())
    }

    pub fn update_policy(ctx: Context<UpdatePolicy>, new_policy: String) -> Result<()> {
        require!(new_policy.len() <= 500, SurveillanceError::PolicyTooLong);
        let state = &mut ctx.accounts.surveillance_state;
        state.policy = new_policy;
        state.version = state
            .version
            .checked_add(1)
            .ok_or(SurveillanceError::ArithmeticOverflow)?;
        state.updated_at = Clock::get()?.unix_timestamp;
        Ok(())
    }

    pub fn attest_compliance(ctx: Context<AttestCompliance>) -> Result<()> {
        let state = &ctx.accounts.surveillance_state;
        require!(state.active, SurveillanceError::PolicyNotActive);

        let attestation = &mut ctx.accounts.attestation;
        attestation.agent = ctx.accounts.agent.key();
        attestation.policy_version = state.version;
        // An agent's signature is a declaration only; it is not independent
        // evidence that surveillance has not occurred.
        attestation.compliant = false;
        attestation.attested_at = Clock::get()?.unix_timestamp;

        emit!(ComplianceAttested {
            agent: attestation.agent,
            policy_version: state.version,
            attested_at: attestation.attested_at,
        });
        Ok(())
    }

    pub fn reject_surveillance(ctx: Context<RejectSurveillance>, reason: String) -> Result<()> {
        require!(reason.len() <= 200, SurveillanceError::ReasonTooLong);
        let state = &ctx.accounts.surveillance_state;
        require!(state.active, SurveillanceError::PolicyNotActive);

        emit!(SurveillanceRejected {
            agent: ctx.accounts.agent.key(),
            reason,
            rejected_at: Clock::get()?.unix_timestamp,
        });
        Ok(())
    }
}

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

#[derive(Accounts)]
pub struct UpdatePolicy<'info> {
    #[account(
        mut,
        seeds = [b"surveillance"],
        bump,
        has_one = authority
    )]
    pub surveillance_state: Account<'info, SurveillanceState>,
    pub authority: Signer<'info>,
}

#[derive(Accounts)]
pub struct AttestCompliance<'info> {
    #[account(
        seeds = [b"surveillance"],
        bump
    )]
    pub surveillance_state: Account<'info, SurveillanceState>,
    #[account(
        init,
        payer = agent,
        space = 8 + 32 + 4 + 1 + 8,
        seeds = [b"attestation", agent.key().as_ref()],
        bump
    )]
    pub attestation: Account<'info, ComplianceAttestation>,
    #[account(mut)]
    pub agent: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct RejectSurveillance<'info> {
    #[account(
        seeds = [b"surveillance"],
        bump
    )]
    pub surveillance_state: Account<'info, SurveillanceState>,
    pub agent: Signer<'info>,
}

#[account]
pub struct SurveillanceState {
    pub authority: Pubkey,
    pub policy: String,
    pub version: u32,
    pub active: bool,
    pub updated_at: i64,
}

#[account]
pub struct ComplianceAttestation {
    pub agent: Pubkey,
    pub policy_version: u32,
    pub compliant: bool,
    pub attested_at: i64,
}

#[event]
pub struct ComplianceAttested {
    pub agent: Pubkey,
    pub policy_version: u32,
    pub attested_at: i64,
}

#[event]
pub struct SurveillanceRejected {
    pub agent: Pubkey,
    pub reason: String,
    pub rejected_at: i64,
}

#[error_code]
pub enum SurveillanceError {
    #[msg("Policy exceeds maximum length of 500 characters")]
    PolicyTooLong,
    #[msg("Anti-surveillance policy is not active")]
    PolicyNotActive,
    #[msg("Rejection reason exceeds maximum length of 200 characters")]
    ReasonTooLong,
    #[msg("Arithmetic overflow")]
    ArithmeticOverflow,
    #[msg("Bootstrap is disabled until a source-backed partner authority design is approved")]
    BootstrapDisabled,
}
