import LoaderSun from "@/components/common/Loader/LoaderSun";
import Button from "@/components/Forms/Button";
import Input from "@/components/Forms/Input";
import { handleSweetAlert } from "@/components/Modal/SweetAlertConfirm";
import { obterDadosDasCordenadas } from "@/requests/common/Globalsolaratlas/obterDadosDasCordenadas";
import { useAuth } from "@/src/contexts/authContext";
import { useScreenContext } from "@/src/contexts/ScreenContext";
import { FormatFields } from "@/utils";
import {
  calcularDistanciaKm,
  obterCoordenadasLoja,
  paraNumero,
} from "@/utils/deslocamento";
import {
  Autocomplete,
  GoogleMap,
  Marker,
  useLoadScript,
} from "@react-google-maps/api";
import { Info, Search } from "lucide-react";
import Image from "next/image";
import { useEffect, useRef, useState } from "react";
import { BiRadioCircleMarked } from "react-icons/bi";
import LoaderGif from "../../public/images/loaders/loader2.gif";
const libraries = ["places"] as any;

const Mapa = ({ form, lojas, ...rest }: any) => {
  const blueMarkerIcon = {
    url: "https://maps.google.com/mapfiles/ms/icons/blue-dot.png",
  };
  const [selectedPlace, setSelectedPlace] = useState<any>(null);
  const [searchLngLat, setSearchLngLat] = useState<any>(
    form.control._formValues?.searchLngLat || null,
  );

  const { isMobile } = useScreenContext();
  const [currentLocation, setCurrentLocation] = useState<any>(null);
  const [zoom, setZoom] = useState(form.control._formValues?.zoom || 6);
  const { usuario, valuesSession } = useAuth();
  const { session }: any = valuesSession();
  const [mapTypeId, setMapTypeId] = useState<
    "roadmap" | "satellite" | "hybrid" | "terrain" | string
  >(
    form.control._formValues?.type ||
      form.control._formValues?.currentMapTypeId ||
      "roadmap",
  );

  useEffect(() => {
    form.setValue("zoom" as never, zoom as never);
  }, [zoom]);
  useEffect(() => {
    setMapTypeId(form.control._formValues?.currentMapTypeId ?? mapTypeId);
  }, []);
  useEffect(() => {
    if (mapRef.current) {
      setMapTypeId(form.control._formValues?.currentMapTypeId ?? mapTypeId);
    }
  }, [mapTypeId]);
  useEffect(() => {
    form.setValue("searchLngLat", searchLngLat);
  }, [searchLngLat]);
  const mapRef = useRef<google.maps.Map | null>(null);

  const autocompleteRef = useRef<any>(null);
  const googleMapsApiKey = "AIzaSyDGmjm0xgXvIWV8ZO6tCvTDiN3-AvGzmVc";
  const [center, setCenter] = useState<any>(
    form.control._formValues?.center || {
      lat: 0,
      lng: 0,
    },
  );
  const [adressView, setAdressView] = useState<any>(
    form.control._formValues?.adressView,
  );

  useEffect(() => {
    form.setValue("center", center);
  }, [center]);

  // ── Distância Aproximada da Loja (Km, somente IDA) ─────────────────────────
  // Distância em linha reta entre o endereço da LOJA e o endereço de
  // instalação escolhido no mapa. Fica gravada no form (distanciaLoja_coleta)
  // para os "Custos Extras" usarem no cálculo dos Kms do DESLOCAMENTO.
  //
  // Loja de referência: a que já foi escolhida na aba "Dados" (quando o
  // usuário volta para cá) ou a loja padrão do usuário logado, já que a aba do
  // endereço vem ANTES da aba "Dados".
  const idLojaReferencia =
    form.control._formValues?.loja?.value ??
    form.control._formValues?.loja ??
    session?.loja_padrao_usuario;

  const lojaReferencia = (lojas || []).find(
    (l: any) => String(l.id_loja) === String(idLojaReferencia),
  );

  const [coordenadasLoja, setCoordenadasLoja] = useState<any>(
    obterCoordenadasLoja(lojaReferencia),
  );
  const [distanciaLoja, setDistanciaLoja] = useState<string>(() => {
    const salvo = form.control._formValues?.distanciaLoja_coleta;
    return salvo === null || salvo === undefined || salvo === ""
      ? ""
      : FormatFields.formatarNumero(salvo);
  });
  // Enquanto false, o campo é recalculado sempre que as coordenadas mudam.
  const [distanciaLojaEditada, setDistanciaLojaEditada] = useState(
    Boolean(form.control._formValues?.distanciaLojaEditada_coleta),
  );
  const [erroDistanciaLoja, setErroDistanciaLoja] = useState("");

  // Coordenadas da loja: o cadastro já grava latitude_loja/longitude_loja.
  // Lojas antigas sem coordenadas são geocodificadas pelo endereço.
  useEffect(() => {
    const doCadastro = obterCoordenadasLoja(lojaReferencia);
    if (doCadastro) {
      setCoordenadasLoja(doCadastro);
      setErroDistanciaLoja("");
      return;
    }

    if (!lojaReferencia) return;

    const enderecoLoja = [
      lojaReferencia.endereco_loja,
      lojaReferencia.numero_loja,
      lojaReferencia.bairro_loja,
      lojaReferencia.cidade_loja,
      lojaReferencia.estado_loja,
      lojaReferencia.cep_loja,
      "BR",
    ]
      .filter((parte: any) => !!parte && String(parte).trim() !== "")
      .join(", ");

    if (!enderecoLoja || enderecoLoja === "BR") {
      setErroDistanciaLoja(
        "Não foi possível calcular: a loja está sem endereço cadastrado.",
      );
      return;
    }

    let cancelado = false;

    fetch(
      `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(
        enderecoLoja,
      )}&key=${googleMapsApiKey}`,
    )
      .then((response) => response.json())
      .then((data) => {
        if (cancelado) return;
        const localizacao = data?.results?.[0]?.geometry?.location;
        if (!localizacao) {
          setErroDistanciaLoja(
            "Não foi possível localizar o endereço da loja para calcular a distância.",
          );
          return;
        }
        setErroDistanciaLoja("");
        setCoordenadasLoja({ lat: localizacao.lat, lng: localizacao.lng });
      })
      .catch(() => {
        if (cancelado) return;
        setErroDistanciaLoja(
          "Não foi possível localizar o endereço da loja para calcular a distância.",
        );
      });

    return () => {
      cancelado = true;
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [idLojaReferencia, lojas]);

  const calcularDistanciaAproximadaLoja = () =>
    calcularDistanciaKm(
      coordenadasLoja || { lat: null, lng: null },
      searchLngLat || { lat: null, lng: null },
    );

  // Recalcula automaticamente enquanto o usuário não tiver alterado o campo.
  useEffect(() => {
    if (distanciaLojaEditada) return;

    const distancia = calcularDistanciaAproximadaLoja();
    if (distancia === null) return;

    const formatada = FormatFields.formatarNumero(distancia);
    setDistanciaLoja(formatada);
    form.setValue("distanciaLoja_coleta", formatada);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [coordenadasLoja, searchLngLat, distanciaLojaEditada]);

  // Marca para o restante do simulador que o valor foi informado à mão, para
  // não ser sobrescrito pelo recálculo automático nos Custos Extras.
  useEffect(() => {
    form.setValue("distanciaLojaEditada_coleta", distanciaLojaEditada);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [distanciaLojaEditada]);

  async function getAddressLatLng(
    address: string,
    lat: any = "",
    lng: any = "",
  ) {
    try {
      let response: any = [];
      if (lat && lng) {
        response = await fetch(
          `https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lng}&key=${googleMapsApiKey}`,
        );
      } else {
        response = await fetch(
          `https://maps.googleapis.com/maps/api/geocode/json?address=${encodeURIComponent(
            address,
          )}&key=${googleMapsApiKey}`,
        );
      }
      const data = await response.json();
      if (data.results && data.results.length > 0) {
        const { lat, lng } = data.results[0].geometry.location;
        setCenter({ lat, lng });
        // setLongLatitude({ lat, lng });
        setAdressView(data.results[0].formatted_address);

        // );
      } else {
        throw new Error(
          "Coordenadas não encontradas para o endereço fornecido",
        );
      }
    } catch (error) {
      console.error("Erro ao obter coordenadas:", error);
    }
  }

  const handlePlaceChanged = async () => {
    const place = autocompleteRef.current.getPlace();
    setSelectedPlace(place);
    setSearchLngLat({
      lat: place?.geometry?.location.lat(),
      lng: place?.geometry?.location.lng(),
    });
    await obterDadosDasCordenadas({
      lat: place?.geometry?.location.lat(),
      long: place?.geometry?.location.lng(),
    }).then((res) => {
      const ghiRes = res?.annual?.data?.GHI;
      if (ghiRes) {
        setGHI(FormatFields.formatarNumero(+ghiRes / 365));
        form.setValue("ghi", FormatFields.formatarNumero(+ghiRes / 365));
      }
      form.setValue("ghiMeses", res?.monthly?.data?.GHI);
      setGhiMeses(res?.monthly?.data?.GHI);
      setIsLoading(false);
    });

    setCurrentLocation(null);

    setZoom(15);
  };
  const [ghi, setGHI] = useState(form.control._formValues?.ghi || "");
  const [ghiMeses, setGhiMeses] = useState<any[]>(
    form.control._formValues?.ghiMeses || [],
  );

  const handleGetLocationClick = async () => {
    if (navigator.geolocation) {
      return new Promise((resolve, reject) => {
        navigator.geolocation.getCurrentPosition(
          async (position) => {
            const { latitude, longitude } = position.coords;
            setSelectedPlace(null);
            setSearchLngLat(null);
            await obterDadosDasCordenadas({
              lat: latitude,
              long: longitude,
            })
              .then((res) => {
                const ghiRes = res?.annual?.data?.GHI;
                if (ghiRes) {
                  setGHI(FormatFields.formatarNumero(+ghiRes / 365));
                  form.setValue(
                    "ghi",
                    FormatFields.formatarNumero(+ghiRes / 365),
                  );
                }
                form.setValue("ghiMeses", res?.monthly?.data?.GHI);
                setGhiMeses(res?.monthly?.data?.GHI);
                setIsLoading(false);
              })
              .catch(() => {
                reject("not ok");
              });
            setSearchLngLat({ lat: latitude, lng: longitude });
            setCurrentLocation({ lat: latitude, lng: longitude });
            // getAddressFromLatLng(latitude, longitude);

            form.setValue("searchLngLat", { lat: latitude, lng: longitude });

            setZoom(15);
            resolve("ok");
          },
          (error) => {
            console.error(error);
            reject("not ok");
          },
        );
      });
    } else {
      console.error("Geolocation não é suportada nesse navegador!.");
    }
  };

  const onMapLoad = (map: any) => {
    map.addListener("zoom_changed", () => {
      setZoom(map.zoom);
    });
    mapRef.current = map;
    setZoom(map.zoom);
    map.addListener("maptypeid_changed", () => {
      const currentType = map.getMapTypeId();
      setMapTypeId(currentType);
    });
  };
  const [isLoading, setIsLoading] = useState(false);
  const [isLoadingLocation, setIsLoadingLocation] = useState(false);
  useEffect(() => {
    if (lojas.length > 0) {
      const loja = lojas.find((l: any) => l.id_loja == usuario.loja_usuario);
      const address = `${loja?.endereco_loja}, ${loja?.numero_loja} - ${loja?.bairro_loja}, ${loja?.cidade_loja}, ${loja?.estado_loja}, ${loja?.cep_loja}, BR`;
      getAddressLatLng(address);
      form.setValue("address", address);
    }
  }, [lojas]);

  const handleMapClick = async (event: any) => {
    const { latLng } = event; // Obter as coordenadas do local clicado
    const lat = latLng.lat();
    const lng = latLng.lng();
    setSearchLngLat({ lat, lng }); // Atualizar as coordenadas do local de pesquisa
    await obterDadosDasCordenadas({
      lat: lat,
      long: lng,
    }).then((res) => {
      const ghiRes = res?.annual?.data?.GHI;
      if (ghiRes) {
        setGHI(FormatFields.formatarNumero(+ghiRes / 365));
        form.setValue("ghi", FormatFields.formatarNumero(+ghiRes / 365));
      }
      form.setValue("ghiMeses", res?.monthly?.data?.GHI);
      setGhiMeses(res?.monthly?.data?.GHI);
    });
    setIsLoading(false);
    setSelectedPlace(null); // Limpar o lugar selecionado (se houver)
    setCurrentLocation(null); // Limpar a localização atual (se houver)

    // getAddressFromLatLng(lat, lng);
  };

  const { isLoaded: isLoadedMap } = useLoadScript({
    googleMapsApiKey,
    libraries,
  });
  if (!isLoadedMap) return <div>Carregando mapa...</div>;

  return (
    <form {...rest} key={form.key}>
      <div style={{ width: "100%" }}>
        <div className="w-full mb-4 md:shadow-md max-sm:bg-gray max-sm:rounded-full md:shadow-t-lg p-4">
          <Autocomplete
            onLoad={(autocomplete) => {
              autocompleteRef.current = autocomplete;
            }}
            onPlaceChanged={handlePlaceChanged}
            options={{
              fields: ["address_components", "geometry", "name"],
            }}
          >
            {/* <div className={`flex items-center ${isDisabledMap && "hidden"}`}> */}
            <div className={`flex items-center`}>
              <Search size={15} />
              <input
                type="text"
                placeholder="Pesquisar endereço..."
                className="w-full dark:bg-form-input max-sm:bg-gray max-sm:text-xs rounded-sm px-2"
                onInput={(e: any) => {
                  const inputEl = e.target; // Acesso ao input real
                  const originalValue = inputEl.value;

                  // Se for um CEP sem hífen, insere o hífen temporariamente
                  if (/^\d{5,8}/.test(originalValue)) {
                    inputEl.value = originalValue.replace(
                      /^(\d{5})(\d)/,
                      "$1-$2",
                    );

                    const event = new Event("input", { bubbles: true });
                    inputEl.dispatchEvent(event);

                    inputEl.value = originalValue;
                  }
                }}
              />
            </div>
          </Autocomplete>
        </div>
        <div className="relative overflow-hidden">
          <div className="flex mb-2 flex-col items-center gap-2">
            <Button
              className="flex flex-row items-center gap-1 text-sm py-1 px-2 bg-primary"
              type="button"
              onClick={() => {
                setIsLoadingLocation(true);
                handleGetLocationClick().finally(() => {
                  setIsLoadingLocation(false);
                });
              }}
              disabled={isLoadingLocation}
            >
              <div>Usar Localização Atual</div>
              {isLoadingLocation ? (
                <Image width={25} height={25} src={LoaderGif} alt="Logo" />
              ) : (
                <BiRadioCircleMarked size={17} />
              )}
            </Button>
          </div>
          <GoogleMap
            zoom={zoom || +form.control._formValues["zoom_coleta"]}
            center={currentLocation || searchLngLat || center}
            mapContainerStyle={{
              width: "100%",
              height: "100vh",
            }}
            onLoad={onMapLoad}
            onClick={(e) => {
              handleMapClick(e);
            }}
            options={{
              mapTypeId,
            }}
            onMapTypeIdChanged={() => {
              const currentMapTypeId = mapRef?.current?.getMapTypeId();
              if (currentMapTypeId) {
                form.setValue("currentMapTypeId", currentMapTypeId);
                setMapTypeId(currentMapTypeId);
              }
            }}
          >
            {searchLngLat && <Marker position={searchLngLat} />}
            {selectedPlace && <Marker position={searchLngLat} />}
            {currentLocation && <Marker position={currentLocation} />}
          </GoogleMap>
        </div>
        <div className="dark:text-white text-sm mt-2">
          Localização Atual: {adressView}
        </div>

        {/* Distância Aproximada da Loja (Km, somente IDA) */}
        <div className="dark:text-white text-sm flex flex-col gap-1 mt-2">
          <div className="flex flex-row gap-2 items-center flex-wrap">
            <div className="whitespace-nowrap">
              Distância Aproximada da Loja
              {lojaReferencia?.nome_loja ? ` (${lojaReferencia.nome_loja})` : ""}
              :
            </div>
            <Input
              name="distanciaLoja_coleta"
              formulario={form}
              mascara="numero"
              suffix="Km"
              width={"w-fit"}
              defaultValue={distanciaLoja}
              onChange={(e: any) => {
                setDistanciaLojaEditada(true);
                setDistanciaLoja(e.target.value);
              }}
            />
            <Button
              type="button"
              className="bg-primary flex flex-row gap-2 rounded-full p-0"
              onClick={(e: any) => {
                e.stopPropagation();
                handleSweetAlert({
                  icon: "info",
                  showDenyButton: false,
                  confirmButtonText: "Ok",
                  html: `
                      <div class="flex flex-col gap-2">
                        <div class="font-bold">
                          Distância Aproximada da Loja
                        </div>
                        <div class="italic text-meta-1">
                          Distância em linha reta entre o endereço da loja e o endereço de instalação, considerando apenas a IDA.
                          <br/><br/>
                          É calculada automaticamente ao escolher o endereço no mapa e pode ser alterada manualmente.
                          Nos "Custos Extras" o DESLOCAMENTO usa esta distância multiplicada por 2 (ida e volta).
                          <br/><br/>
                          Zerar este campo faz o sistema desconsiderar a exigência de cobrança de DESLOCAMENTO.
                        </div>
                      </div>`,
                });
              }}
            >
              <Info />
            </Button>
            {distanciaLojaEditada && (
              <button
                type="button"
                className="text-primary underline text-sm"
                onClick={() => {
                  const distancia = calcularDistanciaAproximadaLoja();
                  if (distancia === null) return;
                  setDistanciaLojaEditada(false);
                  setDistanciaLoja(FormatFields.formatarNumero(distancia));
                  form.setValue(
                    "distanciaLoja_coleta",
                    FormatFields.formatarNumero(distancia),
                  );
                }}
              >
                Recalcular
              </button>
            )}
          </div>
          {erroDistanciaLoja && (
            <div className="text-error text-sm">{erroDistanciaLoja}</div>
          )}
        </div>
        {ghi &&
          (!isLoading ? (
            <div>
              <div>
                <div className="text-sm">
                  Latitude:{" "}
                  <span className="font-bold text-sm">{searchLngLat?.lat}</span>
                </div>
                <div className="text-sm">
                  Longitude:{" "}
                  <span className="font-bold text-sm">{searchLngLat?.lng}</span>
                </div>
              </div>
              <div className="flex flex-row gap-1 text-sm">
                Irradiação Global Horizontal:{" "}
                <span className="font-bold text-sm">{ghi} kWh/m² por dia</span>
                <Button
                  type="button"
                  className={` bg-primary flex flex-row gap-2 rounded-full p-0`}
                  onClick={(e: any) => {
                    e.stopPropagation();
                    handleSweetAlert({
                      icon: "info",
                      // title: "Cálculo Markup",
                      showDenyButton: false,
                      confirmButtonText: "Ok",
                      html: `
                                          <div class="flex flex-col gap-2">
                                            <div>
                                              <div class="font-bold">
                                                Irradiação Global Horizontal
                                              </div>
                                              <div class="italic text-meta-1 flex flex-col gap-2 items-center">
                                                <div>
                                                  ${FormatFields.formatarNumero(ghiMeses.reduce((acc, curr) => (acc += curr), 0))} kWh/m² por ano
                                                </div>
                                                <div class="flex flex-col items-end w-fit leading-none">
                                                  <div>
                                                    ${FormatFields.formatarNumero(ghiMeses.reduce((acc, curr) => (acc += curr), 0))} / 12 meses = ${FormatFields.formatarNumero(ghiMeses.reduce((acc, curr) => (acc += curr), 0) / 12)} kWh/m² por mês
                                                  </div>
                                                  <div class="text-sm">
                                                    (usado na proposta)
                                                  </div>
                                                </div>
                                                <div>
                                                  ${FormatFields.formatarNumero(ghiMeses.reduce((acc, curr) => (acc += curr), 0))} / 365 dias = ${FormatFields.formatarNumero(ghiMeses.reduce((acc, curr) => (acc += curr), 0) / 365)} kWh/m² por dia
                                                </div>
                                              </div>
                                            </div>
                                          </div>`,
                    });
                  }}
                >
                  <Info />
                </Button>
              </div>
            </div>
          ) : (
            <div className="flex relative overflow-hidden items-center justify-center">
              <LoaderSun height={60} />
            </div>
          ))}
      </div>
    </form>
  );
};

export default Mapa;
