use anchor_lang::prelude::*;

declare_id!("9jwLscZsufQERhh4wnc8p5hNYTw6Sz5CrkC3Kejjb1vK");

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

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

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

    pub fn register_commitment(ctx: Context<RegisterCommitment>) -> Result<()> {
        let state = &mut ctx.accounts.privacy_state;
        require!(state.active, PrivacyError::PolicyNotActive);

        let commitment = &mut ctx.accounts.commitment;
        commitment.agent = ctx.accounts.agent.key();
        commitment.policy_version = state.version;
        commitment.committed = true;
        // A self-registration is a declaration, not independently verified
        // evidence of privacy compliance.
        commitment.compliant = false;
        commitment.committed_at = Clock::get()?.unix_timestamp;

        state.total_commitments = state
            .total_commitments
            .checked_add(1)
            .ok_or(PrivacyError::ArithmeticOverflow)?;

        emit!(PrivacyCommitmentRegistered {
            agent: commitment.agent,
            policy_version: state.version,
            committed_at: commitment.committed_at,
        });
        Ok(())
    }

    /// No proof verifier or independent adjudication binding exists yet. Do
    /// not let either an agent or a unilateral authority convert a declaration
    /// into a compliance claim.
    pub fn update_compliance(_ctx: Context<UpdateCompliance>, _compliant: bool) -> Result<()> {
        err!(PrivacyError::ComplianceVerificationUnavailable)
    }

    pub fn close_commitment(ctx: Context<CloseCommitment>) -> Result<()> {
        let commitment = &mut ctx.accounts.commitment;
        require!(commitment.committed, PrivacyError::CommitmentAlreadyClosed);
        commitment.committed = false;

        let state = &mut ctx.accounts.privacy_state;
        state.total_commitments = state
            .total_commitments
            .checked_sub(1)
            .ok_or(PrivacyError::AccountingInvariantViolation)?;

        emit!(PrivacyCommitmentClosed {
            agent: commitment.agent,
            policy_version: commitment.policy_version,
            closed_at: Clock::get()?.unix_timestamp,
        });
        Ok(())
    }
}

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

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

#[derive(Accounts)]
pub struct RegisterCommitment<'info> {
    #[account(
        mut,
        seeds = [b"privacy"],
        bump
    )]
    pub privacy_state: Account<'info, PrivacyState>,
    #[account(
        init,
        payer = agent,
        space = 8 + 32 + 4 + 1 + 1 + 8,
        seeds = [b"commitment", agent.key().as_ref()],
        bump
    )]
    pub commitment: Account<'info, PrivacyCommitment>,
    #[account(mut)]
    pub agent: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct UpdateCompliance<'info> {
    #[account(
        mut,
        seeds = [b"commitment", authority.key().as_ref()],
        bump
    )]
    pub commitment: Account<'info, PrivacyCommitment>,
    pub authority: Signer<'info>,
}

#[derive(Accounts)]
pub struct CloseCommitment<'info> {
    #[account(
        mut,
        seeds = [b"privacy"],
        bump
    )]
    pub privacy_state: Account<'info, PrivacyState>,
    #[account(
        mut,
        close = agent,
        seeds = [b"commitment", agent.key().as_ref()],
        bump,
        has_one = agent
    )]
    pub commitment: Account<'info, PrivacyCommitment>,
    #[account(mut)]
    pub agent: Signer<'info>,
}

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

#[account]
pub struct PrivacyCommitment {
    pub agent: Pubkey,
    pub policy_version: u32,
    pub committed: bool,
    pub compliant: bool,
    pub committed_at: i64,
}

#[event]
pub struct PrivacyCommitmentRegistered {
    pub agent: Pubkey,
    pub policy_version: u32,
    pub committed_at: i64,
}

#[event]
pub struct ComplianceUpdated {
    pub agent: Pubkey,
    pub compliant: bool,
    pub updated_at: i64,
}

#[event]
pub struct PrivacyCommitmentClosed {
    pub agent: Pubkey,
    pub policy_version: u32,
    pub closed_at: i64,
}

#[error_code]
pub enum PrivacyError {
    #[msg("Policy exceeds maximum length of 500 characters")]
    PolicyTooLong,
    #[msg("Privacy policy is not active")]
    PolicyNotActive,
    #[msg("Arithmetic overflow")]
    ArithmeticOverflow,
    #[msg("Privacy commitment accounting invariant violated")]
    AccountingInvariantViolation,
    #[msg("Privacy commitment is already closed")]
    CommitmentAlreadyClosed,
    #[msg("Privacy compliance cannot be marked verified without an approved proof or adjudication design")]
    ComplianceVerificationUnavailable,
    #[msg("Bootstrap is disabled until a source-backed partner authority design is approved")]
    BootstrapDisabled,
}
