"use client"

import type React from "react"
import { useState, useRef, useEffect, useCallback } from "react"
import {
  Box,
  Paper,
  Typography,
  Button,
  Dialog,
  DialogContent,
  DialogActions,
  InputAdornment,
  CircularProgress,
  FormControl,
  FormHelperText,
  Autocomplete,
  TextField,
} from "@mui/material"
import { Search, MyLocation } from "@mui/icons-material"
import { StyledTextField } from "@/shared/theme/css"
import { StyledDialogTitle, WhiteStyledTextField } from "@/shared/sections/rh/styles"
import { IconButton } from "@mui/material"
import FontAwesome from "../fontawesome"
import { faLocationCrosshairs, faLocationDot } from "@fortawesome/free-solid-svg-icons"
import CustomTooltip from "@/shared/components/tooltips/tooltip-custom"
import ActionButtons from "../form/buttons-action"
import { AddressData } from "@/shared/types/common"
import ConditionalComponent from "../table/ConditionalComponent"



export interface AddressMapSelectorProps {
  value?: AddressData | string
  onChange: (value: AddressData | string) => void
  name: string
  label?: string
  placeholder?: string
  required?: boolean
  error?: string
  fullWidth?: boolean
  disabled?: boolean
  isSmallScreen?: boolean
  onBlur?: (event: React.FocusEvent<HTMLInputElement | HTMLTextAreaElement>) => void
}

declare global {
  interface Window {
    google: any
    initMap: () => void
  }
}

export default function AddressMapSelector({
  value,
  onChange,
  name,
  placeholder,
  label = "Adresse",
  required = false,
  error,
  fullWidth = true,
  disabled = false,
  isSmallScreen,
  onBlur
}: AddressMapSelectorProps) {
  const apiKey = process.env.NEXT_PUBLIC_GOOGLE_MAPS_API_KEY
  const [open, setOpen] = useState(false)
  const [mapLoaded, setMapLoaded] = useState(false)
  const [searchValue, setSearchValue] = useState("")
  const [currentPosition, setCurrentPosition] = useState<{ lat: number; lng: number } | null>(null)
  const [selectedPosition, setSelectedPosition] = useState<{ lat: number; lng: number } | null>(
    typeof value === "object" && value ? { lat: value.lat, lng: value.lng } : null,
  )

  const [selectedAddress, setSelectedAddress] = useState<string>("")
  const [isSearching, setIsSearching] = useState(false)
  const [autocompleteService, setAutocompleteService] = useState<any>(null)
  const [placesService, setPlacesService] = useState<any>(null)
  const [inputValue, setInputValue] = useState("")
  const [options, setOptions] = useState<readonly any[]>([])

  const mapRef = useRef<any>(null)
  const markerRef = useRef<any>(null)
  const scriptLoadedRef = useRef(false)
  const mainInputRef = useRef<HTMLInputElement | null>(null)

  useEffect(() => {
    if (
      !window.google &&
      !document.querySelector('script[src*="maps.googleapis.com/maps/api"]') &&
      !scriptLoadedRef.current
    ) {
      scriptLoadedRef.current = true

      window.initMap = () => {
        setMapLoaded(true)
        setAutocompleteService(new window.google.maps.places.AutocompleteService())
        setPlacesService(new window.google.maps.places.PlacesService(document.createElement('div')))
      }

      const script = document.createElement("script")
      script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=places&callback=initMap`
      script.async = true
      script.defer = true
      document.head.appendChild(script)
    } else if (window.google) {
      setMapLoaded(true)
      setAutocompleteService(new window.google.maps.places.AutocompleteService())
      setPlacesService(new window.google.maps.places.PlacesService(document.createElement('div')))
    }
  }, [apiKey])

  const fetchPredictions = useCallback(
    (input: string) => {
      if (!autocompleteService || !input.trim()) {
        setOptions([])
        return
      }

      autocompleteService.getPlacePredictions(
        {
          input,
          componentRestrictions: { country: 'fr' },
          types: ['geocode']
        },
        (predictions: any[], status: string) => {
          if (status !== window.google.maps.places.PlacesServiceStatus.OK || !predictions) {
            setOptions([])
            return
          }
          setOptions(predictions)
        }
      )
    },
    [autocompleteService]
  )

  const handleInputChange = useCallback(
    (event: React.SyntheticEvent<Element, Event>, value: string, reason: string) => {
      setInputValue(value)
      if (reason === 'input') {
        fetchPredictions(value)
      }
    },
    [fetchPredictions]
  )
  const getAddressFromLatLng = useCallback(
    (lat: number, lng: number) => {
      if (!window.google) return

      const geocoder = new window.google.maps.Geocoder()
      geocoder.geocode({ location: { lat, lng } }, (results: any, status: string) => {
        if (status === "OK" && results && results[0]) {
          const newAddress = results[0].formatted_address
          setSelectedAddress(newAddress)
          setSearchValue(newAddress)
          setInputValue(newAddress)

          let city = ""
          let postalCode = ""
          let country = ""

          results[0].address_components.forEach((component: any) => {
            if (component.types.includes("locality")) {
              city = component.long_name
            }
            if (component.types.includes("postal_code")) {
              postalCode = component.long_name
            }
            if (component.types.includes("country")) {
              country = component.long_name
            }
          })

          const addressData: AddressData = {
            address: newAddress,
            lat,
            lng,
            placeId: results[0].place_id,
            formattedAddress: newAddress,
            city,
            postalCode,
            country,
          }

          onChange(addressData)
        }
      })
    },
    [onChange],
  )

  const handleOptionSelect = useCallback(
    (event: React.SyntheticEvent, value: any) => {
      if (!value || !placesService) return

      placesService.getDetails(
        { placeId: value.place_id },
        (place: any, status: string) => {
          if (status !== window.google.maps.places.PlacesServiceStatus.OK || !place.geometry) return

          const newPos = {
            lat: place.geometry.location.lat(),
            lng: place.geometry.location.lng(),
          }

          const newAddress = place.formatted_address || ""
          setSelectedPosition(newPos)
          setSelectedAddress(newAddress)
          setSearchValue(newAddress)
          setInputValue(newAddress)

          if (mapRef.current) {
            mapRef.current.setCenter(newPos)
            mapRef.current.setZoom(17)
          }

          if (markerRef.current) {
            markerRef.current.setPosition(newPos)
          }

          let city = ""
          let postalCode = ""
          let country = ""

          place.address_components?.forEach((component: any) => {
            if (component.types.includes("locality")) {
              city = component.long_name
            }
            if (component.types.includes("postal_code")) {
              postalCode = component.long_name
            }
            if (component.types.includes("country")) {
              country = component.long_name
            }
          })

          const addressData: AddressData = {
            address: newAddress,
            lat: newPos.lat,
            lng: newPos.lng,
            placeId: place.place_id,
            formattedAddress: newAddress,
            city,
            postalCode,
            country,
          }

          onChange(addressData)
        }
      )
    },
    [onChange, placesService]
  )

  const initMap = useCallback(() => {
    if (!mapLoaded || !open || !window.google) return

    const defaultPosition = { lat: 48.8566, lng: 2.3522 }
    const initialPosition = selectedPosition || currentPosition || defaultPosition

    setTimeout(() => {
      if (!document.getElementById("map")) return

      mapRef.current = new window.google.maps.Map(document.getElementById("map") as HTMLElement, {
        center: initialPosition,
        zoom: 15,
        mapTypeControl: false,
        fullscreenControl: false,
        streetViewControl: false,
      })

      markerRef.current = new window.google.maps.Marker({
        position: selectedPosition || initialPosition,
        map: mapRef.current,
        draggable: true,
        animation: window.google.maps.Animation.DROP,
      })

      window.google.maps.event.addListener(markerRef.current, "dragend", () => {
        if (markerRef.current) {
          const position = markerRef.current.getPosition()
          if (position) {
            const newPos = { lat: position.lat(), lng: position.lng() }
            setSelectedPosition(newPos)
            getAddressFromLatLng(newPos.lat, newPos.lng)
          }
        }
      })

      window.google.maps.event.addListener(mapRef.current, "click", (event: any) => {
        if (event.latLng && markerRef.current) {
          markerRef.current.setPosition(event.latLng)
          const newPos = { lat: event.latLng.lat(), lng: event.latLng.lng() }
          setSelectedPosition(newPos)
          getAddressFromLatLng(newPos.lat, newPos.lng)
        }
      })
    }, 300)
  }, [mapLoaded, open, selectedPosition, currentPosition, getAddressFromLatLng])

  

  const getCurrentLocation = useCallback(() => {
    if (navigator.geolocation) {
      setIsSearching(true)
      navigator.geolocation.getCurrentPosition(
        (position) => {
          const pos = {
            lat: position.coords.latitude,
            lng: position.coords.longitude,
          }

          setCurrentPosition(pos)
          setSelectedPosition(pos)

          if (mapRef.current) {
            mapRef.current.setCenter(pos)
            mapRef.current.setZoom(17)
          }

          if (markerRef.current) {
            markerRef.current.setPosition(pos)
          }

          getAddressFromLatLng(pos.lat, pos.lng)
          setIsSearching(false)
        },
        () => {
          setIsSearching(false)
          console.error("Erreur: La géolocalisation a échoué.")
        },
      )
    } else {
      console.error("Erreur: Votre navigateur ne supporte pas la géolocalisation.")
    }
  }, [getAddressFromLatLng])

  useEffect(() => {
    initMap()
  }, [initMap])

  useEffect(() => {
    if (typeof value === "object" && value) {
      setSelectedPosition({ lat: value.lat, lng: value.lng })
      setSelectedAddress(value.address || "")
      setSearchValue(value.address || "")
      setInputValue(value.address || "")
    } else if (typeof value === "string") {
      setSelectedAddress(value)
      setSearchValue(value)
      setInputValue(value)
    }
  }, [value])

  const handleOpen = () => {
    if (!disabled) {
      setOpen(true)
    }
  }

  const handleClose = () => {
    setOpen(false)
  }

  const handleConfirm = () => {
    if (selectedPosition && selectedAddress) {
      const geocoder = new window.google.maps.Geocoder()
      geocoder.geocode(
        { location: { lat: selectedPosition.lat, lng: selectedPosition.lng } },
        (results: any, status: string) => {
          if (status === "OK" && results && results[0]) {
            let city = ""
            let postalCode = ""
            let country = ""

            results[0].address_components.forEach((component: any) => {
              if (component.types.includes("locality")) {
                city = component.long_name
              }
              if (component.types.includes("postal_code")) {
                postalCode = component.long_name
              }
              if (component.types.includes("country")) {
                country = component.long_name
              }
            })

            const addressData: AddressData = {
              address: selectedAddress,
              lat: selectedPosition.lat,
              lng: selectedPosition.lng,
              placeId: results[0].place_id,
              formattedAddress: results[0].formatted_address,
              city,
              postalCode,
              country,
            }

            onChange(addressData)
            handleClose()
          } else {
            const addressData: AddressData = {
              address: selectedAddress,
              lat: selectedPosition.lat,
              lng: selectedPosition.lng,
            }
            onChange(addressData)
            handleClose()
          }
        },
      )
    }
  }

  const handleSearch = () => {
    if (searchValue && mapRef.current && window.google) {
      setIsSearching(true)
      const geocoder = new window.google.maps.Geocoder()
      geocoder.geocode({ address: searchValue }, (results: any, status: string) => {
        setIsSearching(false)
        if (status === "OK" && results && results[0]) {
          const location = results[0].geometry.location
          const newPos = { lat: location.lat(), lng: location.lng() }
          const newAddress = results[0].formatted_address

          setSelectedPosition(newPos)
          setSelectedAddress(newAddress)
          setSearchValue(newAddress)
          setInputValue(newAddress)

          mapRef.current?.setCenter(newPos)
          mapRef.current?.setZoom(17)

          if (markerRef.current) {
            markerRef.current.setPosition(newPos)
          }

          const addressData: AddressData = {
            address: newAddress,
            lat: newPos.lat,
            lng: newPos.lng,
            formattedAddress: newAddress,
          }
          onChange(addressData)
        }
      })
    }
  }

  return (
    <FormControl fullWidth={fullWidth} error={!!error} required={required}>
       <StyledTextField
        isSmallScreen={isSmallScreen}
        name={name}
        label={label}
        disabled={true}
        value={searchValue}
        onChange={(e) => {
          const newValue = e.target.value
          setSelectedAddress(newValue)
          setSearchValue(newValue)
          onChange(newValue)
        }}
        required={required}
        sx={{
          '& .MuiFormHelperText-root': {
            visibility: error ? 'visible' : 'hidden',
            height: error ? 'auto' : '0px'
          }
        }}
        error={!!error}
        helperText={error || ' '}
        isReadOnly={true}
        fullWidth={fullWidth}
        inputRef={mainInputRef}
        placeholder={placeholder || "Sélectionnez une adresse"}
        InputLabelProps={{
          shrink: true,
        }}
        onBlur={onBlur}
        InputProps={{
          readOnly: disabled,
          endAdornment: (
            <InputAdornment position="end">
              <CustomTooltip title={"Selectionnez une Adresse"} arrow>
                <IconButton sx={{p:0}} onClick={handleOpen}>
                  <FontAwesome
                    sx={{ ...(disabled && { color: "text.disabled" }) }}
                    icon={faLocationDot}
                    color="primary.main"
                    width={isSmallScreen ? 17 : 20}
                  />
                </IconButton>
              </CustomTooltip>
            </InputAdornment>
          ),
        }}
      />

      <Dialog open={open} onClose={handleClose} fullWidth maxWidth="md">
        <StyledDialogTitle>Sélectionner une adresse</StyledDialogTitle>
        <DialogContent>
          <Box sx={{ mb: 2, display: "flex", alignItems: "center", gap: 1 }}>
            <Autocomplete
              fullWidth
              freeSolo
              disableClearable
              options={options}
              getOptionLabel={(option) => (typeof option === 'string' ? option : option.description)}
              filterOptions={(x) => x}
              includeInputInList
              filterSelectedOptions
              value={selectedAddress}
              onChange={handleOptionSelect}
              onInputChange={handleInputChange}
              inputValue={inputValue}
              renderOption={(props, option) => (
                <Box component="li" {...props} sx={{ display: "flex", alignItems: "center", gap: 2 }}>
                  <FontAwesome icon={faLocationDot} color="text.disabled" width={16} />
                  {option.description}
                </Box>
              )}
              renderInput={(params) => (
                <WhiteStyledTextField
                  {...params}
                  placeholder="Rechercher une adresse"
                  InputLabelProps={{
                    shrink: true,
                  }}
                  onKeyPress={(e) => e.key === "Enter" && handleSearch()}
                  InputProps={{
                    ...params.InputProps,
                    endAdornment: (
                      <ConditionalComponent
                        isValid={isSearching}
                        defaultComponent={
                          <InputAdornment position="start">
                            <Search color="primary" />
                          </InputAdornment>
                        }
                      >
                        <InputAdornment position="end">
                          <CircularProgress size={20} />
                        </InputAdornment>
                      </ConditionalComponent>
                    )
                  }}
                />
              )}
            />
            <Button
              sx={{ width: "160px",px:0 }}
              variant="contained"
              onClick={getCurrentLocation}
              disabled={isSearching}
              startIcon={<FontAwesome icon={faLocationCrosshairs} />}
            >
              Ma position
            </Button>
          </Box>

          <Paper
            elevation={3}
            id="map"
            sx={{
              height: 400,
              width: "100%",
              mb: 2,
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
            }}
          >
            <ConditionalComponent isValid={!mapLoaded}>
              <CircularProgress />
            </ConditionalComponent>
          </Paper>

        </DialogContent>
        <DialogActions>
          <ActionButtons onSave={handleConfirm} onCancel={handleClose} secoundButtonText={"Confirmer"} />
        </DialogActions>
      </Dialog>
    </FormControl>
  )
}
