// src/hooks/useProfileAddress.ts
import { useState, useEffect, useCallback } from 'react';
import toast from 'react-hot-toast';
import type { Address, UserProfile } from '../types';
import { useUserAddressQuery } from './queries/useUserAddressQuery';
import { useGeocodeMutation } from './mutations/useGeocodeMutation';
import { logger } from '../services/logger.client';
import { useDebounce } from './useDebounce';
import { notifyError } from '../services/notificationService';

/**
 * Helper to generate a consistent address string for geocoding.
 */
const getAddressString = (address: Partial<Address>): string => {
  return [
    address.address_line_1,
    address.city,
    address.province_state,
    address.postal_code,
    address.country,
  ]
    .filter(Boolean)
    .join(', ');
};

/**
 * A custom hook to manage a user's profile address, including fetching,
 * updating, and automatic/manual geocoding.
 *
 * Refactored to use TanStack Query (ADR-0005 Phase 7).
 *
 * @param userProfile The user's profile object.
 * @param isOpen Whether the parent component (e.g., a modal) is open. This is used to reset state.
 * @returns An object with address state and handler functions.
 */
export const useProfileAddress = (userProfile: UserProfile | null, isOpen: boolean) => {
  const [address, setAddress] = useState<Partial<Address>>({});
  const [initialAddress, setInitialAddress] = useState<Partial<Address>>({});

  // TanStack Query for fetching the address
  const {
    data: fetchedAddress,
    isLoading: isFetchingAddress,
    error: addressError,
  } = useUserAddressQuery(userProfile?.address_id, isOpen && !!userProfile?.address_id);

  // TanStack Query mutation for geocoding
  const geocodeMutation = useGeocodeMutation();

  // Effect to handle address fetch errors
  useEffect(() => {
    if (addressError) {
      notifyError(addressError.message || 'Failed to fetch address');
    }
  }, [addressError]);

  // Effect to sync fetched address to local state
  useEffect(() => {
    if (!isOpen || !userProfile) {
      logger.debug(
        '[useProfileAddress] Modal is closed or profile is null. Resetting address state.',
      );
      setAddress({});
      setInitialAddress({});
      return;
    }

    if (fetchedAddress) {
      logger.debug('[useProfileAddress] Successfully fetched address:', fetchedAddress);
      setAddress(fetchedAddress);
      setInitialAddress(fetchedAddress);
    } else if (!userProfile.address_id) {
      logger.debug('[useProfileAddress] Profile has no address_id. Resetting address form.');
      setAddress({});
      setInitialAddress({});
    } else if (!isFetchingAddress && !fetchedAddress && userProfile.address_id) {
      // Fetch completed but returned null - log a warning
      logger.warn(
        `[useProfileAddress] Fetch returned null for addressId: ${userProfile.address_id}.`,
      );
    }
  }, [isOpen, userProfile, fetchedAddress, isFetchingAddress]);

  const handleAddressChange = useCallback((field: keyof Address, value: string) => {
    setAddress((prev) => ({ ...prev, [field]: value }));
  }, []);

  const handleManualGeocode = useCallback(async () => {
    const addressString = getAddressString(address);

    if (!addressString) {
      toast.error('Please fill in the address fields before geocoding.');
      return;
    }

    logger.debug(`[useProfileAddress] Manual geocode triggering for: ${addressString}`);
    try {
      const result = await geocodeMutation.mutateAsync(addressString);
      if (result) {
        const { lat, lng } = result;
        setAddress((prev) => ({ ...prev, latitude: lat, longitude: lng }));
        toast.success('Address re-geocoded successfully!');
      }
    } catch (error) {
      // Error is already logged by the mutation, but we could show a toast here if needed
      logger.error('[useProfileAddress] Manual geocode failed:', error);
    }
  }, [address, geocodeMutation]);

  // --- Automatic Geocoding Logic ---
  const debouncedAddress = useDebounce(address, 1500);

  useEffect(() => {
    const handleAutoGeocode = async () => {
      logger.debug('[useProfileAddress] Auto-geocode effect triggered by debouncedAddress change');

      if (JSON.stringify(debouncedAddress) === JSON.stringify(initialAddress)) {
        logger.debug(
          '[useProfileAddress] Skipping auto-geocode: address is unchanged from initial load.',
        );
        return;
      }

      const addressString = getAddressString(debouncedAddress);

      // Don't geocode an empty address or if we already have coordinates.
      if (!addressString || (debouncedAddress.latitude && debouncedAddress.longitude)) {
        logger.debug(
          '[useProfileAddress] Skipping auto-geocode: empty string or coordinates already exist',
          { hasString: !!addressString, hasCoords: !!debouncedAddress.latitude },
        );
        return;
      }

      logger.debug(`[useProfileAddress] Auto-geocoding: "${addressString}"`);
      try {
        const result = await geocodeMutation.mutateAsync(addressString);
        if (result) {
          logger.debug('[useProfileAddress] Auto-geocode API returned result:', result);
          const { lat, lng } = result;
          setAddress((prev) => ({ ...prev, latitude: lat, longitude: lng }));
          toast.success('Address geocoded successfully!');
        }
      } catch (error) {
        // Error handling - auto-geocode failures are logged but don't block the user
        logger.warn('[useProfileAddress] Auto-geocode failed:', error);
      }
    };

    handleAutoGeocode();
  }, [debouncedAddress, initialAddress, geocodeMutation]);

  return {
    address,
    initialAddress,
    isGeocoding: geocodeMutation.isPending,
    isFetchingAddress,
    handleAddressChange,
    handleManualGeocode,
  };
};
