// Copyright (C) 2026 Jason M. Schwefel. All Rights Reserved.
package com.coldboreballisticsllc.scopedope.ui.screens.tutorial

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.coldboreballisticsllc.scopedope.ui.components.ActionButton
import com.coldboreballisticsllc.scopedope.ui.theme.*

private const val TOTAL_STEPS = 9

@Composable
fun TutorialScreen(
    onDone:    () -> Unit,
    onSkipAll: (() -> Unit)? = null,
) {
    var step by rememberSaveable { mutableStateOf(0) }

    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(ColorBackground)
            .systemBarsPadding(),
    ) {
        when (step) {
            0 -> SlideOverview        (onNext = { step++ })
            1 -> SlideAmmo            (onNext = { step++ })
            2 -> SlideDope            (onNext = { step++ })
            3 -> SlideRifleSetup      (onNext = { step++ })
            4 -> SlideDistances       (onNext = { step++ })
            5 -> SlideCalculate       (onNext = { step++ })
            6 -> SlideResults         (onNext = { step++ })
            7 -> SlidePrint           (onNext = { step++ })
            8 -> SlideConditions      (onNext = onDone, nextLabel = "Done")
        }

        // Step dots
        Row(
            modifier              = Modifier
                .align(Alignment.TopCenter)
                .padding(top = 16.dp),
            horizontalArrangement = Arrangement.spacedBy(8.dp),
            verticalAlignment     = Alignment.CenterVertically,
        ) {
            repeat(TOTAL_STEPS) { i ->
                Box(
                    modifier = Modifier
                        .size(if (i == step) 10.dp else 6.dp)
                        .background(
                            color = if (i == step) ColorAmber else ColorBorder,
                            shape = CircleShape,
                        )
                )
            }
        }

        // Skip — calls onSkipAll (exit onboarding) when provided, otherwise onDone (finish tutorial)
        TextButton(
            onClick  = onSkipAll ?: onDone,
            modifier = Modifier
                .align(Alignment.TopEnd)
                .padding(top = 4.dp, end = 4.dp),
        ) {
            Text(
                text  = if (onSkipAll != null) "Skip to app" else "Skip",
                color = ColorAmberDim,
                style = MaterialTheme.typography.labelMedium,
            )
        }
    }
}

// ── Slide layout helper ───────────────────────────────────────────────────────

@Composable
private fun Slide(
    title:     String,
    onNext:    () -> Unit,
    nextLabel: String = "Next",
    content:   @Composable ColumnScope.() -> Unit,
) {
    Column(
        modifier            = Modifier
            .fillMaxSize()
            .verticalScroll(rememberScrollState())
            .padding(horizontal = 24.dp),
        verticalArrangement = Arrangement.spacedBy(12.dp),
    ) {
        Spacer(Modifier.height(52.dp))
        Text(title, style = MaterialTheme.typography.titleLarge, color = ColorTextPrimary)
        content()
        Spacer(Modifier.height(8.dp))
        ActionButton(text = nextLabel, onClick = onNext, modifier = Modifier.fillMaxWidth())
        Spacer(Modifier.height(24.dp))
    }
}

// ── Content atom helpers ──────────────────────────────────────────────────────

@Composable
private fun Body(text: String) {
    Text(text, style = MaterialTheme.typography.bodyMedium, color = ColorTextMuted)
}

@Composable
private fun Callout(text: String) {
    Surface(
        color   = ColorSurface,
        shape   = MaterialTheme.shapes.small,
        modifier = Modifier.fillMaxWidth(),
    ) {
        Text(
            text     = text,
            style    = MaterialTheme.typography.bodyMedium,
            color    = ColorAmber,
            modifier = Modifier.padding(12.dp),
        )
    }
}

@Composable
private fun Step(label: String, detail: String) {
    Row(
        modifier              = Modifier.fillMaxWidth(),
        horizontalArrangement = Arrangement.spacedBy(12.dp),
        verticalAlignment     = Alignment.Top,
    ) {
        Text(
            text     = label,
            style    = MaterialTheme.typography.labelMedium.copy(fontWeight = FontWeight.Bold),
            color    = ColorAmber,
            modifier = Modifier.width(60.dp),
        )
        Text(
            text     = detail,
            style    = MaterialTheme.typography.bodyMedium,
            color    = ColorTextMuted,
            modifier = Modifier.weight(1f),
        )
    }
}

@Composable
private fun Todo(text: String) {
    Surface(
        color    = ColorSurface2,
        shape    = MaterialTheme.shapes.small,
        modifier = Modifier.fillMaxWidth(),
    ) {
        Row(
            Modifier.padding(12.dp),
            horizontalArrangement = Arrangement.spacedBy(8.dp),
            verticalAlignment     = Alignment.Top,
        ) {
            Text("⚙", style = MaterialTheme.typography.bodyMedium, color = ColorAmberDim)
            Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
                Text("In Development", style = MaterialTheme.typography.labelSmall, color = ColorAmberDim)
                Text(text, style = MaterialTheme.typography.bodyMedium, color = ColorTextMuted)
            }
        }
    }
}

// ── Slides ────────────────────────────────────────────────────────────────────

@Composable
private fun SlideOverview(onNext: () -> Unit) {
    Slide(title = "How ScopeDOPE Works", onNext = onNext) {
        Body(
            "Most ballistic calculators run pure physics — they predict where a bullet should land " +
            "based on manufacturer specs. ScopeDOPE does something different."
        )
        Body(
            "You enter your confirmed impacts — actual corrections you used at real distances. " +
            "ScopeDOPE blends those impacts with atmospheric physics to produce corrections that " +
            "reflect how YOUR specific rifle, ammo, and scope actually behave."
        )
        Callout("The result is a scope label you can trust because it's built from YOUR data, not just the tables.")
        Body("This tutorial walks through each step of the workflow.")
    }
}

@Composable
private fun SlideAmmo(onNext: () -> Unit) {
    Slide(title = "Select Your Ammo", onNext = onNext) {
        Body(
            "ScopeDOPE includes a built-in database of factory loads with G1 and G7 ballistic " +
            "coefficients. Search by name or filter by caliber chip to find your load."
        )
        Body("Tap any entry to select it as your active ammo.")
        Spacer(Modifier.height(4.dp))
        Step("＋", "Tap the + button in the top corner to add a completely custom ammo entry.")
        Spacer(Modifier.height(4.dp))
        Step("⋮", "Tap the ⋮ (more) button on any built-in entry and choose \"Copy to My Ammo\" " +
                  "to duplicate it as a starting point for your own tweaked values — velocity, BC, or both.")
        Spacer(Modifier.height(4.dp))
        Callout("Your custom entries appear in amber in the list so you can tell them apart at a glance.")
        Body("Custom entries can be edited or deleted at any time via their ⋮ menu.")
    }
}

@Composable
private fun SlideDope(onNext: () -> Unit) {
    Slide(title = "Entering Your DOPE", onNext = onNext) {
        Body(
            "DOPE stands for Data On Previous Engagements. These are your verified impacts from " +
            "real range sessions — confirmed distances and the scope adjustment you actually used " +
            "to get on target."
        )
        Body("For each confirmed impact, enter:")
        Step("1", "Distance in yards")
        Step("2", "The dial adjustment you used (in MIL or MOA — set in Settings)")
        Spacer(Modifier.height(8.dp))
        Body("Entering the adjustment sign:")
        Step("+", "Tap the +/- button so the + is green — you dialed UP to get on target. This is the most common case beyond your zero distance.")
        Step("-", "Tap the +/- button so the - is red — you dialed DOWN to get on target. This happens at distances shorter than your zero, or with subsonic loads.")
        Spacer(Modifier.height(4.dp))
        Callout(
            "ScopeDOPE needs at least 3 confirmed impacts to build your ballistic curve. " +
            "Three points are the minimum to model how your rifle actually behaves."
        )
        Body(
            "The more entries you have, the more accurate your corrections become. " +
            "Span your data across your full engagement range — a 100 yd and a 500 yd point " +
            "constrain the curve far better than five points clustered at 100 yd."
        )
        Body("DOPE entries can be removed with the trash icon, or the toggle in Settings disables them entirely for pure physics mode.")
    }
}

@Composable
private fun SlideRifleSetup(onNext: () -> Unit) {
    Slide(title = "Rifle Setup", onNext = onNext) {
        Body("Two values anchor the trajectory calculation:")
        Spacer(Modifier.height(4.dp))
        Step(
            "Zero",
            "The distance at which your rifle is currently zeroed. When you select ammo, " +
            "ScopeDOPE automatically sets this to 50 yd for rimfire calibers and 100 yd for " +
            "everything else. Change it to match your actual zero."
        )
        Spacer(Modifier.height(4.dp))
        Step(
            "Height",
            "Scope height above bore centerline in inches. Most rifle scope setups fall " +
            "between 1.5\" and 2.0\". This primarily affects holdover at close range."
        )
        Spacer(Modifier.height(4.dp))
        Body("These fields are on the main DOPE screen below the ammo panel.")
    }
}

@Composable
private fun SlideDistances(onNext: () -> Unit) {
    Slide(title = "Output Distances", onNext = onNext) {
        Body(
            "Output distances are the ranges you want corrections calculated for. " +
            "They are completely independent from your DOPE entry distances."
        )
        Body("Two presets cover the most common competition formats:")
        Step("NRL22", "Short-range rimfire: 25, 50, 75, 100 yd")
        Step("PRS",   "Long-range gas gun: 200–1000 yd in 100 yd increments")
        Spacer(Modifier.height(4.dp))
        Body("Or type any distance manually and tap +. Tap any distance chip to remove it.")
        Callout("The number of output distances is unlimited — but your scope label can only fit as many entries as the active label format allows.")
    }
}

@Composable
private fun SlideCalculate(onNext: () -> Unit) {
    Slide(title = "Real-Time Calculations", onNext = onNext) {
        Body("Calculations update automatically as you enter data — no button to tap. The engine:")
        Step("1", "Runs a G1/G7 trajectory through the drag model")
        Step("2", "Corrects your BC for current atmospheric conditions (altitude, temp, pressure)")
        Step("3", "If you have DOPE entries, blends the physics result with your confirmed impacts " +
                  "to produce bias-corrected corrections")
        Spacer(Modifier.height(4.dp))
        Callout(
            "Use Real DOPE Data is ON by default. Toggle it off in Settings to run pure physics only — " +
            "useful for comparing what the tables predict against what your rifle actually does."
        )
        Body("Results appear on the Calculations tab as soon as ammo and output distances are set.")
    }
}

@Composable
private fun SlideResults(onNext: () -> Unit) {
    Slide(title = "Calculations & Label Selection", onNext = onNext) {
        Body("The Calculations tab shows a correction table for each output distance.")
        Body("Each row includes:")
        Step("Elev", "Elevation adjustment — dial this much up. Positive = up, negative = down.")
        Step("Wind", "Windage correction based on wind speed and angle from the Conditions tab.")
        Step("Clks", "Elevation in clicks (elevation ÷ click value, rounded)")
        Spacer(Modifier.height(4.dp))
        Body(
            "Check the box next to each entry you want on your scope label. The active label " +
            "format caps how many can be selected — the 50mm circle format holds up to 8. " +
            "Checking a new entry when you're at the limit automatically unchecks the first one."
        )
        Callout("Choose distances that span your real engagement range without wasting label space on ranges you don't shoot.")
    }
}

@Composable
private fun SlidePrint(onNext: () -> Unit) {
    Slide(title = "Print & Export", onNext = onNext) {
        Body("The Print tab is where you get your scope label out of the app.")
        Spacer(Modifier.height(4.dp))
        Step(
            "PNG",
            "Tap \"Save as PNG\" to save your label to your device's Photos library at 400×400 px. " +
            "Print this on a 50mm × 50mm label from any inkjet or laser printer, or use it digitally."
        )
        Spacer(Modifier.height(4.dp))
        Step(
            "BLE",
            "Direct wireless printing to the Niimbot B1 thermal label printer. Tap Connect on the " +
            "Print screen to pair via Bluetooth, then Print to send the label directly to the printer. " +
            "No computer, no app, no cable."
        )
        Spacer(Modifier.height(4.dp))
        Callout("Labels are always printed in black and white. Color coding only appears on-screen.")
        Todo("Label format selector (rectangular format) — coming in a future update.")
    }
}

@Composable
private fun SlideConditions(onNext: () -> Unit, nextLabel: String) {
    Slide(title = "Conditions & Wind", onNext = onNext, nextLabel = nextLabel) {
        Body(
            "Atmospheric conditions affect air density, which affects drag. At long range, " +
            "the difference between sea level and 5,000 ft can shift your point of impact " +
            "by several inches."
        )
        Body("Enter these on the Conditions tab:")
        Step("Alt",  "Altitude in feet — most significant factor at range")
        Step("Temp", "Temperature in °F — warmer air is thinner")
        Step("Pres", "Barometric pressure in hPa")
        Step("Hum",  "Humidity % — minor effect, included for completeness")
        Step("Wind", "Speed in mph and angle relative to you (90° = full crosswind from the right)")
        Spacer(Modifier.height(4.dp))
        Callout("Wind direction is always entered manually — a sensor can measure speed, but only you know which way it's blowing relative to your firing line.")
        Todo(
            "BTMETER BT-100APP Bluetooth anemometer integration — automatically populates wind " +
            "speed and temperature from a connected sensor. Pending device delivery and BLE protocol analysis."
        )
    }
}
