"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import {
  RESIDENCE_TYPE,
  type BilingualAddress,
  type JapanPostAddress,
  type ResidenceType,
} from "@customer-portal/domain/address";
import { DEFAULT_ADDRESS } from "@/features/address/utils";
import { useAddressCompletion } from "./useAddressCompletion";

/**
 * Type for partial initial values that allows undefined residenceType.
 */
type InitialValues = Omit<BilingualAddress, "residenceType"> & {
  residenceType?: ResidenceType | undefined;
};

/**
 * Internal form state type where residenceType can be empty string.
 */
type InternalFormState = Omit<BilingualAddress, "residenceType"> & {
  residenceType: ResidenceType | "";
};

interface UseJapanAddressFormOptions {
  /** Initial address values */
  initialValues?: Partial<InitialValues> | undefined;
  /** Callback when address changes */
  onChange?: ((address: BilingualAddress, isComplete: boolean) => void) | undefined;
  /** Field-level errors */
  errors?: Partial<Record<keyof BilingualAddress, string | undefined>> | undefined;
  /** Fields that have been touched */
  touched?: Partial<Record<keyof BilingualAddress, boolean | undefined>> | undefined;
  /** Whether the form is disabled */
  disabled?: boolean | undefined;
}

/**
 * Comprehensive hook for managing Japan address form state.
 * Consolidates all state, handlers, and refs for the form.
 */
export function useJapanAddressForm({
  initialValues,
  onChange,
  errors = {},
  touched = {},
}: UseJapanAddressFormOptions) {
  const [address, setAddress] = useState<InternalFormState>(() => ({
    ...DEFAULT_ADDRESS,
    ...initialValues,
    residenceType: initialValues?.residenceType ?? DEFAULT_ADDRESS.residenceType,
  }));

  const [isAddressVerified, setIsAddressVerified] = useState(false);
  const [verifiedZipCode, setVerifiedZipCode] = useState<string>("");
  const [showSuccess, setShowSuccess] = useState(false);

  const onChangeRef = useRef(onChange);
  onChangeRef.current = onChange;

  const streetAddressRef = useRef<HTMLInputElement>(null);
  const focusTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const hasInitializedRef = useRef(false);

  // Completion calculation
  const completion = useAddressCompletion({ address, isAddressVerified });

  // Only apply initialValues on first mount to avoid resetting user edits
  useEffect(() => {
    if (initialValues && !hasInitializedRef.current) {
      hasInitializedRef.current = true;
      setAddress(prev => ({
        ...prev,
        ...initialValues,
        residenceType: initialValues.residenceType ?? prev.residenceType,
      }));
      if (initialValues.prefecture && initialValues.city && initialValues.town) {
        setIsAddressVerified(true);
        setVerifiedZipCode(initialValues.postcode || "");
      }
    }
  }, [initialValues]);

  // Cleanup timeout on unmount
  useEffect(() => {
    return () => {
      if (focusTimeoutRef.current) {
        clearTimeout(focusTimeoutRef.current);
      }
    };
  }, []);

  // Notify parent of changes
  useEffect(() => {
    if (completion.hasResidenceType) {
      onChangeRef.current?.(address as BilingualAddress, completion.isComplete);
    } else {
      onChangeRef.current?.(address as BilingualAddress, false);
    }
  }, [address, completion.hasResidenceType, completion.isComplete]);

  // Manage success animation separately
  useEffect(() => {
    setShowSuccess(completion.isComplete);
  }, [completion.isComplete]);

  const getError = useCallback(
    (field: keyof BilingualAddress): string | undefined => {
      return touched[field] ? errors[field] : undefined;
    },
    [errors, touched]
  );

  const handleZipChange = useCallback(
    (value: string) => {
      const normalizedNew = value.replace(/-/g, "");
      const normalizedVerified = verifiedZipCode.replace(/-/g, "");
      const shouldReset = normalizedNew !== normalizedVerified;

      if (shouldReset) {
        setIsAddressVerified(false);
        setShowSuccess(false);
        setAddress(prev => ({
          ...prev,
          postcode: value,
          prefecture: "",
          prefectureJa: "",
          city: "",
          cityJa: "",
          town: "",
          townJa: "",
          buildingName: prev.buildingName,
          roomNumber: prev.roomNumber,
          residenceType: prev.residenceType,
        }));
      } else {
        setAddress(prev => ({ ...prev, postcode: value }));
      }
    },
    [verifiedZipCode]
  );

  const handleAddressFound = useCallback((found: JapanPostAddress) => {
    setAddress(prev => {
      setIsAddressVerified(true);
      setVerifiedZipCode(prev.postcode);
      return {
        ...prev,
        prefecture: found.prefectureRoma,
        city: found.cityRoma,
        town: found.townRoma,
        prefectureJa: found.prefecture,
        cityJa: found.city,
        townJa: found.town,
      };
    });

    // Focus street address input after lookup
    if (focusTimeoutRef.current) {
      clearTimeout(focusTimeoutRef.current);
    }
    focusTimeoutRef.current = setTimeout(() => {
      streetAddressRef.current?.focus();
      focusTimeoutRef.current = null;
    }, 300);
  }, []);

  const handleLookupComplete = useCallback((found: boolean) => {
    if (!found) {
      setIsAddressVerified(false);
      setAddress(prev => ({
        ...prev,
        prefecture: "",
        prefectureJa: "",
        city: "",
        cityJa: "",
        town: "",
        townJa: "",
      }));
    }
  }, []);

  const handleResidenceTypeChange = useCallback((type: ResidenceType) => {
    setAddress(prev => ({
      ...prev,
      residenceType: type,
      roomNumber: type === RESIDENCE_TYPE.HOUSE ? "" : prev.roomNumber,
    }));
  }, []);

  const handleStreetAddressChange = useCallback((value: string) => {
    setAddress(prev => ({ ...prev, streetAddress: value }));
  }, []);

  const handleBuildingNameChange = useCallback((value: string) => {
    setAddress(prev => ({ ...prev, buildingName: value }));
  }, []);

  const handleRoomNumberChange = useCallback((value: string) => {
    setAddress(prev => ({ ...prev, roomNumber: value }));
  }, []);

  return {
    /** Current address state */
    address,
    /** Whether the address has been verified via ZIP lookup */
    isAddressVerified,
    /** Whether to show success state */
    showSuccess,
    /** Completion state including current step */
    completion,
    /** Ref for street address input (for auto-focus) */
    streetAddressRef,
    /** Get error for a field if touched */
    getError,
    /** Whether the residence type is apartment */
    isApartment: address.residenceType === RESIDENCE_TYPE.APARTMENT,
    /** Handlers */
    handlers: {
      handleZipChange,
      handleAddressFound,
      handleLookupComplete,
      handleResidenceTypeChange,
      handleStreetAddressChange,
      handleBuildingNameChange,
      handleRoomNumberChange,
    },
  };
}
