*! xtgets_mata: Mata helper functions for panel GETS indicator saturation
*! Version 1.0.0  14mar2026  Dr Merwan Roudane  merwanroudane920@gmail.com
*! Implements: IIS, FESIS, CSIS, CFESIS, TIS, JIIS, JSIS indicator generation
*! Based on Pretis & Schwarz (2022/2026) "Discovering What Mattered"
*! R package: getspanel (Schwarz & Pretis, 2026, CRAN)
*! Original time-series gets.ado by Damian C. Clarke (2013)
*!
*! The indicator generation follows the R package exactly:
*!   - FESIS uses block-diagonal step matrices (gets::sim + Matrix::bdiag)
*!   - CSIS uses step x regressor interactions
*!   - CFESIS uses block-diagonal step x regressor interactions per unit
*!   - TIS uses block-diagonal trend matrices (gets::tim + Matrix::bdiag)
*!   - IIS, JIIS, JSIS use gets::iim / gets::sim directly
*!
*! The GETS selection follows Clarke (2013) gets.ado:
*!   - tsort() Mata function for t-statistic sorting
*!   - Multiple search paths (numsearch)
*!   - Misspecification tests at each elimination step

********************************************************************************
*** Mata functions for xtgets
********************************************************************************

cap mata: mata drop xtgets_sim()
cap mata: mata drop xtgets_iim()
cap mata: mata drop xtgets_tim()
cap mata: mata drop xtgets_gen_fesis()
cap mata: mata drop xtgets_gen_csis()
cap mata: mata drop xtgets_gen_cfesis()
cap mata: mata drop xtgets_gen_tis()
cap mata: mata drop xtgets_gen_iis()
cap mata: mata drop xtgets_gen_jiis()
cap mata: mata drop xtgets_gen_jsis()
cap mata: mata drop tsort()

mata:

// ============================================================================
// xtgets_sim: Generate Step Indicator Matrix for T periods
// Replicates R gets::sim(T)
// Creates a T x (T-1) matrix of step indicators
// Column j = step starting at period j+1 (1 from period j+1 onward, 0 before)
// ============================================================================
real matrix xtgets_sim(real scalar T)
{
    real matrix S
    real scalar j

    S = J(T, T-1, 0)
    for (j = 1; j <= T-1; j++) {
        S[|j+1, j \ T, j|] = J(T-j, 1, 1)
    }
    return(S)
}

// ============================================================================
// xtgets_iim: Generate Impulse Indicator Matrix for T periods
// Replicates R gets::iim(T)
// Creates a T x T identity matrix
// ============================================================================
real matrix xtgets_iim(real scalar T)
{
    return(I(T))
}

// ============================================================================
// xtgets_tim: Generate Trend Indicator Matrix for T periods
// Replicates R gets::tim(T)
// Creates a T x (T-1) matrix of broken trend indicators
// Column j = trend starting at period j+1: 0,0,...,0,1,2,...,T-j
// ============================================================================
real matrix xtgets_tim(real scalar T)
{
    real matrix TI
    real scalar j, k

    TI = J(T, T-1, 0)
    for (j = 1; j <= T-1; j++) {
        for (k = j+1; k <= T; k++) {
            TI[k, j] = k - j
        }
    }
    return(TI)
}

// ============================================================================
// xtgets_gen_fesis: Fixed-Effect Step Indicator Saturation
// Replicates R isatpanel fesis logic exactly:
//   1. Create gets::sim(T) for each unit
//   2. Block-diagonal via Matrix::bdiag
//   3. Name: fesis{id}.{time}
// ============================================================================
void xtgets_gen_fesis(string scalar idvar, string scalar tvar,
                       string scalar prefix, string scalar touse)
{
    real colvector id, time
    real matrix id_vals, time_vals
    real scalar N, T, n, i, j, k, col_idx
    string scalar vname
    real matrix sim_mat, indicator

    st_view(id, ., idvar, touse)
    st_view(time, ., tvar, touse)
    n = rows(id)

    id_vals = uniqrows(id)
    time_vals = uniqrows(time)
    N = rows(id_vals)
    T = rows(time_vals)

    // Generate sim(T) — same for each unit
    sim_mat = xtgets_sim(T)

    k = 0
    for (i = 1; i <= N; i++) {
        for (j = 1; j <= T-1; j++) {
            // Create indicator: 1 for unit i from time_vals[j+1] onward
            indicator = J(n, 1, 0)
            col_idx = 1
            for (col_idx = 1; col_idx <= n; col_idx++) {
                if (id[col_idx] == id_vals[i]) {
                    // Find position of this obs within unit's time series
                    real scalar t_pos
                    t_pos = 0
                    real scalar tt
                    for (tt = 1; tt <= T; tt++) {
                        if (time_vals[tt] == time[col_idx]) {
                            t_pos = tt
                            break
                        }
                    }
                    if (t_pos > 0) {
                        indicator[col_idx] = sim_mat[t_pos, j]
                    }
                }
            }

            // Only add if not all zeros
            if (sum(indicator) > 0) {
                vname = prefix + strofreal(id_vals[i]) + "_" + strofreal(time_vals[j+1])
                (void) st_addvar("byte", vname)
                st_store(., vname, touse, indicator)
                k++
            }
        }
    }
    printf("{txt}  FESIS: generated %g step indicators (%g units x %g periods)\n",
           k, N, T-1)
}

// ============================================================================
// xtgets_gen_jsis: Joint Step Indicator Saturation
// Common step indicators across all units: gets::sim(T)
// ============================================================================
void xtgets_gen_jsis(string scalar idvar, string scalar tvar,
                      string scalar prefix, string scalar touse)
{
    real colvector id, time
    real matrix time_vals
    real scalar T, n, j, t, k
    string scalar vname
    real colvector indicator
    real matrix sim_mat

    st_view(id, ., idvar, touse)
    st_view(time, ., tvar, touse)
    n = rows(id)

    time_vals = uniqrows(time)
    T = rows(time_vals)

    sim_mat = xtgets_sim(T)

    k = 0
    for (j = 1; j <= T-1; j++) {
        indicator = J(n, 1, 0)
        for (t = 1; t <= n; t++) {
            real scalar t_pos2
            t_pos2 = 0
            real scalar tt2
            for (tt2 = 1; tt2 <= T; tt2++) {
                if (time_vals[tt2] == time[t]) {
                    t_pos2 = tt2
                    break
                }
            }
            if (t_pos2 > 0) {
                indicator[t] = sim_mat[t_pos2, j]
            }
        }
        if (sum(indicator) > 0) {
            vname = prefix + strofreal(time_vals[j+1])
            (void) st_addvar("byte", vname)
            st_store(., vname, touse, indicator)
            k++
        }
    }
    printf("{txt}  JSIS: generated %g joint step indicators\n", k)
}

// ============================================================================
// xtgets_gen_jiis: Joint Impulse Indicator Saturation
// Common impulse indicators: gets::iim(T) — one per time period
// ============================================================================
void xtgets_gen_jiis(string scalar idvar, string scalar tvar,
                      string scalar prefix, string scalar touse)
{
    real colvector id, time
    real matrix time_vals
    real scalar T, n, j, t, k
    string scalar vname
    real colvector indicator

    st_view(id, ., idvar, touse)
    st_view(time, ., tvar, touse)
    n = rows(id)

    time_vals = uniqrows(time)
    T = rows(time_vals)

    k = 0
    for (j = 1; j <= T; j++) {
        indicator = J(n, 1, 0)
        for (t = 1; t <= n; t++) {
            if (time[t] == time_vals[j]) {
                indicator[t] = 1
            }
        }
        vname = prefix + strofreal(time_vals[j])
        (void) st_addvar("byte", vname)
        st_store(., vname, touse, indicator)
        k++
    }
    printf("{txt}  JIIS: generated %g joint impulse indicators\n", k)
}

// ============================================================================
// xtgets_gen_iis: Impulse Indicator Saturation
// Block-diagonal identity: gets::iim(T) per unit
// ============================================================================
void xtgets_gen_iis(string scalar idvar, string scalar tvar,
                     string scalar prefix, string scalar touse)
{
    real colvector id, time
    real matrix id_vals, time_vals
    real scalar N, T, n, i, j, k, col_idx
    string scalar vname
    real colvector indicator

    st_view(id, ., idvar, touse)
    st_view(time, ., tvar, touse)
    n = rows(id)

    id_vals = uniqrows(id)
    time_vals = uniqrows(time)
    N = rows(id_vals)
    T = rows(time_vals)

    k = 0
    for (i = 1; i <= N; i++) {
        for (j = 1; j <= T; j++) {
            indicator = J(n, 1, 0)
            for (col_idx = 1; col_idx <= n; col_idx++) {
                if (id[col_idx] == id_vals[i] & time[col_idx] == time_vals[j]) {
                    indicator[col_idx] = 1
                }
            }
            if (sum(indicator) > 0) {
                vname = prefix + strofreal(id_vals[i]) + "_" + strofreal(time_vals[j])
                (void) st_addvar("byte", vname)
                st_store(., vname, touse, indicator)
                k++
            }
        }
    }
    printf("{txt}  IIS: generated %g impulse indicators (%g units x %g periods)\n",
           k, N, T)
}

// ============================================================================
// xtgets_gen_csis: Coefficient Step Indicator Saturation
// Common step x regressor interactions: gets::sim(T) * each X_k
// Replicates R isatpanel csis logic
// ============================================================================
void xtgets_gen_csis(string scalar idvar, string scalar tvar,
                      string scalar xvars, string scalar prefix,
                      string scalar touse)
{
    real colvector id, time
    real matrix X, time_vals
    real scalar T, K, n, j, kk, t, cnt
    string scalar vname
    real colvector indicator
    string rowvector xnames
    real matrix sim_mat

    st_view(id, ., idvar, touse)
    st_view(time, ., tvar, touse)
    n = rows(id)

    xnames = tokens(xvars)
    K = cols(xnames)
    st_view(X, ., xnames, touse)

    time_vals = uniqrows(time)
    T = rows(time_vals)

    sim_mat = xtgets_sim(T)

    cnt = 0
    for (kk = 1; kk <= K; kk++) {
        for (j = 1; j <= T-1; j++) {
            // Create step indicator x regressor
            indicator = J(n, 1, 0)
            for (t = 1; t <= n; t++) {
                real scalar t_pos3
                t_pos3 = 0
                real scalar tt3
                for (tt3 = 1; tt3 <= T; tt3++) {
                    if (time_vals[tt3] == time[t]) {
                        t_pos3 = tt3
                        break
                    }
                }
                if (t_pos3 > 0) {
                    indicator[t] = sim_mat[t_pos3, j] * X[t, kk]
                }
            }

            if (sum(abs(indicator)) > 0) {
                vname = prefix + xnames[kk] + "_" + strofreal(time_vals[j+1])
                (void) st_addvar("double", vname)
                st_store(., vname, touse, indicator)
                cnt++
            }
        }
    }
    printf("{txt}  CSIS: generated %g indicators (%g vars x %g periods)\n",
           cnt, K, T-1)
}

// ============================================================================
// xtgets_gen_cfesis: Coefficient-FE Step Indicator Saturation
// Block-diagonal step x regressor interactions per unit
// Replicates R isatpanel cfesis logic
// ============================================================================
void xtgets_gen_cfesis(string scalar idvar, string scalar tvar,
                        string scalar xvars, string scalar prefix,
                        string scalar touse)
{
    real colvector id, time
    real matrix X, id_vals, time_vals
    real scalar N, T, K, n, i, j, kk, t, cnt
    string scalar vname
    real colvector indicator
    string rowvector xnames
    real matrix sim_mat

    st_view(id, ., idvar, touse)
    st_view(time, ., tvar, touse)
    n = rows(id)

    xnames = tokens(xvars)
    K = cols(xnames)
    st_view(X, ., xnames, touse)

    id_vals = uniqrows(id)
    time_vals = uniqrows(time)
    N = rows(id_vals)
    T = rows(time_vals)

    sim_mat = xtgets_sim(T)

    cnt = 0
    for (kk = 1; kk <= K; kk++) {
        for (i = 1; i <= N; i++) {
            for (j = 1; j <= T-1; j++) {
                indicator = J(n, 1, 0)
                for (t = 1; t <= n; t++) {
                    if (id[t] == id_vals[i]) {
                        real scalar t_pos4
                        t_pos4 = 0
                        real scalar tt4
                        for (tt4 = 1; tt4 <= T; tt4++) {
                            if (time_vals[tt4] == time[t]) {
                                t_pos4 = tt4
                                break
                            }
                        }
                        if (t_pos4 > 0) {
                            indicator[t] = sim_mat[t_pos4, j] * X[t, kk]
                        }
                    }
                }
                if (sum(abs(indicator)) > 0) {
                    vname = prefix + xnames[kk] + "_" + strofreal(id_vals[i]) + "_" + strofreal(time_vals[j+1])
                    (void) st_addvar("double", vname)
                    st_store(., vname, touse, indicator)
                    cnt++
                }
            }
        }
    }
    printf("{txt}  CFESIS: generated %g indicators (%g vars x %g units x %g periods)\n",
           cnt, K, N, T-1)
}

// ============================================================================
// xtgets_gen_tis: Trend Indicator Saturation
// Block-diagonal trend matrices: gets::tim(T) per unit
// Replicates R isatpanel tis logic
// ============================================================================
void xtgets_gen_tis(string scalar idvar, string scalar tvar,
                     string scalar prefix, string scalar touse)
{
    real colvector id, time
    real matrix id_vals, time_vals
    real scalar N, T, n, i, j, t, k
    string scalar vname
    real colvector indicator
    real matrix tim_mat

    st_view(id, ., idvar, touse)
    st_view(time, ., tvar, touse)
    n = rows(id)

    id_vals = uniqrows(id)
    time_vals = uniqrows(time)
    N = rows(id_vals)
    T = rows(time_vals)

    tim_mat = xtgets_tim(T)

    k = 0
    for (i = 1; i <= N; i++) {
        for (j = 1; j <= T-1; j++) {
            indicator = J(n, 1, 0)
            for (t = 1; t <= n; t++) {
                if (id[t] == id_vals[i]) {
                    real scalar t_pos5
                    t_pos5 = 0
                    real scalar tt5
                    for (tt5 = 1; tt5 <= T; tt5++) {
                        if (time_vals[tt5] == time[t]) {
                            t_pos5 = tt5
                            break
                        }
                    }
                    if (t_pos5 > 0) {
                        indicator[t] = tim_mat[t_pos5, j]
                    }
                }
            }
            if (sum(abs(indicator)) > 0) {
                vname = prefix + strofreal(id_vals[i]) + "_" + strofreal(time_vals[j+1])
                (void) st_addvar("double", vname)
                st_store(., vname, touse, indicator)
                k++
            }
        }
    }
    printf("{txt}  TIS: generated %g trend indicators (%g units x %g periods)\n",
           k, N, T-1)
}

// ============================================================================
// tsort: Sort variables by absolute t-statistic
// EXACT COPY from gets.ado (Clarke, 2013)
// Returns the n-th smallest |t| variable position
// ============================================================================
void tsort(real matrix B, real matrix V, real scalar num)
{
    real vector se, t
    real matrix X
    real scalar dimn
    real vector a

    se = diagonal(V)
    se = sqrt(se)
    t = abs(B' :/ se)
    dimn = length(t)

    if (dimn <= 1) {
        _error(3202)
    }

    // Exclude last element (constant/cons)
    t = t[|1 \ dimn-1|]
    a = 1::dimn-1
    X = (t, a)
    X = sort(X, 1)

    if (num > rows(X)) {
        _error(3201)
    }

    st_numscalar("e(t)", X[num, 1])
    st_numscalar("e(var)", X[num, 2])
}

end