struct MonthlyScaler{T} <: AbstractSesScaler
    mode::Int8
    factors::AbstractVecOrMat{T}
end
struct WeeklyScaler{T} <: AbstractSesScaler
    mode::Int8
    factors::AbstractVecOrMat{T}
end
struct DayOfYearScaler{T} <: AbstractSesScaler
    mode::Int8
    factors::AbstractVecOrMat{T}
end
struct DayOfWeekScaler{T} <: AbstractSesScaler
    mode::Int8
    factors::AbstractVecOrMat{T}
end



struct InvMonthlyScaler <: AbstractInvSesScaler
    scaler::MonthlyScaler
end
struct InvWeeklyScaler <: AbstractInvSesScaler
    scaler::WeeklyScaler
end
struct InvDayOfYearScaler <: AbstractInvSesScaler
    scaler::DayOfYearScaler
end
struct InvDayOfWeekScaler <: AbstractInvSesScaler
    scaler::DayOfWeekScaler
end



function MonthlyScaler(mode::Int8 = inte_two)
    moy = init_factors(mode = mode, init = Float32(1/12), dims = (12, 1));
    return MonthlyScaler(mode, moy);
end
function WeeklyScaler(mode::Int8 = inte_two)
    woy = init_factors(mode = mode, init = Float32(1/53), dims = (53, 1));
    return WeeklyScaler(mode, woy);
end
function DayOfYearScaler(mode::Int8 = inte_two)
    doy = init_factors(mode = mode, init = Float32(1/366), dims = (366, 1));
    return DayOfYearScaler(mode, doy);
end
function DayOfWeekScaler(mode::Int8 = inte_two)
    doy = init_factors(mode = mode, init = Float32(1/7), dims = (7, 1));
    return DayOfWeekScaler(mode, doy);
end



function Base.show(io::IO, scaler::MonthlyScaler)
    print(io, "Monthly Scaler (\n");
    print(io, "moy:", scaler.factors, "\n");
    print(io, ")");
end
function Base.show(io::IO, scaler::WeeklyScaler)
    print(io, "Weekly Scaler (\n");
    print(io, "woy:", scaler.factors, "\n");
    print(io, ")");
end
function Base.show(io::IO, scaler::DayOfYearScaler)
    print(io, "Day of Year Scaler (\n");
    print(io, "doy:", scaler.factors, "\n");
    print(io, ")");
end
function Base.show(io::IO, scaler::DayOfWeekScaler)
    print(io, "Day of Week Scaler (\n");
    print(io, "dow:", scaler.factors, "\n");
    print(io, ")");
end



function Base.show(io::IO, invscaler::InvMonthlyScaler)
    print(io, "Inv. Monthly Scaler (\n");
    print(io, "moy:", invscaler.scaler.factors, "\n");
    print(io, ")");
end
function Base.show(io::IO, invscaler::InvWeeklyScaler)
    print(io, "Inv. Weekly Scaler (\n");
    print(io, "woy:", invscaler.scaler.factors, "\n");
    print(io, ")");
end
function Base.show(io::IO, invscaler::InvDayOfYearScaler)
    print(io, "Inv. Day of Year Scaler (\n");
    print(io, "doy:", invscaler.scaler.factors, "\n");
    print(io, ")");
end
function Base.show(io::IO, invscaler::InvDayOfWeekScaler)
    print(io, "Inv. Day of Week Scaler (\n");
    print(io, "dow:", invscaler.scaler.factors, "\n");
    print(io, ")");
end



filter_indexes(::S, idxs::Dict{Symbol, <:AbstractVector{I}}) where {I, S<:Union{MonthlyScaler, InvMonthlyScaler}} =
    idxs[:moy];
filter_indexes(::S, idxs::Dict{Symbol, <:AbstractVector{I}}) where {I, S<:Union{WeeklyScaler, InvWeeklyScaler}} =
    idxs[:woy];
filter_indexes(::S, idxs::Dict{Symbol, <:AbstractVector{I}}) where {I, S<:Union{DayOfYearScaler, InvDayOfYearScaler}} =
    idxs[:doy];
filter_indexes(::S, idxs::Dict{Symbol, <:AbstractVector{I}}) where {I, S<:Union{DayOfWeekScaler, InvDayOfWeekScaler}} =
    idxs[:dow];



function (mop::MonthlyScaler{L})(labels::Union{L, AbstractVecOrMat{L}}, idxs::Dict{Symbol, <:AbstractVector{I}}) where {I, L}
    # println("[MonthlyScaler Scaler Called]")
    # println("Labels: $labels\nIdxs: $idxs")
    mop(labels, idxs[:moy]), idxs;
end
function (wop::WeeklyScaler{L})(labels::Union{L, AbstractVecOrMat{L}}, idxs::Dict{Symbol, <:AbstractVector{I}}) where {I, L}
    # println("[WeeklyScaler Scaler Called]")
    # println("Labels: $labels\nIdxs: $idxs")
    wop(labels, idxs[:woy]), idxs;
end
function (dyop::DayOfYearScaler{L})(labels::Union{L, AbstractVecOrMat{L}}, idxs::Dict{Symbol, <:AbstractVector{I}}) where {I, L}
    # println("[DayOfYearScaler Scaler Called]")
    # println("Labels: $labels\nIdxs: $idxs")
    dyop(labels, idxs[:doy]), idxs;
end
function (dwop::DayOfWeekScaler{L})(labels::Union{L, AbstractVecOrMat{L}}, idxs::Dict{Symbol, <:AbstractVector{I}}) where {I, L}
    # println("[DayOfWeekScaler Scaler Called]")
    # println("Labels: $labels\nIdxs: $idxs")
    dwop(labels, idxs[:dow]), idxs;
end



(invmop::InvMonthlyScaler)(labels::Union{L, AbstractVecOrMat{L}}, idxs::Dict{Symbol, <:AbstractVector{I}}) where {I, L} =
    invmop(labels, idxs[:moy]), idxs;
(invwop::InvWeeklyScaler)(labels::Union{L, AbstractVecOrMat{L}}, idxs::Dict{Symbol, <:AbstractVector{I}}) where {I, L} =
    invwop(labels, idxs[:woy]), idxs;
(invdyop::InvDayOfYearScaler)(labels::Union{L, AbstractVecOrMat{L}}, idxs::Dict{Symbol, <:AbstractVector{I}}) where {I, L} =
    invdyop(labels, idxs[:doy]), idxs;
(invdwop::InvDayOfWeekScaler)(labels::Union{L, AbstractVecOrMat{L}}, idxs::Dict{Symbol, <:AbstractVector{I}}) where {I, L} =
    invdwop(labels, idxs[:dow]), idxs;



@functor MonthlyScaler
@functor WeeklyScaler
@functor DayOfYearScaler
@functor DayOfWeekScaler



trainable(mop::MonthlyScaler) = (mop.factors,)
trainable(invmop::InvMonthlyScaler) = (invmop.scaler,)
trainable(wop::WeeklyScaler) = (wop.factors,)
trainable(invwop::InvWeeklyScaler) = (invwop.scaler,)
trainable(dyop::DayOfYearScaler) = (dyop.factors,)
trainable(invdyop::InvDayOfYearScaler) = (invdyop.scaler,)
trainable(dwop::DayOfWeekScaler) = (dwop.factors,)
trainable(invdwop::InvDayOfWeekScaler) = (invdwop.scaler,)