-- SPDX-FileCopyrightText: 2026 Alexandra de Wit
--
-- SPDX-License-Identifier: MIT

{- | The memory plan's public vocabulary: the resolved plan and the tenants that carry a
shape of their own. 'Ecluse.Composition.MemoryPlan.resolveMemoryPlan' solves for these, and
the composition root builds every byte-valued bound from them.
-}
module Ecluse.Composition.MemoryPlan.Types (
    MemoryPlan (..),
    PublishTenant (..),
    MirrorArtifactTenant (..),
    QueueTenantDemand (..),
    queueTenantDemand,
    TransientBudget (..),
) where

import Ecluse.Composition.MirrorQueue (MirrorQueuePlan (MemoryBackend, SqsBackend), MirrorRuntimePlan (MirrorWith, NoMirroring))

{- | Whether the memory plan owes the in-memory queue a tenant, projected from the
backend selection ('Ecluse.Composition.MirrorQueue.planMirrorRuntime').
-}
data QueueTenantDemand
    = -- | No mount mirrors: no queue tenant, no enqueue buffer.
      NoQueueTenant
    | -- | Mirroring rides a durable backend, so the plan charges the enqueue buffer alone.
      MirroringWithoutMemoryQueue
    | -- | Mirroring rides the in-memory queue: its depth is a tenant of this plan.
      MemoryQueueTenant
    deriving stock (QueueTenantDemand -> QueueTenantDemand -> Bool
(QueueTenantDemand -> QueueTenantDemand -> Bool)
-> (QueueTenantDemand -> QueueTenantDemand -> Bool)
-> Eq QueueTenantDemand
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: QueueTenantDemand -> QueueTenantDemand -> Bool
== :: QueueTenantDemand -> QueueTenantDemand -> Bool
$c/= :: QueueTenantDemand -> QueueTenantDemand -> Bool
/= :: QueueTenantDemand -> QueueTenantDemand -> Bool
Eq, Int -> QueueTenantDemand -> ShowS
[QueueTenantDemand] -> ShowS
QueueTenantDemand -> String
(Int -> QueueTenantDemand -> ShowS)
-> (QueueTenantDemand -> String)
-> ([QueueTenantDemand] -> ShowS)
-> Show QueueTenantDemand
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> QueueTenantDemand -> ShowS
showsPrec :: Int -> QueueTenantDemand -> ShowS
$cshow :: QueueTenantDemand -> String
show :: QueueTenantDemand -> String
$cshowList :: [QueueTenantDemand] -> ShowS
showList :: [QueueTenantDemand] -> ShowS
Show)

-- | Project the queue-tenant demand from the resolved mirror runtime plan.
queueTenantDemand :: MirrorRuntimePlan -> QueueTenantDemand
queueTenantDemand :: MirrorRuntimePlan -> QueueTenantDemand
queueTenantDemand = \case
    MirrorRuntimePlan
NoMirroring -> QueueTenantDemand
NoQueueTenant
    MirrorWith (SqsBackend SqsConfig
_) -> QueueTenantDemand
MirroringWithoutMemoryQueue
    MirrorWith MirrorQueuePlan
MemoryBackend -> QueueTenantDemand
MemoryQueueTenant

-- | The publish tenant: the aggregate byte-admission for concurrently buffered bodies.
newtype PublishTenant = PublishTenant
    { PublishTenant -> Int
ptAggregateBytes :: Int
    }
    deriving stock (PublishTenant -> PublishTenant -> Bool
(PublishTenant -> PublishTenant -> Bool)
-> (PublishTenant -> PublishTenant -> Bool) -> Eq PublishTenant
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: PublishTenant -> PublishTenant -> Bool
== :: PublishTenant -> PublishTenant -> Bool
$c/= :: PublishTenant -> PublishTenant -> Bool
/= :: PublishTenant -> PublishTenant -> Bool
Eq, Int -> PublishTenant -> ShowS
[PublishTenant] -> ShowS
PublishTenant -> String
(Int -> PublishTenant -> ShowS)
-> (PublishTenant -> String)
-> ([PublishTenant] -> ShowS)
-> Show PublishTenant
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PublishTenant -> ShowS
showsPrec :: Int -> PublishTenant -> ShowS
$cshow :: PublishTenant -> String
show :: PublishTenant -> String
$cshowList :: [PublishTenant] -> ShowS
showList :: [PublishTenant] -> ShowS
Show)

{- | The mirror-artifact tenant, present only when some mount mirrors. The plan charges its
heap as 'matMaxBytes' scaled by 'Ecluse.Composition.MemoryPlan.Bounds.mirrorArtifactEnvelopeMultiplier'.
-}
newtype MirrorArtifactTenant = MirrorArtifactTenant
    { MirrorArtifactTenant -> Int
matMaxBytes :: Int
    -- ^ The worker's per-artifact fetch byte cap (the tarball bound @B@).
    }
    deriving stock (MirrorArtifactTenant -> MirrorArtifactTenant -> Bool
(MirrorArtifactTenant -> MirrorArtifactTenant -> Bool)
-> (MirrorArtifactTenant -> MirrorArtifactTenant -> Bool)
-> Eq MirrorArtifactTenant
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: MirrorArtifactTenant -> MirrorArtifactTenant -> Bool
== :: MirrorArtifactTenant -> MirrorArtifactTenant -> Bool
$c/= :: MirrorArtifactTenant -> MirrorArtifactTenant -> Bool
/= :: MirrorArtifactTenant -> MirrorArtifactTenant -> Bool
Eq, Int -> MirrorArtifactTenant -> ShowS
[MirrorArtifactTenant] -> ShowS
MirrorArtifactTenant -> String
(Int -> MirrorArtifactTenant -> ShowS)
-> (MirrorArtifactTenant -> String)
-> ([MirrorArtifactTenant] -> ShowS)
-> Show MirrorArtifactTenant
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> MirrorArtifactTenant -> ShowS
showsPrec :: Int -> MirrorArtifactTenant -> ShowS
$cshow :: MirrorArtifactTenant -> String
show :: MirrorArtifactTenant -> String
$cshowList :: [MirrorArtifactTenant] -> ShowS
showList :: [MirrorArtifactTenant] -> ShowS
Show)

{- | The resolved plan: every byte-valued bound the composition root builds with, each an
explicit config value or its tenant-derived default. Override violations are the one refusal.
-}
data MemoryPlan = MemoryPlan
    { MemoryPlan -> Int
mpRuntimeReserveBytes :: Int
    -- ^ Tenant 1, taken off the top. Zero with no ceiling datapoint.
    , MemoryPlan -> Int
mpCacheAggregateBytes :: Int
    -- ^ Tenant 3: one shared byte bound for all eligible local cache stores.
    , MemoryPlan -> Int
mpCacheMaxEntries :: Int
    , MemoryPlan -> Int
mpMaxResponseBytes :: Int
    -- ^ The fixed metadata ingest ceiling, independent of memory and CPU admission.
    , MemoryPlan -> Int
mpMaxRequestBytes :: Int
    -- ^ The per-request (publish body) wire cap @Q@, enforced at the publish read site.
    , MemoryPlan -> Int
mpAdmissionCapacity :: Int
    -- ^ CPU-derived concurrency, or the exact explicit operator pin.
    , MemoryPlan -> Maybe PublishTenant
mpPublishTenant :: Maybe PublishTenant
    -- ^ Tenant 5, present only when a publication target is configured.
    , MemoryPlan -> Maybe MirrorArtifactTenant
mpMirrorArtifactTenant :: Maybe MirrorArtifactTenant
    -- ^ Tenant 7, present only when some mount mirrors. Carries the worker's cap.
    , MemoryPlan -> Int
mpQueueMemoryMaxDepth :: Int
    -- ^ The in-memory queue's depth cap (the build parameter, always resolved).
    , MemoryPlan -> Int
mpQueueTenantBytes :: Int
    -- ^ Tenant 6: the bytes the depth charges. Zero unless the memory backend runs.
    , MemoryPlan -> Int
mpFixedBufferBytes :: Int
    -- ^ Tenant 2: the enqueue buffer, charged whenever any mount mirrors.
    , MemoryPlan -> TransientBudget
mpTransientBudget :: TransientBudget
    -- ^ The live data metadata requests may hold at once, which the memory meter enforces.
    , MemoryPlan -> [Text]
mpDegradations :: [Text]
    -- ^ Shed-ladder and explicit-control warnings.
    , MemoryPlan -> [Text]
mpOverrideViolations :: [Text]
    {- ^ The pins the plan blames for a residual overshoot it cannot shed around. The boot and
    check-config refuse on these with exit 2.
    -}
    }
    deriving stock (MemoryPlan -> MemoryPlan -> Bool
(MemoryPlan -> MemoryPlan -> Bool)
-> (MemoryPlan -> MemoryPlan -> Bool) -> Eq MemoryPlan
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: MemoryPlan -> MemoryPlan -> Bool
== :: MemoryPlan -> MemoryPlan -> Bool
$c/= :: MemoryPlan -> MemoryPlan -> Bool
/= :: MemoryPlan -> MemoryPlan -> Bool
Eq, Int -> MemoryPlan -> ShowS
[MemoryPlan] -> ShowS
MemoryPlan -> String
(Int -> MemoryPlan -> ShowS)
-> (MemoryPlan -> String)
-> ([MemoryPlan] -> ShowS)
-> Show MemoryPlan
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> MemoryPlan -> ShowS
showsPrec :: Int -> MemoryPlan -> ShowS
$cshow :: MemoryPlan -> String
show :: MemoryPlan -> String
$cshowList :: [MemoryPlan] -> ShowS
showList :: [MemoryPlan] -> ShowS
Show)

-- | The budget the boot hands the meter and the sampler, in bytes of live data.
data TransientBudget = TransientBudget
    { TransientBudget -> Maybe Int
tbLiveTargetBytes :: Maybe Int
    -- ^ The live data the heap holds in the collector's normal regime. 'Nothing' without a ceiling.
    , TransientBudget -> Int
tbExplainedBytes :: Int
    -- ^ Live data outside the budget: the idle process and the other tenants.
    , TransientBudget -> Int
tbBootBytes :: Int
    -- ^ The budget at boot.
    , TransientBudget -> Maybe Int
tbLiveCeilingBytes :: Maybe Int
    -- ^ The live data the sampler lets charges and the measured remainder reach together.
    , TransientBudget -> Int
tbFloorBytes :: Int
    -- ^ The least the sampler may shrink the budget to.
    , TransientBudget -> Maybe Int
tbOverflowLiveBytes :: Maybe Int
    -- ^ The live data at which the copying collector overflows the ceiling.
    }
    deriving stock (TransientBudget -> TransientBudget -> Bool
(TransientBudget -> TransientBudget -> Bool)
-> (TransientBudget -> TransientBudget -> Bool)
-> Eq TransientBudget
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: TransientBudget -> TransientBudget -> Bool
== :: TransientBudget -> TransientBudget -> Bool
$c/= :: TransientBudget -> TransientBudget -> Bool
/= :: TransientBudget -> TransientBudget -> Bool
Eq, Int -> TransientBudget -> ShowS
[TransientBudget] -> ShowS
TransientBudget -> String
(Int -> TransientBudget -> ShowS)
-> (TransientBudget -> String)
-> ([TransientBudget] -> ShowS)
-> Show TransientBudget
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> TransientBudget -> ShowS
showsPrec :: Int -> TransientBudget -> ShowS
$cshow :: TransientBudget -> String
show :: TransientBudget -> String
$cshowList :: [TransientBudget] -> ShowS
showList :: [TransientBudget] -> ShowS
Show)