//! Builders for large params struct from autogenerated bindings.
//!
//! The bindings contain many massive structs which are used as parameters to
//! functions in the API. This module provides builders to simplify creating
//! these struct. They each have a `new()` method which has the minimum required
//! parameters for the struct. Other options

use std::ffi::c_void;

use crate::sys::nvEncodeAPI::{
	GUID, NV_ENC_BUFFER_FORMAT, NV_ENC_CONFIG, NV_ENC_INITIALIZE_PARAMS, NV_ENC_INITIALIZE_PARAMS_VER,
	NV_ENC_INPUT_RESOURCE_TYPE, NV_ENC_PIC_FLAGS, NV_ENC_PIC_PARAMS, NV_ENC_PIC_PARAMS_VER, NV_ENC_REGISTER_RESOURCE,
	NV_ENC_REGISTER_RESOURCE_VER,
};

#[deprecated(note = "use the safe wrapper `EncoderInitParams`")]
impl NV_ENC_INITIALIZE_PARAMS {
	/// Builder for [`NV_ENC_INITIALIZE_PARAMS`].
	#[must_use]
	pub fn new(encode_guid: GUID, width: u32, height: u32) -> Self {
		NV_ENC_INITIALIZE_PARAMS {
			version: NV_ENC_INITIALIZE_PARAMS_VER,
			encodeGUID: encode_guid,
			encodeWidth: width,
			encodeHeight: height,
			..Default::default()
		}
	}

	/// Specifies the preset for encoding. If the preset GUID is set then
	/// the preset configuration will be applied before any other parameter.
	pub fn preset_guid(&mut self, preset_guid: GUID) -> &mut Self {
		self.presetGUID = preset_guid;
		self
	}

	/// Specifies the advanced codec specific structure. If client has sent a
	/// valid codec config structure, it will override parameters set by the
	/// [`NV_ENC_INITIALIZE_PARAMS::preset_guid`].
	///
	/// The client can query the interface for codec-specific parameters
	/// using [`Encoder::get_preset_config`](super::encoder::Encoder::get_preset_config).
	/// It can then modify (if required) some of the codec config parameters and
	/// send down a custom config structure using this method. Even in this
	/// case the client is recommended to pass the same preset GUID it has
	/// used to get the config.
	pub fn encode_config(&mut self, encode_config: &mut NV_ENC_CONFIG) -> &mut Self {
		self.encodeConfig = encode_config;
		self
	}

	/// Specifies the display aspect ratio (H264/HEVC) or the render
	/// width/height (AV1).
	pub fn display_aspect_ratio(&mut self, width: u32, height: u32) -> &mut Self {
		self.darWidth = width;
		self.darHeight = height;
		self
	}

	/// Specifies the framerate in frames per second as a fraction
	/// `numerator / denominator`.
	pub fn framerate(&mut self, numerator: u32, denominator: u32) -> &mut Self {
		self.frameRateNum = numerator;
		self.frameRateDen = denominator;
		self
	}

	/// Enable the Picture Type Decision to be taken by the
	/// `NvEncodeAPI` interface.
	pub fn enable_picture_type_decision(&mut self) -> &mut Self {
		self.enablePTD = 1;
		self
	}

	// TODO: Add other options
}

impl NV_ENC_PIC_PARAMS {
	/// Create an EOS empty frame that is used at the
	/// end of encoding to flush the encoder.
	#[must_use]
	pub fn end_of_stream() -> Self {
		NV_ENC_PIC_PARAMS {
			version: NV_ENC_PIC_PARAMS_VER,
			encodePicFlags: NV_ENC_PIC_FLAGS::NV_ENC_PIC_FLAG_EOS as u32,
			..Default::default()
		}
	}
}

impl NV_ENC_REGISTER_RESOURCE {
	/// Builder for [`NV_ENC_REGISTER_RESOURCE`].
	///
	/// # Arguments
	///
	/// * `resource_type` - Specifies the type of resource to be registered.
	///   Supported values are:
	///   - [`NV_ENC_INPUT_RESOURCE_TYPE::NV_ENC_INPUT_RESOURCE_TYPE_DIRECTX`],
	///   - [`NV_ENC_INPUT_RESOURCE_TYPE::NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR`],
	///   - [`NV_ENC_INPUT_RESOURCE_TYPE::NV_ENC_INPUT_RESOURCE_TYPE_OPENGL_TEX`]
	/// * `width` - Input frame width.
	/// * `height` - Input frame height.
	/// * `resource_to_register` - Handle to the resource that is being
	///   registered. In the case of
	///   [`NV_ENC_INPUT_RESOURCE_TYPE::NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR`],
	///   this should be a `CUdeviceptr` which you can get from
	///   `cuExternalMemoryGetMappedBuffer`.
	/// * `buffer_format` - Buffer format of resource to be registered.
	#[must_use]
	pub fn new(
		resource_type: NV_ENC_INPUT_RESOURCE_TYPE,
		width: u32,
		height: u32,
		resource_to_register: *mut c_void,
		buffer_format: NV_ENC_BUFFER_FORMAT,
	) -> Self {
		NV_ENC_REGISTER_RESOURCE {
			version: NV_ENC_REGISTER_RESOURCE_VER,
			resourceType: resource_type,
			width,
			height,
			pitch: width,
			resourceToRegister: resource_to_register,
			registeredResource: std::ptr::null_mut(),
			bufferFormat: buffer_format,
			..Default::default()
		}
	}

	/// Set the input buffer pitch.
	///
	/// - For [`NV_ENC_INPUT_RESOURCE_TYPE::NV_ENC_INPUT_RESOURCE_TYPE_DIRECTX`]
	///   resources, set this to 0.
	/// - For [`NV_ENC_INPUT_RESOURCE_TYPE::NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR`]
	///   resources, set this to the pitch as obtained from `cuMemAllocPitch()`,
	///   or to the width in **bytes** (if this resource was created by using
	///   `cuMemAlloc()`). This value must be a multiple of 4.
	/// - For [`NV_ENC_INPUT_RESOURCE_TYPE::NV_ENC_INPUT_RESOURCE_TYPE_OPENGL_TEX`]
	///   resources, set this to the texture width multiplied by the number of
	///   components in the texture format.
	#[must_use]
	pub fn pitch(mut self, pitch: u32) -> Self {
		self.pitch = pitch;
		self
	}

	// TODO: Add other options
}
