*! _xtcspqardl_estimate v1.0.0 — Per-panel quantile regression engine
*! CS-PQARDL: Panel Quantile ARDL with CCE augmentation
*! Called internally by xtcspqardl.ado
*! Author: Dr Merwan Roudane (merwanroudane920@gmail.com)
*! Date: February 2026
*! CSA variables are added to the LR equation only

capture program drop _xtcspqardl_estimate
program define _xtcspqardl_estimate, rclass
	version 15.1
	syntax , DEPVAR(string) INDEPVARS(string) LRVARS(string) ///
		P(integer) QLAGS(string) ///
		TAU(numlist >0 <1 sort) IVAR(string) TVAR(string) ///
		TOUSE(string) CSAVARS(string) [NOCONStant]

	* Parse
	local k : word count `indepvars'
	local k_lr : word count `lrvars'
	local ntau : word count `tau'
	local n_csa : word count `csavars'

	* Parse q lags per variable
	local nqlags : word count `qlags'
	if `nqlags' == 1 {
		forvalues j = 1/`k' {
			local q`j' = `qlags'
		}
	}
	else if `nqlags' == `k' {
		forvalues j = 1/`k' {
			local q`j' : word `j' of `qlags'
		}
	}
	else {
		di as err "qlags() must have 1 or k elements"
		exit 198
	}

	* Get panel IDs
	qui levelsof `ivar' if `touse', local(ids)
	local npanels : word count `ids'

	* ================================================================
	* PRE-GENERATE ALL VARIABLES
	* ================================================================

	* --- Depvar ---
	tempvar dv_plain
	qui gen double `dv_plain' = `depvar' if `touse'
	local depvar_q "`dv_plain'"

	* --- LR variables ---
	local lr_varlist ""
	forvalues j = 1/`k_lr' {
		local lrv : word `j' of `lrvars'
		tempvar lr_plain`j'
		qui gen double `lr_plain`j'' = `lrv' if `touse'
		local lr_varlist "`lr_varlist' `lr_plain`j''"
	}

	* --- Contemporaneous indepvars ---
	local indep_plain ""
	forvalues j = 1/`k' {
		local xvar : word `j' of `indepvars'
		tempvar x_plain`j'
		qui gen double `x_plain`j'' = `xvar' if `touse'
		local indep_plain "`indep_plain' `x_plain`j''"
	}

	* --- AR lags of depvar (p-1 additional lags) ---
	local ar_varlist ""
	if `p' > 1 {
		forvalues lag = 1/`= `p' - 1' {
			tempvar ar_lag`lag'
			qui gen double `ar_lag`lag'' = L`lag'.`dv_plain' if `touse'
			local ar_varlist "`ar_varlist' `ar_lag`lag''"
		}
	}
	local ncoefs_ar = `p' - 1

	* --- SR impact: contemporaneous + lags of each indepvar ---
	local sr_varlist ""
	local ncoefs_sr = 0
	forvalues j = 1/`k' {
		local xvar_p : word `j' of `indep_plain'
		local sr_varlist "`sr_varlist' `xvar_p'"
		local ++ncoefs_sr
		if `q`j'' > 1 {
			forvalues lag = 1/`= `q`j'' - 1' {
				tempvar sr_`j'_lag`lag'
				qui gen double `sr_`j'_lag`lag'' = L`lag'.`xvar_p' if `touse'
				local sr_varlist "`sr_varlist' `sr_`j'_lag`lag''"
				local ++ncoefs_sr
			}
		}
	}

	* --- CSA variables (already generated, just create plain copies) ---
	local csa_plain ""
	local ci = 0
	foreach csav of local csavars {
		local ++ci
		tempvar csa_p`ci'
		qui gen double `csa_p`ci'' = `csav' if `touse'
		local csa_plain "`csa_plain' `csa_p`ci''"
	}

	* Build full regressor list: LR + AR + SR + CSA (CSA in LR equation)
	local fullreg "`lr_varlist' `ar_varlist' `sr_varlist' `csa_plain'"
	local ncoefs_lr = `k_lr'
	local ncoefs_total = `ncoefs_lr' + `ncoefs_ar' + `ncoefs_sr' + `n_csa'

	* ================================================================
	* Storage matrices
	* ================================================================
	local k_x = `k_lr' - 1
	local beta_dim = `k_x' * `ntau'
	local phi_dim = max(`ncoefs_ar', 1) * `ntau'
	local sr_dim = `ncoefs_sr' * `ntau'
	local csa_dim = `n_csa' * `ntau'

	tempname rho_all beta_all phi_all sr_all halflife_all csa_all

	matrix `rho_all' = J(`npanels', `ntau', .)
	matrix `beta_all' = J(`npanels', max(`beta_dim',1), .)
	matrix `halflife_all' = J(`npanels', `ntau', .)

	if `ncoefs_ar' > 0 {
		matrix `phi_all' = J(`npanels', `ncoefs_ar' * `ntau', .)
	}
	else {
		matrix `phi_all' = J(`npanels', `ntau', 0)
	}

	if `ncoefs_sr' > 0 {
		matrix `sr_all' = J(`npanels', `sr_dim', .)
	}
	else {
		matrix `sr_all' = J(1, 1, .)
	}

	matrix `csa_all' = J(`npanels', `csa_dim', .)

	* ================================================================
	* Loop over panels
	* ================================================================
	local pi = 0
	local success_count = 0

	foreach i of local ids {
		local ++pi

		qui count if `touse' & `ivar' == `i'
		local ni = r(N)

		if `ni' < `ncoefs_total' + 5 {
			continue
		}

		local any_tau_ok = 0
		local ti = 0

		foreach tauval of local tau {
			local ++ti
			local tq = round(`tauval' * 100)

			* Run quantile regression
			capture qui qreg `depvar_q' `fullreg' ///
				if `touse' & `ivar' == `i', quantile(`tq')

			if _rc != 0 & _rc != 498 {
				continue
			}
			if e(N) < 5 continue

			local any_tau_ok = 1

			tempname b_qr
			matrix `b_qr' = e(b)

			* ρ(τ) = coefficient on first LR var (lagged y level)
			matrix `rho_all'[`pi', `ti'] = `b_qr'[1, 1]

			* Half-life
			local rho_val = `b_qr'[1, 1]
			if `rho_val' < 0 {
				matrix `halflife_all'[`pi', `ti'] = ln(2) / abs(`rho_val')
			}

			* β(τ) = -coef(x_level) / coef(y_level)
			if abs(`rho_val') > 1e-10 {
				forvalues j = 2/`k_lr' {
					local bcol = (`ti' - 1) * `k_x' + (`j' - 1)
					matrix `beta_all'[`pi', `bcol'] = ///
						-`b_qr'[1, `j'] / `rho_val'
				}
			}

			* φ (AR lags)
			if `ncoefs_ar' > 0 {
				forvalues j = 1/`ncoefs_ar' {
					local pcol = (`ti' - 1) * `ncoefs_ar' + `j'
					local bpos = `k_lr' + `j'
					matrix `phi_all'[`pi', `pcol'] = `b_qr'[1, `bpos']
				}
			}

			* SR impact coefficients
			if `ncoefs_sr' > 0 {
				forvalues j = 1/`ncoefs_sr' {
					local scol = (`ti' - 1) * `ncoefs_sr' + `j'
					local bpos = `k_lr' + `ncoefs_ar' + `j'
					matrix `sr_all'[`pi', `scol'] = `b_qr'[1, `bpos']
				}
			}

			* CSA coefficients (nuisance)
			forvalues j = 1/`n_csa' {
				local ccol = (`ti' - 1) * `n_csa' + `j'
				local bpos = `k_lr' + `ncoefs_ar' + `ncoefs_sr' + `j'
				capture matrix `csa_all'[`pi', `ccol'] = `b_qr'[1, `bpos']
			}
		}

		if `any_tau_ok' {
			local ++success_count
		}
	}

	* ================================================================
	* Compute Mean Group averages
	* ================================================================
	tempname rho_mg beta_mg halflife_mg phi_mg sr_mg csa_coef_mg
	matrix `rho_mg' = J(1, `ntau', .)
	matrix `beta_mg' = J(1, max(`beta_dim',1), .)
	matrix `halflife_mg' = J(1, `ntau', .)

	if `ncoefs_ar' > 0 {
		matrix `phi_mg' = J(1, `ncoefs_ar' * `ntau', .)
	}
	else {
		matrix `phi_mg' = J(1, `ntau', .)
	}
	if `ncoefs_sr' > 0 {
		matrix `sr_mg' = J(1, `sr_dim', .)
	}
	else {
		matrix `sr_mg' = J(1, 1, .)
	}
	matrix `csa_coef_mg' = J(1, max(`csa_dim',1), .)

	* Rho & halflife averages
	forvalues t = 1/`ntau' {
		local cnt = 0
		local cnt_hl = 0
		local sum_r = 0
		local sum_hl = 0
		forvalues i = 1/`npanels' {
			if `rho_all'[`i', `t'] != . {
				local ++cnt
				local sum_r = `sum_r' + `rho_all'[`i', `t']
			}
			if `halflife_all'[`i', `t'] != . {
				local ++cnt_hl
				local sum_hl = `sum_hl' + `halflife_all'[`i', `t']
			}
		}
		if `cnt' > 0 matrix `rho_mg'[1, `t'] = `sum_r' / `cnt'
		if `cnt_hl' > 0 matrix `halflife_mg'[1, `t'] = `sum_hl' / `cnt_hl'
	}

	* Beta average
	local bdim = max(`beta_dim', 1)
	forvalues c = 1/`bdim' {
		local cnt = 0
		local sum_b = 0
		forvalues i = 1/`npanels' {
			if `beta_all'[`i', `c'] != . {
				local ++cnt
				local sum_b = `sum_b' + `beta_all'[`i', `c']
			}
		}
		if `cnt' > 0 matrix `beta_mg'[1, `c'] = `sum_b' / `cnt'
	}

	* Phi average
	local phi_cols = colsof(`phi_mg')
	forvalues c = 1/`phi_cols' {
		local cnt = 0
		local sum_p = 0
		forvalues i = 1/`npanels' {
			if `phi_all'[`i', `c'] != . {
				local ++cnt
				local sum_p = `sum_p' + `phi_all'[`i', `c']
			}
		}
		if `cnt' > 0 matrix `phi_mg'[1, `c'] = `sum_p' / `cnt'
	}

	* SR average
	if `ncoefs_sr' > 0 {
		forvalues c = 1/`sr_dim' {
			local cnt = 0
			local sum_s = 0
			forvalues i = 1/`npanels' {
				if `sr_all'[`i', `c'] != . {
					local ++cnt
					local sum_s = `sum_s' + `sr_all'[`i', `c']
				}
			}
			if `cnt' > 0 matrix `sr_mg'[1, `c'] = `sum_s' / `cnt'
		}
	}

	* CSA average
	local cdim = max(`csa_dim', 1)
	forvalues c = 1/`cdim' {
		local cnt = 0
		local sum_c = 0
		forvalues i = 1/`npanels' {
			if `csa_all'[`i', `c'] != . {
				local ++cnt
				local sum_c = `sum_c' + `csa_all'[`i', `c']
			}
		}
		if `cnt' > 0 matrix `csa_coef_mg'[1, `c'] = `sum_c' / `cnt'
	}

	* ================================================================
	* MG variance: V = (1/(N(N-1))) Σ(b_i - b̄)(b_i - b̄)'
	* ================================================================
	tempname beta_V rho_V sr_V
	matrix `beta_V' = J(max(`beta_dim',1), max(`beta_dim',1), 0)
	matrix `rho_V' = J(`ntau', `ntau', 0)
	matrix `sr_V' = J(max(`sr_dim',1), max(`sr_dim',1), 0)

	* Beta variance: per-quantile block
	forvalues t = 1/`ntau' {
		local col_start = (`t' - 1) * `k_x' + 1
		local col_end = `t' * `k_x'

		if `k_x' < 1 continue

		local nv = 0
		forvalues i = 1/`npanels' {
			local ok = 1
			forvalues c = `col_start'/`col_end' {
				if `beta_all'[`i', `c'] == . local ok = 0
			}
			if `ok' local ++nv
		}

		if `nv' > 1 {
			forvalues i = 1/`npanels' {
				local ok = 1
				forvalues c = `col_start'/`col_end' {
					if `beta_all'[`i', `c'] == . local ok = 0
				}
				if `ok' {
					forvalues r = `col_start'/`col_end' {
						forvalues c = `col_start'/`col_end' {
							local dev_r = `beta_all'[`i', `r'] - `beta_mg'[1, `r']
							local dev_c = `beta_all'[`i', `c'] - `beta_mg'[1, `c']
							matrix `beta_V'[`r', `c'] = `beta_V'[`r', `c'] + ///
								`dev_r' * `dev_c'
						}
					}
				}
			}
			local scale = 1 / (`nv' * (`nv' - 1))
			forvalues r = `col_start'/`col_end' {
				forvalues c = `col_start'/`col_end' {
					matrix `beta_V'[`r', `c'] = `scale' * `beta_V'[`r', `c']
				}
			}
		}
	}

	* Rho variance: per-quantile diagonal
	forvalues t = 1/`ntau' {
		local nv = 0
		local ss = 0
		forvalues i = 1/`npanels' {
			if `rho_all'[`i', `t'] != . {
				local ++nv
				local dev = `rho_all'[`i', `t'] - `rho_mg'[1, `t']
				local ss = `ss' + `dev' * `dev'
			}
		}
		if `nv' > 1 {
			matrix `rho_V'[`t', `t'] = `ss' / (`nv' * (`nv' - 1))
		}
	}

	* SR variance: per-element diagonal (MG between-group variance)
	if `ncoefs_sr' > 0 {
		forvalues c = 1/`sr_dim' {
			local nv = 0
			local ss = 0
			forvalues i = 1/`npanels' {
				if `sr_all'[`i', `c'] != . {
					local ++nv
					local dev = `sr_all'[`i', `c'] - `sr_mg'[1, `c']
					local ss = `ss' + `dev' * `dev'
				}
			}
			if `nv' > 1 {
				matrix `sr_V'[`c', `c'] = `ss' / (`nv' * (`nv' - 1))
			}
		}
	}

	* CSA variance: per-element diagonal (MG between-group variance)
	tempname csa_V
	local csa_vdim = max(`csa_dim', 1)
	matrix `csa_V' = J(`csa_vdim', `csa_vdim', 0)

	forvalues c = 1/`csa_vdim' {
		local nv = 0
		local ss = 0
		forvalues i = 1/`npanels' {
			if `csa_all'[`i', `c'] != . {
				local ++nv
				local dev = `csa_all'[`i', `c'] - `csa_coef_mg'[1, `c']
				local ss = `ss' + `dev' * `dev'
			}
		}
		if `nv' > 1 {
			matrix `csa_V'[`c', `c'] = `ss' / (`nv' * (`nv' - 1))
		}
	}

	* ================================================================
	* Return results
	* ================================================================
	return scalar npanels = `npanels'
	return scalar valid_panels = `success_count'
	return scalar ntau = `ntau'
	return scalar k = `k'
	return scalar k_lr = `k_lr'
	return scalar p = `p'
	return scalar ncoefs_sr = `ncoefs_sr'

	return matrix rho_all = `rho_all'
	return matrix beta_all = `beta_all'
	return matrix halflife_all = `halflife_all'
	return matrix phi_all = `phi_all'
	return matrix sr_all = `sr_all'
	return matrix csa_all = `csa_all'

	return matrix rho_mg = `rho_mg'
	return matrix beta_mg = `beta_mg'
	return matrix halflife_mg = `halflife_mg'
	return matrix phi_mg = `phi_mg'
	return matrix sr_mg = `sr_mg'
	return matrix csa_coef_mg = `csa_coef_mg'

	return matrix beta_V = `beta_V'
	return matrix rho_V = `rho_V'
	return matrix sr_V = `sr_V'
	return matrix csa_V = `csa_V'
end