package dev.privacyllc.period.designsystem.art

import androidx.annotation.DrawableRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import dev.privacyllc.period.designsystem.R

/**
 * The onboarding and empty-state illustrations.
 *
 * ## Why these are raster, when PRODUCT_PLAN.md §42 asks for vectors
 *
 * §42's preference list ends *"avoid **unnecessary** raster imagery"*, and it
 * offers polished placeholder vectors as the fallback for artwork that does not
 * exist yet — which is what used to be here. The artwork now exists: eight
 * illustrations supplied by the project owner, in a matched light and dark pair.
 *
 * They are gradient landscapes with soft glow and depth. There is no honest
 * `VectorDrawable` of one; converting them would either lose the drawing or
 * produce a path soup larger and slower than the image. So the raster is
 * necessary rather than unnecessary, and the whole set costs 216 KB.
 *
 * [CycleProgressMark] stays a vector, because it is the one mark that is
 * *drawn from data* — its arc is the user's actual position in their cycle.
 *
 * ## How the theme swap works
 *
 * There is no `isSystemInDarkTheme()` branch here on purpose. Each drawable has
 * a `drawable/` and a `drawable-night/` copy, and Android resolves it. That
 * means the dark art also follows a device-level theme change with no
 * recomposition of ours, and a screenshot test of either theme picks the right
 * one for free.
 *
 * ## Sources
 *
 * `docs/design/dist/` holds the delivered set at full resolution, with a README
 * recording the decisions behind them — no baked text, no step numbers, and a
 * forecast illustration that deliberately names no fields. Re-read it before
 * regenerating any of these.
 */

/** Step 1. Overlapping rings over a dawn landscape — the cycle, before it means anything specific. */
@Composable
fun WelcomeIllustration(
    modifier: Modifier = Modifier,
    size: Dp = IllustrationDefaults.Size,
) = Illustration(R.drawable.art_welcome, "Overlapping circles above a sunrise", modifier, size)

/** Step 2. A cycle ring with one marked day — the first day being recorded. */
@Composable
fun LastPeriodIllustration(
    modifier: Modifier = Modifier,
    size: Dp = IllustrationDefaults.Size,
) = Illustration(R.drawable.art_last_period, "A cycle ring with one marked day", modifier, size)

/** Step 3. The same ring with a span between two marked days — a period with a start and an end. */
@Composable
fun PeriodEndIllustration(
    modifier: Modifier = Modifier,
    size: Dp = IllustrationDefaults.Size,
) = Illustration(R.drawable.art_period_end, "A cycle ring with a marked span between two days", modifier, size)

/**
 * Step 4, and the Insights empty state.
 *
 * Earlier cycles fading behind the current one — §42's "points gradually
 * converging into a pattern", which is the honest picture of what the engine
 * does with history. Used in two places, which is why it carries no step number.
 */
@Composable
fun LearningIllustration(
    modifier: Modifier = Modifier,
    size: Dp = IllustrationDefaults.Size,
) = Illustration(R.drawable.art_learning, "Earlier cycle rings fading behind the current one", modifier, size)

/**
 * Step 5, the privacy promise.
 *
 * A shield with the cycle ring inside it. Putting the cycle *inside* the shield
 * is the whole sentence the screen is making, and enclosure reads as protection
 * without reaching for a padlock — which would make a calm product look like a
 * security one.
 */
@Composable
fun PrivacyIllustration(
    modifier: Modifier = Modifier,
    size: Dp = IllustrationDefaults.Size,
) = Illustration(R.drawable.art_privacy, "A shield containing a cycle ring", modifier, size)

/** Step 6. A notification with a shield on it — what a reminder shows, and what it withholds. */
@Composable
fun NotificationPrivacyIllustration(
    modifier: Modifier = Modifier,
    size: Dp = IllustrationDefaults.Size,
) = Illustration(R.drawable.art_notification_privacy, "A notification card marked with a shield", modifier, size)

/**
 * Step 7, the first forecast.
 *
 * A calendar and a cycle arc running from logged days into dashed predicted
 * ones. It deliberately names no fields: a drawing that said "fertile window"
 * or "confidence: low" would contradict the live forecast beside it, which on a
 * first run declines to estimate fertility at all.
 */
@Composable
fun ForecastIllustration(
    modifier: Modifier = Modifier,
    size: Dp = IllustrationDefaults.Size,
) = Illustration(R.drawable.art_forecast, "A calendar with a cycle arc continuing into predicted days", modifier, size)

/**
 * The empty state — no periods logged yet.
 *
 * The ring is empty because nothing has been recorded, not because something
 * failed. It is the same ring the other illustrations fill with cycle days,
 * which is what makes this read as *waiting* rather than *broken*.
 */
@Composable
fun EmptyStateIllustration(
    modifier: Modifier = Modifier,
    size: Dp = IllustrationDefaults.Size,
) = Illustration(R.drawable.art_empty_state, "An empty cycle ring above a sunrise", modifier, size)

/**
 * One drawing, sized by height and clipped to a rounded corner.
 *
 * **Height rather than a square box**: the set does not share one aspect ratio,
 * and forcing a square would letterbox some and crop others. Each illustration
 * keeps its own proportions and every screen agrees on how tall the artwork is,
 * which is the dimension that decides whether the button below it stays on
 * screen.
 *
 * **Clipped because the corners are painted in.** Each drawing is composed as a
 * card with its own rounded corner, so the pixels outside that curve are the
 * card's own backdrop — near-black in the dark set, near-white in the light one.
 * Drawn unclipped they appear as four notches against the app's background,
 * which is obvious the moment you look at a device and invisible in code review.
 * Clipping slightly inside the painted curve removes them, and what is left
 * reads as a deliberate rounded card rather than a pasted rectangle.
 */
@Composable
private fun Illustration(
    @DrawableRes id: Int,
    description: String,
    modifier: Modifier,
    size: Dp,
) {
    Image(
        painter = painterResource(id),
        contentDescription = description,
        modifier = modifier
            .height(size)
            .clip(RoundedCornerShape(IllustrationDefaults.CornerRadius)),
        contentScale = ContentScale.FillHeight,
    )
}

object IllustrationDefaults {
    val Size: Dp = 160.dp

    /**
     * Slightly wider than the curve painted into the artwork, so the clip lands
     * inside it and no corner of the source card's backdrop survives.
     */
    val CornerRadius: Dp = 18.dp
}
