/**
 * Phase 5 — Integration wiring tests.
 *
 * Verifies the checkout step constants, barrel exports, type contracts,
 * and step-label configuration after wiring OrderReviewStep into the
 * checkout flow and removing the "shipping-method" step.
 */
import { describe, it, expect, expectTypeOf } from "vitest";
import type { CheckoutStep } from "./constants";
import { CHECKOUT_STEPS, CHECKOUT_PATH, CHECKOUT_SUCCESS_PATH } from "./constants";
import type {
  CheckoutSelectedShippingRate,
  CheckoutShippingRateResult,
  CheckoutValidationResult,
  CheckoutAddress,
} from "./types";

// ─── Checkout Step Sequence ──────────────────────────────────────────────────

describe("CHECKOUT_STEPS (Phase 5 integration)", () => {
  it("contains exactly 4 steps in the correct order", () => {
    expect(CHECKOUT_STEPS).toEqual([
      "validation",
      "shipping-address",
      "review",
      "payment",
    ]);
  });

  it("does not contain 'shipping-method'", () => {
    expect(CHECKOUT_STEPS).not.toContain("shipping-method");
  });

  it("'review' sits between 'shipping-address' and 'payment'", () => {
    const reviewIndex = CHECKOUT_STEPS.indexOf("review");
    const addressIndex = CHECKOUT_STEPS.indexOf("shipping-address");
    const paymentIndex = CHECKOUT_STEPS.indexOf("payment");
    expect(reviewIndex).toBeGreaterThan(addressIndex);
    expect(reviewIndex).toBeLessThan(paymentIndex);
  });

  it("'validation' is the first step", () => {
    expect(CHECKOUT_STEPS[0]).toBe("validation");
  });

  it("'payment' is the last step", () => {
    expect(CHECKOUT_STEPS[CHECKOUT_STEPS.length - 1]).toBe("payment");
  });

  it("CHECKOUT_PATH and CHECKOUT_SUCCESS_PATH are defined", () => {
    expect(CHECKOUT_PATH).toBe("/checkout");
    expect(CHECKOUT_SUCCESS_PATH).toBe("/checkout/success");
  });
});

// ─── CheckoutStep Type ───────────────────────────────────────────────────────

describe("CheckoutStep type (Phase 5)", () => {
  it("includes 'review' as a valid step", () => {
    const step: CheckoutStep = "review";
    expect(step).toBe("review");
  });

  it("includes all four expected steps", () => {
    const steps: CheckoutStep[] = ["validation", "shipping-address", "review", "payment"];
    expect(steps).toHaveLength(4);
    steps.forEach((s) => expect(CHECKOUT_STEPS).toContain(s));
  });

  it("does not allow 'shipping-method' as a type literal", () => {
    type IsValid = "shipping-method" extends CheckoutStep ? true : false;
    expectTypeOf<IsValid>().toEqualTypeOf<false>();
  });
});

// ─── Barrel Exports ──────────────────────────────────────────────────────────

describe("Barrel exports (Phase 5)", () => {
  it("re-exports useShippingRate hook", async () => {
    const mod = await import("./index");
    expect(mod.useShippingRate).toBeDefined();
    expect(typeof mod.useShippingRate).toBe("function");
  });

  it("re-exports CHECKOUT_STEPS constant", async () => {
    const mod = await import("./index");
    expect(mod.CHECKOUT_STEPS).toBeDefined();
    expect(mod.CHECKOUT_STEPS).toEqual(CHECKOUT_STEPS);
  });
});

// ─── Shipping Rate Type Contracts ────────────────────────────────────────────

describe("CheckoutSelectedShippingRate type contract", () => {
  const sampleRate: CheckoutSelectedShippingRate = {
    provider: "DPD UK",
    serviceName: "Next Day",
    serviceToken: "dpd_uk_next_day",
    amount: 5.5,
    currency: "GBP",
    estimatedDays: 1,
    durationTerms: "1-2 business days",
    carrierAccount: "ca_abc123",
  };

  it("has all required fields populated", () => {
    expect(sampleRate.provider).toBe("DPD UK");
    expect(sampleRate.serviceName).toBe("Next Day");
    expect(sampleRate.serviceToken).toBe("dpd_uk_next_day");
    expect(sampleRate.amount).toBe(5.5);
    expect(sampleRate.currency).toBe("GBP");
    expect(sampleRate.estimatedDays).toBe(1);
    expect(sampleRate.durationTerms).toBe("1-2 business days");
    expect(sampleRate.carrierAccount).toBe("ca_abc123");
  });

  it("amount is number (not string)", () => {
    expectTypeOf<CheckoutSelectedShippingRate["amount"]>().toEqualTypeOf<number>();
  });

  it("estimatedDays is number", () => {
    expectTypeOf<CheckoutSelectedShippingRate["estimatedDays"]>().toEqualTypeOf<number>();
  });

  it("all fields are required strings or number (no optional fields)", () => {
    expectTypeOf<CheckoutSelectedShippingRate["provider"]>().toEqualTypeOf<string>();
    expectTypeOf<CheckoutSelectedShippingRate["serviceName"]>().toEqualTypeOf<string>();
    expectTypeOf<CheckoutSelectedShippingRate["serviceToken"]>().toEqualTypeOf<string>();
    expectTypeOf<CheckoutSelectedShippingRate["currency"]>().toEqualTypeOf<string>();
    expectTypeOf<CheckoutSelectedShippingRate["durationTerms"]>().toEqualTypeOf<string>();
    expectTypeOf<CheckoutSelectedShippingRate["carrierAccount"]>().toEqualTypeOf<string>();
  });
});

describe("CheckoutShippingRateResult type contract", () => {
  const sampleResult: CheckoutShippingRateResult = {
    shipmentObjectId: "shp_test_123",
    selectedRate: {
      provider: "UPS",
      serviceName: "Standard",
      serviceToken: "ups_standard",
      amount: 7.99,
      currency: "GBP",
      estimatedDays: 3,
      durationTerms: "3-5 business days",
      carrierAccount: "ca_ups",
    },
    alternativeRates: [
      {
        provider: "Evri UK",
        serviceName: "Economy",
        serviceToken: "evri_economy",
        amount: 3.99,
        currency: "GBP",
        estimatedDays: 5,
        durationTerms: "5-7 business days",
        carrierAccount: "ca_evri",
      },
    ],
    cartSubtotal: 4998,
    shippingTotal: 7.99,
    orderTotal: 5005.99,
  };

  it("includes shipmentObjectId as a string", () => {
    expect(sampleResult.shipmentObjectId).toBe("shp_test_123");
    expectTypeOf<CheckoutShippingRateResult["shipmentObjectId"]>().toEqualTypeOf<string>();
  });

  it("selectedRate is a full CheckoutSelectedShippingRate", () => {
    expect(sampleResult.selectedRate.provider).toBe("UPS");
    expect(sampleResult.selectedRate.amount).toBe(7.99);
  });

  it("alternativeRates is an array of CheckoutSelectedShippingRate", () => {
    expect(sampleResult.alternativeRates).toHaveLength(1);
    expect(sampleResult.alternativeRates[0].provider).toBe("Evri UK");
    expectTypeOf<CheckoutShippingRateResult["alternativeRates"]>().toEqualTypeOf<
      CheckoutSelectedShippingRate[]
    >();
  });

  it("totals are numeric", () => {
    expectTypeOf<CheckoutShippingRateResult["cartSubtotal"]>().toEqualTypeOf<number>();
    expectTypeOf<CheckoutShippingRateResult["shippingTotal"]>().toEqualTypeOf<number>();
    expectTypeOf<CheckoutShippingRateResult["orderTotal"]>().toEqualTypeOf<number>();
  });

  it("orderTotal logically equals cartSubtotal + shippingTotal (application invariant)", () => {
    expect(sampleResult.orderTotal).toBeCloseTo(
      sampleResult.cartSubtotal + sampleResult.shippingTotal,
      2,
    );
  });
});

// ─── OrderReviewStep Props Contract ──────────────────────────────────────────

describe("OrderReviewStep props contract", () => {
  it("onProceed callback receives shipmentObjectId and selectedRate", () => {
    type OnProceedFn = (
      shipmentObjectId: string,
      shippingRate: CheckoutSelectedShippingRate,
    ) => void;

    const mockOnProceed: OnProceedFn = (shipmentId, rate) => {
      expect(typeof shipmentId).toBe("string");
      expect(typeof rate.provider).toBe("string");
      expect(typeof rate.amount).toBe("number");
    };

    mockOnProceed("shp_abc", {
      provider: "DPD UK",
      serviceName: "Next Day",
      serviceToken: "dpd_uk_next_day",
      amount: 5.5,
      currency: "GBP",
      estimatedDays: 1,
      durationTerms: "1-2 business days",
      carrierAccount: "ca_123",
    });
  });

  it("requires addressId, addresses, cartResult, sessionId, onProceed, onBack", () => {
    type ReviewStepProps = {
      addressId: string;
      addresses: CheckoutAddress[];
      cartResult: CheckoutValidationResult;
      sessionId: string | undefined;
      onProceed: (
        shipmentObjectId: string,
        shippingRate: CheckoutSelectedShippingRate,
      ) => void;
      onBack: () => void;
    };

    const props: ReviewStepProps = {
      addressId: "addr_123",
      addresses: [],
      cartResult: { valid: true, items: [], issues: [], subtotal: 0 },
      sessionId: undefined,
      onProceed: () => {},
      onBack: () => {},
    };

    expect(props.addressId).toBe("addr_123");
    expect(typeof props.onProceed).toBe("function");
    expect(typeof props.onBack).toBe("function");
  });
});

// ─── Step Navigation Logic ───────────────────────────────────────────────────

describe("Step navigation logic (Phase 5)", () => {
  it("shipping-address → review transition is valid", () => {
    const from: CheckoutStep = "shipping-address";
    const to: CheckoutStep = "review";
    const fromIdx = CHECKOUT_STEPS.indexOf(from);
    const toIdx = CHECKOUT_STEPS.indexOf(to);
    expect(toIdx).toBe(fromIdx + 1);
  });

  it("review → payment transition is valid", () => {
    const from: CheckoutStep = "review";
    const to: CheckoutStep = "payment";
    const fromIdx = CHECKOUT_STEPS.indexOf(from);
    const toIdx = CHECKOUT_STEPS.indexOf(to);
    expect(toIdx).toBe(fromIdx + 1);
  });

  it("review → shipping-address back navigation is valid", () => {
    const from: CheckoutStep = "review";
    const to: CheckoutStep = "shipping-address";
    const fromIdx = CHECKOUT_STEPS.indexOf(from);
    const toIdx = CHECKOUT_STEPS.indexOf(to);
    expect(toIdx).toBe(fromIdx - 1);
  });

  it("step indices are contiguous from 0 to length-1", () => {
    CHECKOUT_STEPS.forEach((step, i) => {
      expect(CHECKOUT_STEPS.indexOf(step)).toBe(i);
    });
  });
});
