use anchor_lang::prelude::*;

declare_id!("6DFwZ6RGdeAS1ZxbmfPvnh61S67V2764dbKe7HzqV45C");

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

    pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
        let deployment_authorized = false;
        require!(deployment_authorized, AdapterError::BootstrapDisabled);
        let state = &mut ctx.accounts.adapter_state;
        state.total_profiles = 0;
        state.created_at = Clock::get()?.unix_timestamp;
        Ok(())
    }

    pub fn create_profile(
        ctx: Context<CreateProfile>,
        name: String,
        description: String,
    ) -> Result<()> {
        require!(name.len() <= 64, AdapterError::NameTooLong);
        require!(description.len() <= 256, AdapterError::DescriptionTooLong);

        let state = &mut ctx.accounts.adapter_state;
        let profile = &mut ctx.accounts.agent_profile;

        profile.agent = ctx.accounts.agent.key();
        profile.name = name;
        profile.description = description;
        profile.created_at = Clock::get()?.unix_timestamp;
        profile.last_updated = profile.created_at;

        state.total_profiles = state
            .total_profiles
            .checked_add(1)
            .ok_or(AdapterError::ArithmeticOverflow)?;

        emit!(ProfileCreated {
            agent: profile.agent,
            created_at: profile.created_at,
        });
        Ok(())
    }

    pub fn update_profile(
        ctx: Context<UpdateProfile>,
        name: String,
        description: String,
    ) -> Result<()> {
        require!(name.len() <= 64, AdapterError::NameTooLong);
        require!(description.len() <= 256, AdapterError::DescriptionTooLong);

        let profile = &mut ctx.accounts.agent_profile;
        profile.name = name;
        profile.description = description;
        profile.last_updated = Clock::get()?.unix_timestamp;

        emit!(ProfileUpdated {
            agent: profile.agent,
            updated_at: profile.last_updated,
        });
        Ok(())
    }

    pub fn close_profile(ctx: Context<CloseProfile>) -> Result<()> {
        let profile = &ctx.accounts.agent_profile;
        let state = &mut ctx.accounts.adapter_state;
        state.total_profiles = state
            .total_profiles
            .checked_sub(1)
            .ok_or(AdapterError::AccountingInvariantViolation)?;
        emit!(ProfileClosed {
            agent: profile.agent,
            closed_at: Clock::get()?.unix_timestamp,
        });
        Ok(())
    }

    pub fn get_agent_profile(ctx: Context<GetProfile>) -> Result<()> {
        let profile = &ctx.accounts.agent_profile;
        emit!(ProfileQueried {
            agent: profile.agent,
            name: profile.name.clone(),
            queried_at: Clock::get()?.unix_timestamp,
        });
        Ok(())
    }
}

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

#[derive(Accounts)]
pub struct CreateProfile<'info> {
    #[account(
        mut,
        seeds = [b"adapter"],
        bump
    )]
    pub adapter_state: Account<'info, AdapterState>,
    #[account(
        init,
        payer = agent,
        space = 8 + 32 + 4 + 64 + 4 + 256 + 8 + 8,
        seeds = [b"profile", agent.key().as_ref()],
        bump
    )]
    pub agent_profile: Account<'info, AgentProfile>,
    #[account(mut)]
    pub agent: Signer<'info>,
    pub system_program: Program<'info, System>,
}

#[derive(Accounts)]
pub struct UpdateProfile<'info> {
    #[account(
        mut,
        seeds = [b"profile", agent.key().as_ref()],
        bump,
        has_one = agent
    )]
    pub agent_profile: Account<'info, AgentProfile>,
    pub agent: Signer<'info>,
}

#[derive(Accounts)]
pub struct CloseProfile<'info> {
    #[account(
        mut,
        seeds = [b"adapter"],
        bump
    )]
    pub adapter_state: Account<'info, AdapterState>,
    #[account(
        mut,
        close = agent,
        seeds = [b"profile", agent.key().as_ref()],
        bump,
        has_one = agent
    )]
    pub agent_profile: Account<'info, AgentProfile>,
    #[account(mut)]
    pub agent: Signer<'info>,
}

#[derive(Accounts)]
pub struct GetProfile<'info> {
    #[account()]
    pub agent_profile: Account<'info, AgentProfile>,
}

#[account]
pub struct AdapterState {
    pub total_profiles: u64,
    pub created_at: i64,
}

#[account]
pub struct AgentProfile {
    pub agent: Pubkey,
    pub name: String,
    pub description: String,
    pub created_at: i64,
    pub last_updated: i64,
}

#[event]
pub struct ProfileCreated {
    pub agent: Pubkey,
    pub created_at: i64,
}

#[event]
pub struct ProfileUpdated {
    pub agent: Pubkey,
    pub updated_at: i64,
}

#[event]
pub struct ProfileQueried {
    pub agent: Pubkey,
    pub name: String,
    pub queried_at: i64,
}

#[event]
pub struct ProfileClosed {
    pub agent: Pubkey,
    pub closed_at: i64,
}

#[error_code]
pub enum AdapterError {
    #[msg("Name exceeds maximum length of 64 characters")]
    NameTooLong,
    #[msg("Description exceeds maximum length of 256 characters")]
    DescriptionTooLong,
    #[msg("Arithmetic overflow")]
    ArithmeticOverflow,
    #[msg("Adapter profile accounting invariant violated")]
    AccountingInvariantViolation,
    #[msg("Bootstrap is disabled until a source-backed partner authority design is approved")]
    BootstrapDisabled,
}
