import { describe, it, expect, expectTypeOf } from "vitest";
import type {
  ShippoConfidenceScore,
  ShippoValidationValue,
  ShippoAddressType,
  ShippoValidationReason,
  RecommendedAddress,
  AddressValidationResult,
} from "./checkout";

describe("AddressValidationResult types", () => {
  it("ShippoConfidenceScore accepts valid literals", () => {
    expectTypeOf<"high">().toMatchTypeOf<ShippoConfidenceScore>();
    expectTypeOf<"medium">().toMatchTypeOf<ShippoConfidenceScore>();
    expectTypeOf<"low">().toMatchTypeOf<ShippoConfidenceScore>();
  });

  it("ShippoValidationValue accepts valid literals", () => {
    expectTypeOf<"valid">().toMatchTypeOf<ShippoValidationValue>();
    expectTypeOf<"partially_valid">().toMatchTypeOf<ShippoValidationValue>();
    expectTypeOf<"invalid">().toMatchTypeOf<ShippoValidationValue>();
  });

  it("ShippoAddressType accepts valid literals", () => {
    expectTypeOf<"residential">().toMatchTypeOf<ShippoAddressType>();
    expectTypeOf<"commercial">().toMatchTypeOf<ShippoAddressType>();
    expectTypeOf<"unknown">().toMatchTypeOf<ShippoAddressType>();
    expectTypeOf<"po_box">().toMatchTypeOf<ShippoAddressType>();
    expectTypeOf<"military">().toMatchTypeOf<ShippoAddressType>();
  });

  it("ShippoValidationReason has code and description", () => {
    expectTypeOf<ShippoValidationReason>().toHaveProperty("code");
    expectTypeOf<ShippoValidationReason>().toHaveProperty("description");
  });

  it("RecommendedAddress has required fields and no state", () => {
    expectTypeOf<RecommendedAddress>().toHaveProperty("addressLine1");
    expectTypeOf<RecommendedAddress>().toHaveProperty("city");
    expectTypeOf<RecommendedAddress>().toHaveProperty("postalCode");
    expectTypeOf<RecommendedAddress>().toHaveProperty("country");
    expectTypeOf<RecommendedAddress>().toHaveProperty("confidenceScore");
    expectTypeOf<RecommendedAddress>().toHaveProperty("confidenceCode");
    expectTypeOf<RecommendedAddress>().toHaveProperty("confidenceDescription");

    type Keys = keyof RecommendedAddress;
    expectTypeOf<"state" extends Keys ? true : false>().toEqualTypeOf<false>();
    expectTypeOf<"addressLine2" extends Keys ? true : false>().toEqualTypeOf<false>();
  });

  it("AddressValidationResult is structurally complete", () => {
    expectTypeOf<AddressValidationResult>().toHaveProperty("isValid");
    expectTypeOf<AddressValidationResult>().toHaveProperty("validationValue");
    expectTypeOf<AddressValidationResult>().toHaveProperty("reasons");
    expectTypeOf<AddressValidationResult>().toHaveProperty("addressType");
    expectTypeOf<AddressValidationResult>().toHaveProperty("changedAttributes");
    expectTypeOf<AddressValidationResult>().toHaveProperty("originalAddress");
  });

  it("recommendedAddress is optional on AddressValidationResult", () => {
    const withoutRecommended: AddressValidationResult = {
      isValid: true,
      validationValue: "valid",
      reasons: [],
      addressType: "unknown",
      changedAttributes: [],
      originalAddress: {
        addressLine1: "10 Downing Street",
        city: "London",
        postalCode: "SW1A 2AA",
        country: "GB",
      },
    };
    expect(withoutRecommended.recommendedAddress).toBeUndefined();
  });

  it("AddressValidationResult accepts a full object with recommended address", () => {
    const full: AddressValidationResult = {
      isValid: false,
      validationValue: "partially_valid",
      reasons: [{ code: "postal_data_match", description: "Postal code matched" }],
      addressType: "unknown",
      changedAttributes: ["postalCode"],
      recommendedAddress: {
        addressLine1: "10 Downing Street",
        city: "London",
        postalCode: "SW1A 2AA",
        country: "GB",
        completeAddress: "10 Downing Street;LONDON;SW1A 2AA;UNITED KINGDOM",
        confidenceScore: "high",
        confidenceCode: "postal_data_match",
        confidenceDescription: "Matched via postal data",
      },
      originalAddress: {
        addressLine1: "10 Downing St",
        city: "London",
        postalCode: "SW1A2AA",
        country: "GB",
      },
    };
    expect(full.isValid).toBe(false);
    expect(full.recommendedAddress).toBeDefined();
    expect(full.recommendedAddress!.confidenceScore).toBe("high");
  });

  it("originalAddress uses additionalInformation instead of addressLine2", () => {
    const result: AddressValidationResult = {
      isValid: true,
      validationValue: "valid",
      reasons: [],
      addressType: "unknown",
      changedAttributes: [],
      originalAddress: {
        addressLine1: "10 Downing Street",
        additionalInformation: "Flat 1",
        city: "London",
        postalCode: "SW1A 2AA",
        country: "GB",
      },
    };
    expect(result.originalAddress.additionalInformation).toBe("Flat 1");

    type OrigKeys = keyof AddressValidationResult["originalAddress"];
    expectTypeOf<"state" extends OrigKeys ? true : false>().toEqualTypeOf<false>();
    expectTypeOf<"addressLine2" extends OrigKeys ? true : false>().toEqualTypeOf<false>();
  });
});
