function [args,additionalargs] = offlineTemplateLinearParameters(mdl,modelType,varargin)
%

%   Copyright 2022-2023 The MathWorks, Inc.

disallowedParams = {'Beta','Bias','Learner','BatchIndex','FitBias','Epsilon'};


if isa(mdl,"ClassificationKernel")
    disallowedParams = [disallowedParams 'Standardize']; % kernel models do not support standardize
    templateLinearParamsList = [{'Solver','BatchSize','Lambda','LearnRate','LearnRateSchedule',...
        'EstimationPeriod','Shuffle'},disallowedParams];
else
    templateLinearParamsList = [{'Solver','BatchSize','Lambda','LearnRate','LearnRateSchedule',...
        'EstimationPeriod','Shuffle','Standardize'},disallowedParams];
end

try
    if isa(mdl,'classreg.learning.FitTemplate')
        mdl = fillIfNeeded(mdl,modelType);
    end

    cleanedupargs = incremental.utils.partialMatchParameters(templateLinearParamsList,modelType,varargin{:});
    additionalargs = incremental.utils.validateDisallowedParameters(mdl,disallowedParams,cleanedupargs);
    args = struct();
    solverIsArg = false;
    if isfield(additionalargs,'Solver')
        args.Solver = validatestring(additionalargs.Solver,{'sgd','asgd','scale-invariant'},mfilename,'Solver');
        solverIsArg = true;
    else
        if isempty(mdl.ModelParams.Solver)
            args.Solver = 'scale-invariant';
        else
            args.Solver =  mdl.ModelParams.Solver{:};
        end
    end

    if ~isempty(mdl.ModelParams.Lambda)
        assert(isscalar(mdl.ModelParams.Lambda),message('stats:incremental:Offline:LinearNonScalarLambda'));
    end

    if ~isempty(mdl.ModelParams.InitialBeta)
        args.Beta = mdl.ModelParams.InitialBeta; % use the impl so that kernel models can use the same code
    end

    if ~isempty(mdl.ModelParams.InitialBias)
        args.Bias = mdl.ModelParams.InitialBias;
    end

    if ~isempty(mdl.ModelParams.Stream)
        args.Stream = mdl.ModelParams.Stream;
    end

    if ~isempty(mdl.ModelParams.Learner)
        args.Learner = mdl.ModelParams.Learner;
    end

    rglz = mdl.ModelParams.Regularization;
    isRidge = isempty(rglz) | strcmpi(rglz,'ridge');

    isSolverSgdAsgd = false;
    if ~isempty(mdl.ModelParams.Solver)
        if isequal(mdl.ModelParams.Solver{:},'sgd') || isequal(mdl.ModelParams.Solver{:},'asgd')
            isSolverSgdAsgd = true;
        end
    end

    if isSolverSgdAsgd &&  isRidge
        if solverIsArg && (isequal(args.Solver,'sgd') || isequal(args.Solver,'asgd'))
            assert(isequal(mdl.ModelParams.Solver{:},args.Solver),message('stats:incremental:Template:InvalidLinearSolverChange',mdl.ModelParams.Solver{:}));
        end
        additionalargs = incremental.utils.validateDisallowedParameters(mdl,{'LearnRate','LearnRateSchedule','BatchSize','Lambda'},additionalargs);

        if ~isempty(mdl.ModelParams.LearnRate)
            args.LearnRate = mdl.ModelParams.LearnRate;
        end

        if ~isempty(mdl.ModelParams.BatchIndex)
            args.BatchIndex = mdl.ModelParams.BatchIndex;
        end

        if ~isempty(mdl.ModelParams.BatchSize)
            args.BatchSize = mdl.ModelParams.BatchSize;
        end

        args.LearnRateSchedule = 'decaying';

        if ~isempty(mdl.ModelParams.Lambda)
            args.Lambda = mdl.ModelParams.Lambda;
        end
    else
        if ~(isequal(args.Solver,'sgd') || isequal(args.Solver,'asgd'))
            additionalargs = incremental.utils.validateDisallowedParameters(mdl,{'LearnRate','LearnRateSchedule','BatchSize','Lambda'},additionalargs);

            if ~isempty(mdl.ModelParams.Lambda)
                args.Lambda = mdl.ModelParams.Lambda;
            end

            args.Solver = 'scale-invariant';
        else
            if ~solverIsArg
                additionalargs = incremental.utils.validateDisallowedParameters(mdl,{'LearnRate','LearnRateSchedule','BatchSize','Lambda'},additionalargs);

                if ~isempty(mdl.ModelParams.Lambda)
                    args.Lambda = mdl.ModelParams.Lambda;
                end

                args.Solver = 'scale-invariant';
            end
        end
    end
    if ~isempty(mdl.ModelParams.Epsilon)
        args.Epsilon = mdl.ModelParams.Epsilon;
    end

    if ~isempty(mdl.ModelParams.FitBias)
        args.FitBias = mdl.ModelParams.FitBias;
    end
catch ME
    throwAsCaller(ME);
end

end
