// SGX Remote Attestation Support

#![cfg_attr(feature = "sgx", no_std)]

#[cfg(feature = "sgx")]
extern crate sgx_tstd as std;

#[cfg(feature = "sgx")]
use sgx_types::*;

use super::SgxError;

/// Remote attestation for SGX enclaves
pub struct RemoteAttestation {
	#[cfg(feature = "sgx")]
	context: sgx_ra_context_t,
	sp_public_key: Option<[u8; 64]>,
	spid: Option<[u8; 16]>,
	quote: Option<Vec<u8>>,
}

impl RemoteAttestation {
	/// Create new remote attestation instance
	pub fn new() -> Self {
		Self {
			#[cfg(feature = "sgx")]
			context: 0,
			sp_public_key: None,
			spid: None,
			quote: None,
		}
	}

	/// Configure the Intel SGX Service Provider ID (SPID) used for EPID-based quotes.
	///
	/// Note: This is only required for quote generation flows that use a SPID (legacy EPID).
	pub fn configure_spid(&mut self, spid: [u8; 16]) {
		self.spid = Some(spid);
	}

	/// Initialize remote attestation with service provider
	#[cfg(feature = "sgx")]
	pub fn init_attestation(&mut self, sp_pub_key: &[u8; 64]) -> Result<(), SgxError> {
		self.sp_public_key = Some(*sp_pub_key);

		let mut context = 0;
		let result = unsafe {
			sgx_ra_init(
				sp_pub_key.as_ptr() as *const sgx_ec256_public_t,
				0, // Use default key derivation function
				&mut context,
			)
		};

		if result != sgx_status_t::SGX_SUCCESS {
			return Err(SgxError::AttestationError("Failed to initialize RA".into()));
		}

		self.context = context;
		Ok(())
	}

	#[cfg(not(feature = "sgx"))]
	pub fn init_attestation(&mut self, sp_pub_key: &[u8; 64]) -> Result<(), SgxError> {
		self.sp_public_key = Some(*sp_pub_key);
		Ok(())
	}

	/// Generate attestation quote
	#[cfg(feature = "sgx")]
	pub fn generate_quote(&mut self, user_data: &[u8]) -> Result<Vec<u8>, SgxError> {
		if user_data.len() > 64 {
			return Err(SgxError::AttestationError("User data too large".into()));
		}

		let spid = self
			.spid
			.ok_or_else(|| SgxError::AttestationError("SPID not configured".into()))?;

		// Get enclave report
		let mut target_info = sgx_target_info_t::default();
		let mut report_data = sgx_report_data_t::default();
		report_data.d[..user_data.len()].copy_from_slice(user_data);
		let mut report = sgx_report_t::default();

		let result = unsafe { sgx_create_report(&target_info, &report_data, &mut report) };

		if result != sgx_status_t::SGX_SUCCESS {
			return Err(SgxError::AttestationError("Failed to create report".into()));
		}

		// Generate quote from report using Quoting Enclave
		let quote_size = 2048;
		let mut quote = vec![0u8; quote_size];

		// Call Quoting Enclave to generate quote
		let qe_result = unsafe {
			sgx_get_quote(
				&report,
				sgx_quote_sign_type_t::SGX_LINKABLE_SIGNATURE,
				&spid as *const _ as *const sgx_spid_t,
				std::ptr::null(),
				std::ptr::null(),
				0,
				std::ptr::null_mut(),
				quote.as_mut_ptr() as *mut sgx_quote_t,
				quote_size as u32,
			)
		};

		if qe_result != sgx_status_t::SGX_SUCCESS {
			return Err(SgxError::AttestationError("Failed to generate quote".into()));
		}

		self.quote = Some(quote.clone());
		Ok(quote)
	}

	#[cfg(not(feature = "sgx"))]
	pub fn generate_quote(&mut self, user_data: &[u8]) -> Result<Vec<u8>, SgxError> {
		if user_data.len() > 64 {
			return Err(SgxError::AttestationError("User data too large".into()));
		}

		// Simulated quote for non-SGX builds
		let mut quote = vec![0u8; 256];
		quote[..user_data.len()].copy_from_slice(user_data);
		self.quote = Some(quote.clone());
		Ok(quote)
	}

	/// Get attestation quote
	pub fn get_quote(&self) -> Option<&[u8]> {
		self.quote.as_deref()
	}

	/// Close remote attestation context
	#[cfg(feature = "sgx")]
	pub fn close(&mut self) -> Result<(), SgxError> {
		if self.context != 0 {
			let result = unsafe { sgx_ra_close(self.context) };

			if result != sgx_status_t::SGX_SUCCESS {
				return Err(SgxError::AttestationError("Failed to close RA".into()));
			}

			self.context = 0;
		}
		Ok(())
	}

	#[cfg(not(feature = "sgx"))]
	pub fn close(&mut self) -> Result<(), SgxError> {
		Ok(())
	}
}

/// Quote verification for remote attestation
pub struct QuoteVerifier {
	ias_api_key: Option<String>,
	ias_url: Option<String>,
}

impl QuoteVerifier {
	/// Create new quote verifier
	pub fn new() -> Self {
		Self { ias_api_key: None, ias_url: None }
	}

	/// Verify quote with Intel Attestation Service
	fn verify_with_ias(&self, _quote: &[u8], _api_key: &str, _url: &str) -> Result<bool, SgxError> {
		// IAS verification implementation
		// This would make HTTPS request to IAS in production
		// Returns verification status
		Err(SgxError::AttestationError(
			"IAS quote verification is not implemented; do not treat quotes as verified".into(),
		))
	}

	/// Configure Intel Attestation Service (IAS)
	pub fn configure_ias(&mut self, api_key: String, url: String) {
		self.ias_api_key = Some(api_key);
		self.ias_url = Some(url);
	}

	/// Verify attestation quote
	pub fn verify_quote(&self, quote: &[u8]) -> Result<QuoteVerificationResult, SgxError> {
		// Send quote to Intel Attestation Service for verification
		let ias_api_key = self
			.ias_api_key
			.as_ref()
			.ok_or_else(|| SgxError::AttestationError("IAS API key not configured".into()))?;
		let ias_url = self
			.ias_url
			.as_ref()
			.ok_or_else(|| SgxError::AttestationError("IAS URL not configured".into()))?;

		// Perform IAS verification via HTTPS
		let verification_result = self.verify_with_ias(quote, ias_api_key, ias_url)?;

		if !verification_result {
			return Err(SgxError::AttestationError("Quote verification failed".into()));
		}

		// Extract and validate measurements
		Ok(QuoteVerificationResult {
			verified: verification_result,
			mrenclave: extract_mrenclave(quote),
			mrsigner: extract_mrsigner(quote),
			product_id: 0,
			isv_svn: 0,
			tcb_status: TcbStatus::UpToDate,
		})
	}
}

/// Quote verification result
#[derive(Debug, Clone)]
pub struct QuoteVerificationResult {
	pub verified: bool,
	pub mrenclave: [u8; 32],
	pub mrsigner: [u8; 32],
	pub product_id: u16,
	pub isv_svn: u16,
	pub tcb_status: TcbStatus,
}

/// TCB (Trusted Computing Base) status
#[derive(Debug, Clone)]
pub enum TcbStatus {
	UpToDate,
	SWHardeningNeeded,
	ConfigurationNeeded,
	OutOfDate,
	Revoked,
}

/// Extract MRENCLAVE from quote
fn extract_mrenclave(quote: &[u8]) -> [u8; 32] {
	let mut mrenclave = [0u8; 32];
	if quote.len() >= 64 {
		mrenclave.copy_from_slice(&quote[..32]);
	}
	mrenclave
}

/// Extract MRSIGNER from quote
fn extract_mrsigner(quote: &[u8]) -> [u8; 32] {
	let mut mrsigner = [0u8; 32];
	if quote.len() >= 96 {
		mrsigner.copy_from_slice(&quote[32..64]);
	}
	mrsigner
}

#[cfg(feature = "sgx")]
extern "C" {
	fn sgx_ra_init(
		p_pub_key: *const sgx_ec256_public_t,
		b_pse: i32,
		p_context: *mut sgx_ra_context_t,
	) -> sgx_status_t;

	fn sgx_ra_close(context: sgx_ra_context_t) -> sgx_status_t;

	fn sgx_create_report(
		p_ti: *const sgx_target_info_t,
		p_report_data: *const sgx_report_data_t,
		p_report: *mut sgx_report_t,
	) -> sgx_status_t;

	fn sgx_get_quote(
		p_report: *const sgx_report_t,
		quote_type: sgx_quote_sign_type_t,
		p_spid: *const sgx_spid_t,
		p_nonce: *const sgx_quote_nonce_t,
		p_sig_rl: *const u8,
		sig_rl_size: u32,
		p_qe_report: *mut sgx_report_t,
		p_quote: *mut sgx_quote_t,
		quote_size: u32,
	) -> sgx_status_t;
}
