import { describe, it, expect, expectTypeOf } from "vitest";
import type {
  CheckoutRecommendedAddress,
  CheckoutAddressValidationResult,
  CheckoutAddress,
  AddressFormData,
} from "./types";

describe("CheckoutAddress type", () => {
  it("accepts a fully populated UK address", () => {
    const addr: CheckoutAddress = {
      id: "abc123",
      type: "shipping",
      fullName: "Alice Smith",
      firstName: "Alice",
      lastName: "Smith",
      phone: "+447911123456",
      addressLine1: "10 Downing Street",
      additionalInformation: "Flat 4B",
      city: "London",
      postalCode: "SW1A 2AA",
      country: "GB",
      isDefault: true,
      isValidated: false,
    };
    expect(addr.id).toBe("abc123");
    expect(addr.isValidated).toBe(false);
  });

  it("accepts minimal address (optional fields omitted)", () => {
    const addr: CheckoutAddress = {
      id: "xyz789",
      type: "billing",
      fullName: "Bob Jones",
      firstName: "Bob",
      lastName: "Jones",
      phone: "+447911999888",
      addressLine1: "221B Baker Street",
      city: "London",
      postalCode: "NW1 6XE",
      country: "GB",
      isDefault: false,
      isValidated: true,
    };
    expect(addr.additionalInformation).toBeUndefined();
  });

  it("firstName and lastName are required strings (not optional)", () => {
    expectTypeOf<CheckoutAddress["firstName"]>().toEqualTypeOf<string>();
    expectTypeOf<CheckoutAddress["lastName"]>().toEqualTypeOf<string>();
  });

  it("does not have state or addressLine2 fields", () => {
    type Keys = keyof CheckoutAddress;
    expectTypeOf<"state" extends Keys ? true : false>().toEqualTypeOf<false>();
    expectTypeOf<"addressLine2" extends Keys ? true : false>().toEqualTypeOf<false>();
  });

  it("has additionalInformation as optional string", () => {
    expectTypeOf<CheckoutAddress["additionalInformation"]>().toEqualTypeOf<
      string | undefined
    >();
  });

  it("has isValidated as required boolean (not optional)", () => {
    expectTypeOf<CheckoutAddress["isValidated"]>().toEqualTypeOf<boolean>();
  });

  it("type is restricted to shipping or billing", () => {
    expectTypeOf<CheckoutAddress["type"]>().toEqualTypeOf<"shipping" | "billing">();
  });
});

describe("CheckoutAddressValidationResult type", () => {
  it("accepts a valid result without recommended address", () => {
    const result: CheckoutAddressValidationResult = {
      isValid: true,
      validationValue: "valid",
      reasons: [],
      addressType: "unknown",
      changedAttributes: [],
      originalAddress: {
        addressLine1: "10 Downing Street",
        city: "London",
        postalCode: "SW1A 2AA",
        country: "GB",
      },
    };
    expect(result.isValid).toBe(true);
    expect(result.recommendedAddress).toBeUndefined();
  });

  it("accepts a result with recommended address", () => {
    const recommended: CheckoutRecommendedAddress = {
      addressLine1: "10 Downing Street",
      city: "London",
      postalCode: "SW1A 2AA",
      country: "GB",
      confidenceScore: "high",
      confidenceCode: "postal_data_match",
      confidenceDescription: "Matched via postal data",
    };

    const result: CheckoutAddressValidationResult = {
      isValid: false,
      validationValue: "partially_valid",
      reasons: [{ code: "street_name", description: "Street name corrected" }],
      addressType: "unknown",
      changedAttributes: ["addressLine1", "postalCode"],
      recommendedAddress: recommended,
      originalAddress: {
        addressLine1: "10 Downing St",
        city: "London",
        postalCode: "SW1A2AA",
        country: "GB",
      },
    };
    expect(result.recommendedAddress).toBeDefined();
    expect(result.changedAttributes).toContain("postalCode");
  });

  it("originalAddress does not have state or addressLine2", () => {
    type OrigKeys = keyof CheckoutAddressValidationResult["originalAddress"];
    expectTypeOf<"state" extends OrigKeys ? true : false>().toEqualTypeOf<false>();
    expectTypeOf<"addressLine2" extends OrigKeys ? true : false>().toEqualTypeOf<false>();
  });

  it("originalAddress has additionalInformation as optional", () => {
    const result: CheckoutAddressValidationResult = {
      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");
  });

  it("validationValue is restricted to valid | partially_valid | invalid", () => {
    expectTypeOf<CheckoutAddressValidationResult["validationValue"]>().toEqualTypeOf<
      "valid" | "partially_valid" | "invalid"
    >();
  });

  it("addressType covers all Shippo address types", () => {
    expectTypeOf<CheckoutAddressValidationResult["addressType"]>().toEqualTypeOf<
      "residential" | "commercial" | "unknown" | "po_box" | "military"
    >();
  });
});

describe("CheckoutRecommendedAddress type", () => {
  it("confidenceScore is restricted to high | medium | low", () => {
    expectTypeOf<CheckoutRecommendedAddress["confidenceScore"]>().toEqualTypeOf<
      "high" | "medium" | "low"
    >();
  });

  it("does not have state or addressLine2 fields", () => {
    type Keys = keyof CheckoutRecommendedAddress;
    expectTypeOf<"state" extends Keys ? true : false>().toEqualTypeOf<false>();
    expectTypeOf<"addressLine2" extends Keys ? true : false>().toEqualTypeOf<false>();
  });

  it("additionalInformation and completeAddress are optional", () => {
    const addr: CheckoutRecommendedAddress = {
      addressLine1: "10 Downing Street",
      city: "London",
      postalCode: "SW1A 2AA",
      country: "GB",
      confidenceScore: "medium",
      confidenceCode: "match",
      confidenceDescription: "Matched",
    };
    expect(addr.additionalInformation).toBeUndefined();
    expect(addr.completeAddress).toBeUndefined();
  });
});

describe("AddressFormData type", () => {
  it("accepts a fully populated UK form data object", () => {
    const data: AddressFormData = {
      firstName: "Alice",
      lastName: "Smith",
      phone: "7911123456",
      addressLine1: "10 Downing Street",
      additionalInformation: "Flat 4B",
      city: "London",
      postalCode: "SW1A 2AA",
      country: "GB",
    };
    expect(data.firstName).toBe("Alice");
    expect(data.additionalInformation).toBe("Flat 4B");
  });

  it("accepts minimal form data (optional fields omitted)", () => {
    const data: AddressFormData = {
      firstName: "Bob",
      lastName: "Jones",
      phone: "7911999888",
      addressLine1: "221B Baker Street",
      city: "London",
      postalCode: "NW1 6XE",
      country: "GB",
    };
    expect(data.additionalInformation).toBeUndefined();
  });

  it("firstName and lastName are required strings", () => {
    expectTypeOf<AddressFormData["firstName"]>().toEqualTypeOf<string>();
    expectTypeOf<AddressFormData["lastName"]>().toEqualTypeOf<string>();
  });

  it("does not have fullName, state, or addressLine2", () => {
    type Keys = keyof AddressFormData;
    expectTypeOf<"fullName" extends Keys ? true : false>().toEqualTypeOf<false>();
    expectTypeOf<"state" extends Keys ? true : false>().toEqualTypeOf<false>();
    expectTypeOf<"addressLine2" extends Keys ? true : false>().toEqualTypeOf<false>();
  });

  it("additionalInformation is optional string", () => {
    expectTypeOf<AddressFormData["additionalInformation"]>().toEqualTypeOf<
      string | undefined
    >();
  });

  it("does not include id, type, isDefault, or isValidated", () => {
    type Keys = keyof AddressFormData;
    expectTypeOf<"id" extends Keys ? true : false>().toEqualTypeOf<false>();
    expectTypeOf<"type" extends Keys ? true : false>().toEqualTypeOf<false>();
    expectTypeOf<"isDefault" extends Keys ? true : false>().toEqualTypeOf<false>();
    expectTypeOf<"isValidated" extends Keys ? true : false>().toEqualTypeOf<false>();
  });
});
