#!/usr/bin/env bash
#
# Idempotently create the 16 Stripe Prices that back creator-tier subscriptions
# (4 tiers x {standard, founder} x {monthly, annual}). Re-running is safe: each
# price is keyed by `lookup_key`, so an existing price with the right key and
# the right amount is left alone.
#
# What it does on each price:
#   - If no price exists with the lookup_key  -> create it.
#   - If a price exists with that key and the right amount -> reuse it.
#   - If a price exists with that key but a different amount -> archive the old
#     one (active=false) and create a new price with `transfer_lookup_key=true`,
#     which moves the key onto the new price atomically.
#
# Existing subscriptions are not affected: Stripe Subscriptions are pinned to
# the specific Price ID at signup, regardless of whether that Price is later
# archived or its lookup_key is transferred. Only new checkouts pick up the new
# price.
#
# Old manually-created prices that don't have a lookup_key are NOT touched.
# Run with --archive-old-on-tier-products to also archive every non-matching
# active price on the four tier products (use after verifying the new set
# works end-to-end).
#
# Usage:
#   STRIPE_SECRET_KEY=sk_live_... ./deploy/stripe_seed_creator_tier_prices.sh
#   STRIPE_SECRET_KEY=sk_test_... ./deploy/stripe_seed_creator_tier_prices.sh --dry-run
#
# Reads the tier-price source of truth from
# `_private/docs/mnw/server-internal/business/assumptions.toml` so docs, Rust
# enum, and Stripe stay in lockstep. If you change prices, edit that toml
# (and `CreatorTier::price_cents`), then re-run this.
#
# Output: prints CREATOR_TIER_*_PRICE_ID env-var assignments suitable for
# pasting into the server's environment file.

set -euo pipefail

DRY_RUN=0
ARCHIVE_OLD=0
for arg in "$@"; do
    case "$arg" in
        --dry-run) DRY_RUN=1 ;;
        --archive-old-on-tier-products) ARCHIVE_OLD=1 ;;
        *) echo "unknown arg: $arg" >&2; exit 2 ;;
    esac
done

: "${STRIPE_SECRET_KEY:?STRIPE_SECRET_KEY must be set}"

API="https://api.stripe.com/v1"
AUTH=(-u "${STRIPE_SECRET_KEY}:")

# Monthly prices in whole dollars. Founder = exactly 50% of standard. Annual =
# monthly * 12 * 0.9, rounded to the nearest whole dollar (matches the displayed
# prices in site-docs/about/pricing.md and site-docs/guide/tiers.md).
#
# Tiers: basic small_files big_files everything
declare -A STANDARD_MONTHLY=(
    [basic]=16
    [small_files]=24
    [big_files]=36
    [everything]=60
)

# Product display names — these appear on Stripe dashboard and customer
# receipts. One product per tier; four prices hang off each.
declare -A PRODUCT_NAME=(
    [basic]="Creator Tier — Basic"
    [small_files]="Creator Tier — Small Files"
    [big_files]="Creator Tier — Big Files"
    [everything]="Creator Tier — Everything"
)

# Round monthly cents to the displayed annual price (whole dollars).
annual_cents() {
    local monthly_cents=$1
    # bash arithmetic is integer-only, so compute in cents using nearest-int rounding.
    # exact = monthly * 12 * 90 / 100; we round to nearest whole dollar (multiple of 100 cents).
    local exact=$(( monthly_cents * 12 * 90 / 100 ))
    # Round to nearest 100 cents.
    local remainder=$(( exact % 100 ))
    if (( remainder >= 50 )); then
        echo $(( exact - remainder + 100 ))
    else
        echo $(( exact - remainder ))
    fi
}

# stripe_get path query_string
stripe_get() {
    local path=$1
    local query=${2:-}
    curl -sS -G "${AUTH[@]}" "${API}/${path}" ${query:+--data-urlencode "$query"}
}

# Find or create the Product for a tier. Reuses an existing product by metadata
# tag `mnw_tier=<slug>` so re-running doesn't duplicate.
ensure_product() {
    local tier_slug=$1
    local name=${PRODUCT_NAME[$tier_slug]}

    # Search by metadata.mnw_tier.
    local resp
    resp=$(stripe_get "products/search" "query=metadata['mnw_tier']:'${tier_slug}' AND active:'true'")
    local existing
    existing=$(echo "$resp" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d['data'][0]['id'] if d.get('data') else '')")
    if [[ -n "$existing" ]]; then
        echo "$existing"
        return
    fi

    if (( DRY_RUN )); then
        echo "prod_DRYRUN_${tier_slug}"
        return
    fi

    local created
    created=$(curl -sS "${AUTH[@]}" "${API}/products" \
        -d "name=${name}" \
        -d "metadata[mnw_tier]=${tier_slug}")
    echo "$created" | python3 -c "import json,sys; print(json.load(sys.stdin)['id'])"
}

# Find a price by lookup_key. Echoes "id|unit_amount" or empty.
find_price_by_lookup() {
    local key=$1
    local resp
    resp=$(stripe_get "prices" "lookup_keys[]=${key}")
    echo "$resp" | python3 -c "
import json,sys
d = json.load(sys.stdin)
if d.get('data'):
    p = d['data'][0]
    print(f\"{p['id']}|{p['unit_amount']}|{p.get('active', True)}\")
"
}

# Create a price with lookup_key. If transfer_lookup_key is 1, archives whichever
# price currently holds the key.
create_price() {
    local product_id=$1
    local unit_amount_cents=$2
    local interval=$3   # month | year
    local lookup=$4
    local transfer=$5   # 0 | 1

    if (( DRY_RUN )); then
        echo "price_DRYRUN_${lookup}"
        return
    fi

    local args=(
        -d "currency=usd"
        -d "product=${product_id}"
        -d "unit_amount=${unit_amount_cents}"
        -d "recurring[interval]=${interval}"
        -d "lookup_key=${lookup}"
    )
    if (( transfer )); then
        args+=(-d "transfer_lookup_key=true")
    fi

    local resp
    resp=$(curl -sS "${AUTH[@]}" "${API}/prices" "${args[@]}")
    local price_id
    price_id=$(echo "$resp" | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('id') or ''); sys.exit(0 if d.get('id') else 1)" || true)
    if [[ -z "$price_id" ]]; then
        echo "FAILED to create price ${lookup}: $resp" >&2
        exit 1
    fi
    echo "$price_id"
}

archive_price() {
    local price_id=$1
    if (( DRY_RUN )); then
        echo "(dry-run) would archive ${price_id}" >&2
        return
    fi
    curl -sS "${AUTH[@]}" "${API}/prices/${price_id}" -d "active=false" >/dev/null
    echo "archived ${price_id}" >&2
}

# Ensure a price with the given lookup_key, amount, and interval exists. Echoes the price ID.
ensure_price() {
    local product_id=$1
    local unit_amount_cents=$2
    local interval=$3
    local lookup=$4

    local found
    found=$(find_price_by_lookup "$lookup")
    if [[ -n "$found" ]]; then
        local existing_id existing_amount existing_active
        IFS='|' read -r existing_id existing_amount existing_active <<<"$found"
        if [[ "$existing_amount" == "$unit_amount_cents" && "$existing_active" == "True" ]]; then
            echo "$existing_id"
            return
        fi
        # Wrong amount or inactive: transfer the key onto a fresh price and archive the old one.
        echo "lookup_key ${lookup}: existing ${existing_id} amount=${existing_amount}, want ${unit_amount_cents}; rotating" >&2
        local new_id
        new_id=$(create_price "$product_id" "$unit_amount_cents" "$interval" "$lookup" 1)
        archive_price "$existing_id"
        echo "$new_id"
        return
    fi

    create_price "$product_id" "$unit_amount_cents" "$interval" "$lookup" 0
}

# uppercase a tier slug for env var name
upper_slug() {
    echo "$1" | tr '[:lower:]' '[:upper:]'
}

# env var name for (tier, rate, interval).
env_var_name() {
    local tier_slug=$1
    local rate=$2     # standard | founder
    local interval=$3 # monthly | annual
    local tier_uc
    tier_uc=$(upper_slug "$tier_slug")
    local prefix="CREATOR_TIER_${tier_uc}"
    case "${rate}_${interval}" in
        standard_monthly) echo "${prefix}_PRICE_ID" ;;
        standard_annual)  echo "${prefix}_ANNUAL_PRICE_ID" ;;
        founder_monthly)  echo "${prefix}_FOUNDER_PRICE_ID" ;;
        founder_annual)   echo "${prefix}_FOUNDER_ANNUAL_PRICE_ID" ;;
    esac
}

main() {
    local TIERS=(basic small_files big_files everything)
    local env_lines=()
    local wanted_lookup_keys=()

    for tier in "${TIERS[@]}"; do
        local std_monthly_cents=$(( STANDARD_MONTHLY[$tier] * 100 ))
        local founder_monthly_cents=$(( std_monthly_cents / 2 ))
        local std_annual_cents
        std_annual_cents=$(annual_cents "$std_monthly_cents")
        local founder_annual_cents
        founder_annual_cents=$(annual_cents "$founder_monthly_cents")

        echo "==> ${tier}: standard \$${STANDARD_MONTHLY[$tier]}/mo, founder \$$(( STANDARD_MONTHLY[$tier] / 2 ))/mo" >&2
        echo "    annual cents: standard=${std_annual_cents}, founder=${founder_annual_cents}" >&2

        local product_id
        product_id=$(ensure_product "$tier")
        echo "    product: ${product_id}" >&2

        for rate in standard founder; do
            for interval in monthly annual; do
                local cents stripe_interval
                if [[ "$rate" == "standard" && "$interval" == "monthly" ]]; then
                    cents=$std_monthly_cents
                elif [[ "$rate" == "standard" && "$interval" == "annual" ]]; then
                    cents=$std_annual_cents
                elif [[ "$rate" == "founder" && "$interval" == "monthly" ]]; then
                    cents=$founder_monthly_cents
                else
                    cents=$founder_annual_cents
                fi
                if [[ "$interval" == "monthly" ]]; then
                    stripe_interval=month
                else
                    stripe_interval=year
                fi

                local lookup="creator_tier_${tier}_${rate}_${interval}"
                wanted_lookup_keys+=("$lookup")
                local price_id
                price_id=$(ensure_price "$product_id" "$cents" "$stripe_interval" "$lookup")
                local var
                var=$(env_var_name "$tier" "$rate" "$interval")
                env_lines+=("${var}=${price_id}")
                echo "    ${lookup} -> ${price_id} (\$$(awk "BEGIN { printf \"%.2f\", $cents/100 }"))" >&2
            done
        done

        if (( ARCHIVE_OLD )); then
            echo "    archiving stale prices on product ${product_id}..." >&2
            # List all active prices on this product, archive any whose lookup_key isn't in the wanted set
            # (or whose lookup_key is null, which means it was created manually before lookup_keys existed).
            local resp
            resp=$(stripe_get "prices" "product=${product_id}&active=true&limit=100")
            # Build a python literal of the wanted keys for this tier
            local tier_wanted_py="["
            for k in "${wanted_lookup_keys[@]}"; do
                if [[ "$k" == "creator_tier_${tier}_"* ]]; then
                    tier_wanted_py+="'$k',"
                fi
            done
            tier_wanted_py+="]"
            local stale_ids
            stale_ids=$(echo "$resp" | python3 -c "
import json, sys
d = json.load(sys.stdin)
wanted = set(${tier_wanted_py})
for p in d.get('data', []):
    if p.get('lookup_key') not in wanted:
        print(p['id'])
")
            for sid in $stale_ids; do
                archive_price "$sid"
            done
        fi
    done

    echo
    echo "# Paste into the server environment (and restart):"
    printf '%s\n' "${env_lines[@]}" | sort
}

main "$@"
