import React, { useState, useEffect, useCallback } from "react";
import { Address } from "../types";
import {
  geocodingService,
  AddressComponents,
} from "../services/geocodingService";
import AddressAutocomplete from "./AddressAutocomplete";
import { PlaceDetails } from "../services/placesService";
import {
  useAddressAutocomplete,
  usStates,
} from "../hooks/useAddressAutocomplete";

interface LocationFormData {
  address1: string;
  address2: string;
  city: string;
  state: string;
  zipCode: string;
  country: string;
  latitude?: number;
  longitude?: number;
}

interface LocationFormProps {
  data: LocationFormData;
  userAddresses: Address[];
  selectedAddressId: string;
  addressesLoading: boolean;
  onChange: (
    e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>
  ) => void;
  onAddressSelect: (addressId: string) => void;
  formatAddressDisplay: (address: Address) => string;
  onCoordinatesChange?: (latitude: number, longitude: number) => void;
  onGeocodeRef?: (
    geocodeFunction: () => Promise<{
      latitude: number;
      longitude: number;
    } | null>
  ) => void;
}

const LocationForm: React.FC<LocationFormProps> = ({
  data,
  userAddresses,
  selectedAddressId,
  addressesLoading,
  onChange,
  onAddressSelect,
  formatAddressDisplay,
  onCoordinatesChange,
  onGeocodeRef,
}) => {
  const [geocoding, setGeocoding] = useState(false);
  const [geocodeError, setGeocodeError] = useState<string | null>(null);
  const [geocodeSuccess, setGeocodeSuccess] = useState(false);
  const [placesApiError, setPlacesApiError] = useState(false);

  // Debounced geocoding function
  const geocodeAddress = useCallback(
    async (
      addressData: LocationFormData
    ): Promise<{ latitude: number; longitude: number } | null> => {
      if (
        !geocodingService.isAddressComplete(addressData as AddressComponents)
      ) {
        return null;
      }

      setGeocoding(true);
      setGeocodeError(null);
      setGeocodeSuccess(false);

      try {
        const result = await geocodingService.geocodeAddress(
          addressData as AddressComponents
        );

        if ("error" in result) {
          setGeocodeError(result.details || result.error);
          return null;
        } else {
          setGeocodeSuccess(true);
          if (onCoordinatesChange) {
            onCoordinatesChange(result.latitude, result.longitude);
          }
          // Clear success message after 3 seconds
          setTimeout(() => setGeocodeSuccess(false), 3000);

          // Return the coordinates
          return { latitude: result.latitude, longitude: result.longitude };
        }
      } catch (error) {
        setGeocodeError("Failed to geocode address");
        return null;
      } finally {
        setGeocoding(false);
      }
    },
    [onCoordinatesChange]
  );

  // Expose geocoding function to parent components
  const triggerGeocoding = useCallback(async () => {
    if (data.address1 && data.city && data.state && data.zipCode) {
      const coordinates = await geocodeAddress(data);
      return coordinates; // Return coordinates directly from geocoding
    }
    return null; // Incomplete address
  }, [data, geocodeAddress]);

  // Pass geocoding function to parent component
  useEffect(() => {
    if (onGeocodeRef) {
      onGeocodeRef(triggerGeocoding);
    }
  }, [onGeocodeRef, triggerGeocoding]);

  // Use address autocomplete hook
  const { parsePlace } = useAddressAutocomplete();

  // Handle place selection from autocomplete
  const handlePlaceSelect = useCallback(
    (place: PlaceDetails) => {
      try {
        const parsedAddress = parsePlace(place);

        if (!parsedAddress) {
          setPlacesApiError(true);
          return;
        }

        // Create synthetic events to update form data
        const createSyntheticEvent = (name: string, value: string) =>
          ({
            target: {
              name,
              value,
              type: "text",
            },
          } as React.ChangeEvent<HTMLInputElement>);

        // Update all address fields
        onChange(createSyntheticEvent("address1", parsedAddress.address1));
        onChange(createSyntheticEvent("city", parsedAddress.city));
        onChange(createSyntheticEvent("state", parsedAddress.state));
        onChange(createSyntheticEvent("zipCode", parsedAddress.zipCode));
        onChange(createSyntheticEvent("country", parsedAddress.country));

        // Set coordinates immediately
        if (onCoordinatesChange) {
          onCoordinatesChange(parsedAddress.latitude, parsedAddress.longitude);
        }

        // Clear any previous geocoding messages
        setGeocodeError(null);
        setGeocodeSuccess(true);
        setPlacesApiError(false);
        setTimeout(() => setGeocodeSuccess(false), 3000);
      } catch (error) {
        console.error("Error handling place selection:", error);
        setPlacesApiError(true);
      }
    },
    [onChange, onCoordinatesChange, parsePlace]
  );

  // Handle Places API errors
  const handlePlacesApiError = useCallback(() => {
    setPlacesApiError(true);
  }, []);

  return (
    <div className="card mb-4">
      <div className="card-body">
        <div className="mb-3">
          <small className="text-muted">
            <i className="bi bi-info-circle me-2"></i>
            Your address is private. This will only be used to show renters a
            general area.
          </small>
        </div>

        {addressesLoading ? (
          <div className="text-center py-3">
            <div className="spinner-border spinner-border-sm" role="status">
              <span className="visually-hidden">Loading addresses...</span>
            </div>
          </div>
        ) : (
          <>
            {/* Multiple addresses - show dropdown */}
            {userAddresses.length > 1 && (
              <div className="mb-3">
                <label className="form-label">Select Address</label>
                <select
                  className="form-select"
                  value={selectedAddressId || "new"}
                  onChange={(e) => onAddressSelect(e.target.value)}
                >
                  <option value="new">Enter new address</option>
                  {userAddresses.map((address) => (
                    <option key={address.id} value={address.id}>
                      {formatAddressDisplay(address)}
                    </option>
                  ))}
                </select>
              </div>
            )}

            {/* Show form fields for all scenarios with addresses <= 1 or when "new" is selected */}
            {(userAddresses.length <= 1 ||
              (userAddresses.length > 1 && !selectedAddressId)) && (
              <>
                <div className="row mb-3">
                  <div className="col-md-6">
                    <div className="d-flex justify-content-between align-items-center mb-2">
                      <label htmlFor="address1" className="form-label mb-0">
                        Address Line 1 *
                      </label>
                    </div>

                    {!placesApiError ? (
                      <AddressAutocomplete
                        id="address1"
                        name="address1"
                        value={data.address1}
                        onChange={(value) => {
                          const syntheticEvent = {
                            target: {
                              name: "address1",
                              value,
                              type: "text",
                            },
                          } as React.ChangeEvent<HTMLInputElement>;
                          onChange(syntheticEvent);
                        }}
                        onPlaceSelect={handlePlaceSelect}
                        onError={handlePlacesApiError}
                        placeholder="Start typing an address..."
                        className="form-control"
                        required
                        countryRestriction="us"
                        types={["address"]}
                      />
                    ) : (
                      <input
                        type="text"
                        className="form-control"
                        id="address1"
                        name="address1"
                        value={data.address1}
                        onChange={onChange}
                        placeholder="123 Main Street"
                        required
                      />
                    )}

                    {placesApiError && (
                      <div className="text-muted small mt-1">
                        <i className="bi bi-info-circle me-1"></i>
                        Address autocomplete is unavailable. Using manual input.
                      </div>
                    )}
                  </div>
                  <div className="col-md-6">
                    <label htmlFor="address2" className="form-label">
                      Address Line 2
                    </label>
                    <input
                      type="text"
                      className="form-control"
                      id="address2"
                      name="address2"
                      value={data.address2}
                      onChange={onChange}
                      placeholder="Apt, Suite, Unit, etc."
                    />
                  </div>
                </div>

                <div className="row mb-3">
                  <div className="col-md-6">
                    <label htmlFor="city" className="form-label">
                      City *
                    </label>
                    <input
                      type="text"
                      className="form-control"
                      id="city"
                      name="city"
                      value={data.city}
                      onChange={onChange}
                      required
                    />
                  </div>
                  <div className="col-md-3">
                    <label htmlFor="state" className="form-label">
                      State *
                    </label>
                    <select
                      className="form-select"
                      id="state"
                      name="state"
                      value={data.state}
                      onChange={onChange}
                      required
                    >
                      <option value="">Select State</option>
                      {usStates.map((state) => (
                        <option key={state} value={state}>
                          {state}
                        </option>
                      ))}
                    </select>
                  </div>
                  <div className="col-md-3">
                    <label htmlFor="zipCode" className="form-label">
                      ZIP Code *
                    </label>
                    <input
                      type="text"
                      className="form-control"
                      id="zipCode"
                      name="zipCode"
                      value={data.zipCode}
                      onChange={onChange}
                      placeholder="12345"
                      required
                    />
                  </div>
                </div>
              </>
            )}
          </>
        )}
      </div>
    </div>
  );
};

export default LocationForm;
