"use client";

/**
 * AddressStepJapan - Integration adapter for JapanAddressForm
 *
 * Maps JapanAddressForm data to the existing address format used by
 * SignupForm, AddressCard, and other address consumers.
 *
 * WHMCS Field Mapping (English):
 * - address1 = buildingName + roomNumber (for apartments)
 * - address2 = town (romanized street/block)
 * - city = city (romanized)
 * - state = prefecture (romanized)
 * - postcode = ZIP code
 * - country = "JP"
 *
 * Japanese fields are stored separately for Salesforce sync.
 */

import { useCallback, useEffect, useMemo, useRef } from "react";
import { JapanAddressForm, type JapanAddressFormData } from "./JapanAddressForm";
import {
  type BilingualAddress,
  RESIDENCE_TYPE,
  prepareWhmcsAddressFields,
  type ResidenceType,
} from "@customer-portal/domain/address";

/**
 * Partial form data type that allows undefined residenceType
 * for cases where user hasn't selected yet
 */
type PartialJapanAddressFormData = Omit<JapanAddressFormData, "residenceType"> & {
  residenceType?: ResidenceType | undefined;
};

// ============================================================================
// Types
// ============================================================================

/**
 * Legacy address data format used by existing forms
 * Maps to WHMCS address fields
 */
interface LegacyAddressData {
  address1: string;
  address2: string;
  city: string;
  state: string;
  postcode: string;
  country: string;
  countryCode?: string | undefined;
}

/**
 * Form interface expected by SignupForm and similar consumers
 */
interface FormInterface {
  values: { address: LegacyAddressData };
  errors: Record<string, string | undefined>;
  touched: Record<string, boolean | undefined>;
  setValue: (field: string, value: unknown) => void;
  setTouchedField: (field: string) => void;
}

interface AddressStepJapanProps {
  form: FormInterface;
  /**
   * Called when Japanese address data changes.
   * Use this to capture Japanese fields for Salesforce sync.
   */
  onJapaneseAddressChange?: (data: BilingualAddress) => void;
}

// ============================================================================
// Helpers
// ============================================================================

/**
 * Convert JapanAddressFormData to legacy address format for WHMCS
 */
function toWhmcsFormat(data: JapanAddressFormData): LegacyAddressData {
  const whmcsFields = prepareWhmcsAddressFields(data);

  return {
    address1: whmcsFields.address1 || "",
    address2: whmcsFields.address2 || "",
    city: whmcsFields.city || "",
    state: whmcsFields.state || "",
    postcode: whmcsFields.postcode || "",
    country: "JP",
    countryCode: "JP",
  };
}

/**
 * Convert legacy address format to JapanAddressFormData
 * Used for initializing form from existing data
 */
function fromLegacyFormat(address: LegacyAddressData): PartialJapanAddressFormData {
  // Try to parse address1 into building name and room number
  // Format: "BuildingName RoomNumber" or just "BuildingName"
  const address1Parts = (address.address1 || "").trim();
  const lastSpaceIndex = address1Parts.lastIndexOf(" ");

  let buildingName = address1Parts;
  let roomNumber = "";

  // If there's a space and the last part looks like a room number (e.g., "201", "1F", etc.)
  if (lastSpaceIndex > 0) {
    const potentialRoom = address1Parts.slice(lastSpaceIndex + 1);
    if (/^[0-9A-Z]+$/i.test(potentialRoom) && potentialRoom.length <= 10) {
      buildingName = address1Parts.slice(0, lastSpaceIndex);
      roomNumber = potentialRoom;
    }
  }

  // Only set residence type if there's existing address data
  // For new users, leave it undefined so they must explicitly choose
  const hasExistingAddress = address.postcode || address.state || address.city;
  const residenceType = hasExistingAddress
    ? roomNumber
      ? RESIDENCE_TYPE.APARTMENT
      : RESIDENCE_TYPE.HOUSE
    : undefined;

  return {
    postcode: address.postcode || "",
    prefecture: address.state || "",
    city: address.city || "",
    town: address.address2 || "",
    streetAddress: "",
    buildingName: buildingName || "",
    roomNumber: roomNumber || "",
    residenceType,
    // Japanese fields are not available from legacy format
    prefectureJa: "",
    cityJa: "",
    townJa: "",
  };
}

// ============================================================================
// Component
// ============================================================================

export function AddressStepJapan({ form, onJapaneseAddressChange }: AddressStepJapanProps) {
  const { values, errors, touched, setValue, setTouchedField } = form;
  const address = values.address;

  // Track if this is the first render to avoid infinite loops
  const isInitialMount = useRef(true);

  // Compute initial values only once on mount
  const initialValues = useMemo((): PartialJapanAddressFormData => {
    const base: PartialJapanAddressFormData = {
      postcode: address.postcode || "",
      prefecture: address.state || "",
      city: address.city || "",
      town: address.address2 || "",
      streetAddress: "",
      buildingName: "",
      roomNumber: "",
      residenceType: undefined,
      prefectureJa: "",
      cityJa: "",
      townJa: "",
    };
    return {
      ...base,
      ...fromLegacyFormat(address),
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []); // Only compute on mount

  // Extract address field errors
  const getError = (field: string): string | undefined => {
    const key = `address.${field}`;
    return touched[key] || touched["address"] ? (errors[key] ?? errors[field]) : undefined;
  };

  // Map Japan address field names to legacy field names for error display
  const japanFieldErrors: Partial<Record<keyof JapanAddressFormData, string | undefined>> = {
    postcode: getError("postcode"),
    prefecture: getError("state"),
    city: getError("city"),
    town: getError("address2"),
    buildingName: getError("address1"),
    roomNumber: getError("address1"),
  };

  // Map touched fields
  const japanFieldTouched: Partial<Record<keyof JapanAddressFormData, boolean | undefined>> = {
    postcode: touched["address.postcode"] || touched["address"],
    prefecture: touched["address.state"] || touched["address"],
    city: touched["address.city"] || touched["address"],
    town: touched["address.address2"] || touched["address"],
    buildingName: touched["address.address1"] || touched["address"],
    roomNumber: touched["address.address1"] || touched["address"],
  };

  // Handle Japan address form changes
  const handleJapanAddressChange = useCallback(
    (data: JapanAddressFormData, _isComplete: boolean) => {
      // Skip the initial mount to avoid loops
      if (isInitialMount.current) {
        isInitialMount.current = false;
        return;
      }

      // Convert to legacy format and update parent form
      const legacyAddress = toWhmcsFormat(data);
      setValue("address", legacyAddress);

      // Notify parent of Japanese address data for Salesforce
      onJapaneseAddressChange?.(data);
    },
    [setValue, onJapaneseAddressChange]
  );

  // Handle field blur - mark as touched in parent form
  const handleBlur = useCallback(
    (field: keyof JapanAddressFormData) => {
      // Map Japan field to legacy field for touched tracking
      const fieldMap: Record<string, string> = {
        postcode: "address.postcode",
        prefecture: "address.state",
        city: "address.city",
        town: "address.address2",
        buildingName: "address.address1",
        roomNumber: "address.address1",
      };

      const legacyField = fieldMap[field];
      if (legacyField) {
        setTouchedField(legacyField);
      }
    },
    [setTouchedField]
  );

  // Set Japan as default country on mount if empty
  useEffect(() => {
    if (!address.country) {
      setValue("address", { ...address, country: "JP", countryCode: "JP" });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []); // Only on mount

  return (
    <JapanAddressForm
      initialValues={initialValues}
      onChange={handleJapanAddressChange}
      errors={japanFieldErrors}
      touched={japanFieldTouched}
      onBlur={handleBlur}
    />
  );
}
