package com.dangerousthings.aliro;

import javacard.framework.APDU;
import javacard.framework.Applet;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.Util;

/**
 * Scaffold for the Aliro step-up phase (spec §8.4). Lives under
 * {@link AliroAids#STEP_UP}.
 *
 * <p>This first pass only answers SELECT with a minimal FCI and rejects
 * unknown commands cleanly. The actual step-up protocol — mdoc
 * SessionData framing (DeviceRequest/DeviceResponse CBOR with
 * Aliro-remapped integer keys per Tables 8-21/8-22), ENVELOPE/GET
 * RESPONSE command chaining, and a fresh AES-256-GCM session keyed by
 * StepUpSKDevice/StepUpSKReader derived per spec §8.4.3 — comes in
 * follow-up iterations.
 *
 * <p>When that work lands, this applet will need access to the
 * {@code StepUpSK} (a 32-byte session-bound value produced by
 * {@link AliroApplet}'s derivation in §8.3.1.13). Since Java Card
 * installs distinct instances per AID, that state will be exchanged via
 * a shared package-private holder (not yet implemented).
 */
public class StepUpApplet extends Applet {

    private static final byte CLA_PROPRIETARY = (byte) 0x80;

    public static void install(byte[] bArray, short bOffset, byte bLength) {
        StepUpApplet applet = new StepUpApplet();
        if (bArray == null || bLength == 0) {
            applet.register();
        } else {
            applet.register(bArray, (short) (bOffset + 1), bArray[bOffset]);
        }
    }

    @Override
    public boolean select() {
        return true;
    }

    @Override
    public void process(APDU apdu) {
        if (selectingApplet()) {
            sendStepUpFci(apdu);
            return;
        }

        byte[] buf = apdu.getBuffer();
        if (buf[ISO7816.OFFSET_CLA] != CLA_PROPRIETARY) {
            ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
        }

        // Until the mdoc DeviceRequest pipeline lands, every proprietary INS
        // is unrecognised. ENVELOPE + GET RESPONSE handlers plug in here.
        ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
    }

    /**
     * Minimal FCI for step-up SELECT. The spec (§10.2.1.2) allows the UD to
     * advertise supported APDU command/response sizes here; those get added
     * when we implement ENVELOPE/GET RESPONSE.
     *
     * <pre>
     * 6F L
     *   84 09 [step-up AID]
     * </pre>
     */
    private void sendStepUpFci(APDU apdu) {
        byte[] buf = apdu.getBuffer();
        short off = 0;
        buf[off++] = 0x6F;
        short outerLenPos = off++;

        buf[off++] = (byte) 0x84;
        buf[off++] = (byte) AliroAids.STEP_UP.length;
        off = Util.arrayCopyNonAtomic(AliroAids.STEP_UP, (short) 0,
                                      buf, off, (short) AliroAids.STEP_UP.length);

        buf[outerLenPos] = (byte) (off - 2);
        apdu.setOutgoingAndSend((short) 0, off);
    }
}
