// File: basisu_astc_hdr_6x6_enc.h
#pragma once
#include "basisu_enc.h"
#include "../transcoder/basisu_astc_hdr_core.h"

namespace astc_6x6_hdr
{
	const uint32_t ASTC_HDR_6X6_DEF_USER_COMP_LEVEL = 2;
	const uint32_t ASTC_HDR_6X6_MAX_USER_COMP_LEVEL = 12;
	
	const uint32_t ASTC_HDR_6X6_MAX_COMP_LEVEL = 4;
	
	const float LDR_BLACK_BIAS = 0.0f;// .49f;
		
	// Note: This struct is copied several times, so do not place any heavyweight objects in here.
	struct astc_hdr_6x6_global_config
	{
		// Important: The Delta ITP colorspace error metric we use internally makes several assumptions about the nature of the HDR RGB inputs supplied to the encoder.
		// This encoder computes colorspace error in the ICtCp (or more accurately the delta E ITP, where CT is scaled by .5 vs. ICtCp to become T) colorspace, so getting this correct is important.
		// By default the encoder assumes the input is in absolute luminance (in nits or candela per square meter, cd/m^2), specified as positive-only linear light RGB, using the REC 709 colorspace gamut (but NOT the sRGB transfer function, i.e. linear light).
		// If the m_rec2020_bt2100_color_gamut flag is true, the input colorspace is treated as REC 2020/BT.2100 (which is wider than 709).
		// For SDR/LDR->HDR upconversion, the REC 709 sRGB input should be converted to linear light (sRGB->linear) and the resulting normalized linear RGB values scaled by either 80 or 100 nits (the luminance of a typical SDR monitor). 
		// SDR upconversion to normalized [0,1] (i.e. non-absolute) luminances may work but is not supported because ITP errors will not be predicted correctly.
		// 11/3/2025: This flag is always copied straight into the output KTX2 DFD colorspace, even for non-HDR formats.
		// TODO: Move this parameter to reflect this.
		bool m_rec2020_bt2100_color_gamut = false; 

		// levels 0-3 normal levels, 4=exhaustive
		uint32_t m_master_comp_level = 0;
		uint32_t m_highest_comp_level = 1;

		float m_lambda = 0.0f;

		bool m_extra_patterns_flag = false; // def to false, works in comp levels [1,4]
		bool m_brute_force_partition_matching = false; // def to false

		bool m_jnd_optimization = false; // defaults to false for HDR inputs, on SDR upconverted images this can default to enabled
		float m_jnd_delta_itp_thresh = .75f;

		bool m_force_one_strip = false;
				
		bool m_gaussian1_fallback = true; // def to true, if this is disabled m_gaussian2_fallback should be disabled too
		float m_gaussian1_strength = 1.45f;

		bool m_gaussian2_fallback = true; // def to true, hopefully rarely kicks in
		float m_gaussian2_strength = 1.83f;
				
		// m_disable_delta_endpoint_usage may give a slight increase in RDO ASTC encoding efficiency. It's also faster.
		bool m_disable_delta_endpoint_usage = false;

		// Scale up Delta ITP errors for very dark pixels, assuming they will be brightly exposed > 1.0x.
		// We don't know if the output will be exposed, or not. If heavily exposed, our JND calculations will not be conservative enough.
		bool m_delta_itp_dark_adjustment = true;

		bool m_debug_images = false;
		std::string m_debug_image_prefix = "dbg_astc_hdr_6x6_devel_";

		bool m_output_images = false;
		std::string m_output_image_prefix = "dbg_astc_hdr_6x6_output_";

		bool m_debug_output = false;
		bool m_image_stats = false;
		bool m_status_output = false;

		//-------------------------------------------------------------------------------------
		// Very low level/devel parameters - intended for development. Best not to change them.
		//-------------------------------------------------------------------------------------
		bool m_deblocking_flag = true;
		float m_deblock_penalty_weight = .03f;
		bool m_disable_twothree_subsets = false; // def to false
		bool m_use_solid_blocks = true; // def to true
		bool m_use_runs = true; // def to true
		bool m_block_stat_optimizations_flag = true; // def to true	

		bool m_rdo_candidate_diversity_boost = true; // def to true
		float m_rdo_candidate_diversity_boost_bit_window_weight = 1.2f;

		bool m_favor_higher_compression = true; // utilize all modes
		uint32_t m_num_reuse_xy_deltas = basist::astc_6x6_hdr::NUM_REUSE_XY_DELTAS;

		// By default, for compatibility with KTX-Software (which uses v1.60), we write v1.6 compatible UASTC HDR 6x6i files.
		// The transcoder is compatible with both variants. This setting impacts how 2x2 blocks are upsampled and the initial marker version.
		// Eventually once KTX-Software upgrades to the latest version of basisu this will be defaulted to false.
		// If this is false a v2.0 or later transcoder is required for UASTC HDR 6x6i.
		bool m_write_basisu_1_6_compatible_files = true;

		void print() const
		{
			basisu::fmt_debug_printf("  m_master_comp_level: {}, m_highest_comp_level: {}\n", m_master_comp_level, m_highest_comp_level);
			basisu::fmt_debug_printf("  m_lambda: {}\n", m_lambda);
			basisu::fmt_debug_printf("  m_rec2020_bt2100_color_gamut: {}\n", m_rec2020_bt2100_color_gamut);
			basisu::fmt_debug_printf("  m_extra_patterns_flag: {}, m_brute_force_partition_matching: {}\n", m_extra_patterns_flag, m_brute_force_partition_matching);
			basisu::fmt_debug_printf("  m_jnd_optimization: {}, m_jnd_delta_itp_thresh: {}\n", m_jnd_optimization, m_jnd_delta_itp_thresh);
			basisu::fmt_debug_printf("  m_force_one_strip: {}\n", m_force_one_strip);
			basisu::fmt_debug_printf("  m_gaussian1_fallback: {}, m_gaussian1_strength: {}\n", m_gaussian1_fallback, m_gaussian1_strength);
			basisu::fmt_debug_printf("  m_gaussian2_fallback: {}, m_gaussian2_strength: {}\n", m_gaussian2_fallback, m_gaussian2_strength);
			basisu::fmt_debug_printf("  m_disable_delta_endpoint_usage: {}\n", m_disable_delta_endpoint_usage);
			basisu::fmt_debug_printf("  m_delta_itp_dark_adjustment: {}\n", m_delta_itp_dark_adjustment);
			basisu::fmt_debug_printf("  m_debug_images: {}, m_debug_image_prefix: {}\n", m_debug_images, m_debug_image_prefix);
			basisu::fmt_debug_printf("  m_output_images: {}, m_output_image_prefix: {}\n", m_output_images, m_output_image_prefix);
			basisu::fmt_debug_printf("  m_image_stats: {}, m_status_output: {}\n", m_image_stats, m_status_output);
			basisu::fmt_debug_printf("  m_deblocking_flag: {}, m_deblock_penalty_weight: {}\n", m_deblocking_flag, m_deblock_penalty_weight);
			basisu::fmt_debug_printf("  m_disable_twothree_subsets: {}, m_use_solid_blocks: {}\n", m_disable_twothree_subsets, m_use_solid_blocks);
			basisu::fmt_debug_printf("  m_use_runs: {}, m_block_stat_optimizations_flag: {}\n", m_use_runs, m_block_stat_optimizations_flag);
			basisu::fmt_debug_printf("  m_rdo_candidate_diversity_boost: {}, m_rdo_candidate_diversity_boost_bit_window_weight: {}\n", m_rdo_candidate_diversity_boost, m_rdo_candidate_diversity_boost_bit_window_weight);
			basisu::fmt_debug_printf("  m_favor_higher_compression: {}, m_num_reuse_xy_deltas: {}\n", m_favor_higher_compression, m_num_reuse_xy_deltas);
			basisu::fmt_debug_printf("  m_write_basisu_1_6_compatible_files: {}\n", m_write_basisu_1_6_compatible_files);
		}
				
		astc_hdr_6x6_global_config()
		{
		}

		void clear()
		{
			astc_hdr_6x6_global_config def;
			std::swap(*this, def);
		}

		// Max level is ASTC_HDR_6X6_MAX_USER_COMP_LEVEL
		void set_user_level(int level);
	};

	void global_init();

	struct result_metrics
	{
		basisu::image_metrics m_im_astc_log2;
		basisu::image_metrics m_im_astc_half;

		basisu::image_metrics m_im_bc6h_log2;
		basisu::image_metrics m_im_bc6h_half;
	};
	
	// The input image should be unpadded to 6x6 boundaries, i.e. the original unexpanded image.
	bool compress_photo(const basisu::imagef& orig_src_img, const astc_hdr_6x6_global_config& global_cfg, basisu::job_pool* pJob_pool,
		basisu::uint8_vec& intermediate_tex_data, basisu::uint8_vec& astc_tex_data, result_metrics& metrics);

} // namespace uastc_6x6_hdr
