cap program drop nnlme
program define nnlme, eclass byable(onecall) prop(me xt mi bayes xtbs)
    version 17.0

    // Step 1: Parse the dependent variable
    syntax varlist(min=1 max=1) [if] [in], ///
        SURV(varlist) Time(varname)  ///
		[ID(varname)] ///
        [SHAPE(varlist)] [ITer(integer 0)]		///
		[	METHod(string)		///
			RESCOVariance(string)	///
			RESCORRelation(string) 	///
			RESVARiance(string)	///
			INITial(string)		///
			lmeopts(string)		///
			pnlsopts(string)	///
			NOCONStant		/// /* eq linear form	*/
			xb			/// /* eq linear form	*/
			EMITERate(passthru)	///
			EMTOLerance(passthru)	///
			emlog			///
		]
    // Extract dependent variable
    gettoken depvar rest : varlist

    // Validate required options
    if "`id'" == "" {
        di as error "option id() is required"
        exit 198
    }
    if "`surv'" == "" {
        di as error "option surv() is required"
        exit 198
    }
    if "`time'" == "" {
        di as error "option time() is required"
        exit 198
    }

    capture confirm numeric variable `time'
    if _rc {
        di as error "The variable specified in time() must be numeric."
        exit 198
    }
	qui

    // Run the model
    di as txt " "
    di as txt " "
    di as txt ">>> Starting up NNLME <<<"
    di as txt " "
    di as txt " "

	// Set default iteration count
    if `iter' == 0 {
        local iter = 25
    }
	else {
        di as txt ">>> Max Iteration Set: `iter'"
    }

        // Build the model based on whether shape variables are specified
        if "`shape'" != "" {
            menl `depvar' = {ri1:} + {surv:}*{sl1:} + {shp:}, ///
                define(ri1: U0[`id'] , xb) ///
                define(shp: `shape', xb) ///
				define(sl1: -exp({a00})) ///
                define(surv: ln(1 + exp(min(700, `time' - exp(-{curv_c1: `surv', xb}))))) ///
                iterate(`iter') ///
                stddev noretable nofetable noheader
        }
        else {
            menl `depvar' = {ri1:} + {surv:}*{sl1:}, ///
                define(ri1: U0[`id'], xb) ///
				define(sl1: -exp({a00})) ///
                define(surv: ln(1 + exp(min(700, `time' - exp(-{curv_c1: `surv', xb}))))) ///
                iterate(`iter') ///
                stddev noretable nofetable noheader
        }

    // Check if model estimation succeeded
    if _rc {
        di as error ">>> Model estimation failed, code: `_rc'."
        exit _rc
    }
   // Store estimation results
    tempname coef V coef_mat
    matrix `coef' = e(b)
    matrix `coef_mat' = e(b)
    matrix `V' = e(V)
    local N = e(N)
	local L = e(ll)
	local fit = round(e(ll),.01)
    local names : colnames `coef_mat'
    local n_coef = colsof(`coef_mat')
	local eqs : coleq `coef_mat'
    local p = round(e(p),.001)
	local ch = round(e(chi2),.01)
	mat def H = e(hierstats)
	local group = H[1,1]
	local hier = round(H[1,2],.001)

    ereturn post `coef' `V', obs(`N')
	ereturn scalar ll = `L'
    ereturn local cmd "nnlme"

	// Custom display routine
    di as txt _n "Nested Non-Linear Longitudinal Mixed-Effects Model" _col(58) "Number of obs" _col(72) "= "  as res `N'
    di as txt "Group Variable: `id' "	_col(58) "N. Groups" _col(72) "= "  as res `group'
    di as txt " "	_col(45) "Obs. w/in Groups" _col(72) "= "  as res `hier'
	di as txt _col(58) "Wald chi2"  _col(72) "= " as res "`ch'"
	di as txt "Linearization log likelihood = `fit'"	_col(58) "Prob. > Chi2" _col(72) "= " as res "`p'"
	di as txt " "

	// Track printed sections
	local surv_printed = 0
	local shape_printed = 0
	local a00_printed = 0
	local first_cons = 1
	local re_printed = 0
	local resid_printed = 0

	forvalues i = 1/`n_coef' {
		local eq : word `i' of `eqs'
		local vname : word `i' of `names'

		// Identify parameter type
		local is_shape = ("`eq'" == "shp")
		local is_surv = ("`eq'" == "curv_c1")
		local is_cons = ("`vname'" == "_cons")
		local is_a00 = ("`eq'" == "a00" | "`vname'" == "a00")
		local is_re = ("`eq'" == "`id'" | "`vname'" == "`id'" | strpos("`vname'", "lnsd"))
		local is_resid = strpos("`vname'", "lnsigma")


		// Skip if not relevant
		if !(`is_surv' | `is_shape' | `is_a00' | `is_re' | `is_resid') continue

		// Print headers
		if `is_surv' & !`surv_printed' {
			di as txt "{hline 80}"
			di as txt _col(14) "{c |}" _col(20) "NIR" _col(30) "Std. Err." _col(45) "Z" _col(52) "P>|Z|" _col(60) "[95% Conf. Interval]"
			di as txt "{hline 13}{c +}{hline 67}"
			di as txt "/survival" _col(14) "{c |}"
			local surv_printed = 1
		}
		if `is_shape' & !`shape_printed' {
			di as txt "{hline 13}{c +}{hline 67}"
			di as txt _col(14) "{c |}" _col(20) "Coef." _col(30) "Std. Err." _col(45) "Z" _col(52) "P>|z|" _col(60) "[95% Conf. Interval]"
			di as txt "{hline 13}{c +}{hline 67}"
			di as txt "/shape" _col(14) "{c |}"
			local shape_printed = 1
		}
		if `is_a00' & !`a00_printed' {
			di as txt "{hline 13}{c +}{hline 67}"
			di as txt "/acc. param." _col(14) "{c |}"
			local a00_printed = 1
		}
		if `is_re' & !`re_printed' {
		di as txt "{hline 13}{c +}{hline 67}"
		di as txt "Random Eff." _col(14) "{c |}" _col(20) "Est." _col(30) "Std. Err." _col(45) "Z" _col(52) "P>|z|" _col(60) "[95% Conf. Interval]"
		di as txt "{hline 13}{c +}{hline 67}"
		di as txt "/`id'" _col(14) "{c |}"
        local re_printed = 1
		}
		if `is_resid' & !`resid_printed' {
			di as txt "/residual" _col(14) "{c |}"
			local resid_printed = 1
		}
		// Extract statistics
		local coef = `coef_mat'[1, `i']
		local se = sqrt(e(V)[`i', `i'])
		local z = `coef' / `se'
		local p = 2*(1 - normal(abs(`z')))
		local ci_lb = `coef' - 1.96*`se'
		local ci_ub = `coef' + 1.96*`se'

		// Rename second _cons in shape to intercept
		local display_vname "`vname'"
		if "`vname'" == "_cons" & `first_cons' & `is_shape' {
			local display_vname "intercept"
			local first_cons = 1
		}

		// Custom display formatting
		if `is_surv' {
			local display_coef = exp(`coef')
			local display_ci_lb = exp(`ci_lb')
			local display_ci_ub = exp(`ci_ub')
		}

		else {
			local display_coef = `coef'
			local display_ci_lb = `ci_lb'
			local display_ci_ub = `ci_ub'
		}

	// Display row
	di as txt %12s "`display_vname'" _col(14) "{c |}" as res ///
    _col(16) %9.0g `display_coef' ///
    _col(28) %9.0g `se' ///
    _col(40) %6.2f `z' ///
    _col(49) %6.3f `p' ///
    _col(58) %9.0g `display_ci_lb' ///
    _col(70) %9.0g `display_ci_ub'
	}
	if e(converged)==1 {
		di "Warning: Convergence not achieved."
}
di as txt "{hline 80}"
end