function T = tdcs_load_data()
%TDCS_LOAD_DATA Load, join, and curate the raw tDCS reaching matrices.
%   T = TDCS_LOAD_DATA() reads analysis/matlab/raw/raw_success.csv and
%   raw_total.csv (app-exported matrix format: metric header line, blank
%   line, file "Group" line, "# Days Reach" subject-header line, then one
%   row per day with one value per subject column), reshapes each to long
%   form, joins them on (subject, day), applies the curated 12-animal
%   group map from tdcs_config (the file's own Group row is ignored),
%   and restricts to day >= 0.
%
%   Returns a table with variables:
%     subject  (string)      animal name
%     group    (categorical) curated group (Naive, Electrode-Box-A,
%                             Electrode-Box-A2, Electrode-Box-B2,
%                             Right-Electrode)
%     day      (double)      "# Days Reach" value, >= 0
%     success  (double)      successful reaches in the session
%     total    (double)      total attempts in the session
%
%   Only the 12 curated animals (per tdcs_config().groups) are retained;
%   any other animal present in the raw export is dropped.

thisDir = fileparts(mfilename('fullpath'));
successFile = fullfile(thisDir, 'raw', 'raw_success.csv');
totalFile = fullfile(thisDir, 'raw', 'raw_total.csv');

Tsuccess = localReadMatrix(successFile, 'success');
Ttotal = localReadMatrix(totalFile, 'total');

% Left join keyed on (subject, day): every non-blank Success cell becomes
% a row; Total is looked up for the same (subject, day). Per the plan's
% Global Constraints, Total is fully populated wherever Success is, so
% this should never introduce a missing total — but the join is a left
% join (not an inner join) specifically so that an unmatched Success row
% would still be kept (with total = NaN) rather than silently dropped.
T = outerjoin(Tsuccess, Ttotal, 'Keys', {'subject', 'day'}, ...
    'MergeKeys', true, 'Type', 'left');

% Apply the curated map: keep only the 12 curated animals, and assign
% group from the map (overriding the file's own Group row).
cfg = tdcs_config();
subjectsCell = cellstr(T.subject);
keep = isKey(cfg.groups, subjectsCell);
T = T(keep, :);
subjectsCell = subjectsCell(keep);

groupVals = cell(height(T), 1);
for i = 1:height(T)
    groupVals{i} = cfg.groups(subjectsCell{i});
end
T.group = categorical(groupVals);

% Restrict to day >= 0 (analysis window).
T = T(T.day >= 0, :);

% Final variable order and a deterministic row order.
T = T(:, {'subject', 'group', 'day', 'success', 'total'});
T = sortrows(T, {'subject', 'day'});

end

function Tlong = localReadMatrix(filePath, valueName)
%LOCALREADMATRIX Parse one app-exported day-by-subject matrix to long form.
%   Line 1 = "Data,<metric>" (skipped), line 2 blank (skipped), line 3 =
%   "Group,<...>" (skipped -- grouping comes from the curated map, not
%   this row), line 4 = "# Days Reach,<subject headers>" (columns 2:end
%   are the subject names), lines 5+ = "<day>,<value per subject>" with
%   blank cells meaning "no session that day for that subject".

lines = readlines(filePath);
% Defensive: drop any wholly-blank trailing line (e.g. if the file ends
% with a newline). Real data rows always start with a day number and are
% never zero-length.
while numel(lines) > 0 && strlength(strip(lines(end))) == 0
    lines(end) = [];
end

headerParts = strsplit(lines(4), ',', 'CollapseDelimiters', false);
subjects = string(headerParts(2:end));
nSubjects = numel(subjects);

dataLines = lines(5:end);
dataLines = dataLines(strlength(strip(dataLines)) > 0);
nRows = numel(dataLines);

day = nan(nRows * nSubjects, 1);
subjectCol = strings(nRows * nSubjects, 1);
value = nan(nRows * nSubjects, 1);

idx = 0;
for r = 1:nRows
    parts = strsplit(dataLines(r), ',', 'CollapseDelimiters', false);
    dayVal = str2double(parts(1));
    for c = 1:nSubjects
        col = c + 1;
        if col <= numel(parts)
            cellStr = strtrim(parts(col));
        else
            cellStr = "";
        end
        if strlength(cellStr) == 0
            continue
        end
        idx = idx + 1;
        day(idx) = dayVal;
        subjectCol(idx) = subjects(c);
        value(idx) = str2double(cellStr);
    end
end

day = day(1:idx);
subjectCol = subjectCol(1:idx);
value = value(1:idx);

Tlong = table(subjectCol, day, value, 'VariableNames', {'subject', 'day', valueName});

end
