// Import necessary modules and components
import { FieldErrors, Resolver, SubmitHandler, useForm } from "react-hook-form";
import { POIDatasourceProd } from "../../data/datasource/api/poi_datasource";
import { POIRepositoryProd } from "../../data/repository/poi_repository";
import { PointOfInterest } from "../../data/datasource/api/entities/poi";
import { useState } from "react";
import axios, { AxiosError } from "axios";
import { toast } from "react-toastify";
import { languaguesList } from "../../core/constants/languages";
import { showErrorAxios } from "../../core/utils/Messages";

// Initialize data source and repository
const POIDatasouce = new POIDatasourceProd();
const POIRepository = new POIRepositoryProd(POIDatasouce);

// Define resolver for form validation
const resolver: Resolver<PointOfInterest> = async (data) => {
  const errors: FieldErrors<PointOfInterest> = {};

  // Validate idPlace
  if (!data.idPlace) {
    errors.idPlace = {
      type: "required",
      message: "Debe seleccionar el lugar al que pertenece el punto de interés",
    };
  }

  // Validate name
  if (!data.name) {
    errors.name = {
      type: "required",
      message: "El nombre del punto de interés es requerido",
    };
  } else if (data.name.length > 255) {
    errors.name = {
      type: "maxLength",
      message: "El tamaño no debe sobrepasar los 255 caracteres",
    };
  }

  // Validate content in English
  if (!data.contentEN) {
    errors.contentEN = {
      type: "required",
      message: "La descripción del punto de interés en inglés es requerida",
    };
  } else if (data.contentEN.length > 1024) {
    errors.contentEN = {
      type: "maxLength",
      message: "El tamaño no debe sobrepasar los 1024 caracteres",
    };
  }

  // Validate content in Spanish
  if (!data.contentES) {
    errors.contentES = {
      type: "required",
      message: "La descripción del punto de interés en español es requerida",
    };
  } else if (data.contentES.length > 1024) {
    errors.contentES = {
      type: "maxLength",
      message: "El tamaño no debe sobrepasar los 1024 caracteres",
    };
  }

  // Validate directions in English
  if (!data.directionsEN) {
    errors.directionsEN = {
      type: "required",
      message: "Las direcciones del punto de interés en inglés son requeridas",
    };
  } else if (data.directionsEN.length > 1024) {
    errors.directionsEN = {
      type: "maxLength",
      message: "El tamaño no debe sobrepasar los 1024 caracteres",
    };
  }

  // Validate directions in Spanish
  if (!data.directionsES) {
    errors.directionsES = {
      type: "required",
      message: "Las direcciones del punto de interés en español son requeridas",
    };
  } else if (data.directionsES.length > 1024) {
    errors.directionsES = {
      type: "maxLength",
      message: "El tamaño no debe sobrepasar los 1024 caracteres",
    };
  }

  // Validate image
  if (!data.image) {
    errors.image = {
      type: "required",
      message: "Debe de haber al menos 1 imagen representativa del lugar",
    };
  }

  return {
    values: Object.keys(errors).length > 0 ? {} : data,
    errors: errors,
  };
};

// Custom hook for point of interest functionality
export const usePointOfInterest = (
  forceRenderList?: () => void,
  setIsWindowActive?: (visibility: boolean) => void
) => {
  const {
    register,
    handleSubmit,
    setValue,
    formState: { errors },
    clearErrors,
    resetField,
  } = useForm<PointOfInterest>({ resolver });
  const [errorMessage, setErrorMessage] = useState("");
  const [
    languageDescriptionIndexSelected,
    setLanguageDescriptionIndexSelected,
  ] = useState(0);
  const [languageDirectionsIndexSelected, setLanguageDirectionsIndexSelected] =
    useState(0);
  const [descriptions, setDescriptions] = useState<string[]>(
    new Array(languaguesList.length).fill("")
  );
  const [directions, setDirections] = useState<string[]>(
    new Array(languaguesList.length).fill("")
  );
  const [poiList, setPoiList] = useState<PointOfInterest[]>([]);
  const [pending, setPending] = useState(false);

  // Handle point of interest registration
  const onSubmitRegister: SubmitHandler<PointOfInterest> = (
    data: PointOfInterest
  ) => {
    const fetch = async () => {
      try {
        await POIRepository.registerPoint(data).then(() => {
          if (forceRenderList && setIsWindowActive) {
            setTimeout(() => {
              forceRenderList();
              setIsWindowActive(false);
            }, 1000);
          }
        });
      } catch (error: any) {
        if (axios.isAxiosError(error)) {
          error as AxiosError;
          switch (error.code) {
            case axios.AxiosError.ERR_BAD_REQUEST:
              setErrorMessage("Acceso no autorizado");
              break;
            case axios.AxiosError.ERR_NETWORK:
              setErrorMessage("Conexión con el servidor fallida");
              break;
            default:
              setErrorMessage(error.message);
              break;
          }
        }
        throw new Error();
      }
    };
    toast.promise(fetch(), {
      pending: "Subiendo datos...",
      success: "Los datos se han subido correctamente",
      error: errorMessage,
    });
  };

  // Update points of interest by place
  const updatePOIByPlace = async (idPlace: number) => {
    setPending(true);
    try {
      const POIs = await POIRepository.getPOIsByPlace(idPlace);
      setPoiList(POIs);
      setPending(false);
    } catch (error: any) {
      if (axios.isAxiosError(error)) {
        error as AxiosError;
        showErrorAxios(error);
      }
      setPending(false);
    }
  };

  // Get PDF by place and points
  const getPdfById = async (
    idPlace: number,
    pointsId: number[]
  ): Promise<string | null> => {
    try {
      const pdfUrl = await POIRepository.getPDFByPoints(idPlace, pointsId);
      return pdfUrl;
    } catch (error: any) {
      if (axios.isAxiosError(error)) {
        error as AxiosError;
        showErrorAxios(error);
      }
    }
    return null;
  };

  // Get point of interest by ID
  const getPointById = async (
    idPoint: number
  ): Promise<PointOfInterest | null> => {
    try {
      const point = await POIRepository.getPOIById(idPoint);
      return point;
    } catch (error: any) {
      if (axios.isAxiosError(error)) {
        error as AxiosError;
        showErrorAxios(error);
      }
    }
    return null;
  };

  return {
    register,
    handleSubmit,
    errors,
    onSubmitRegister,
    setValue,
    languageDescriptionIndexSelected,
    setLanguageDescriptionIndexSelected,
    languageDirectionsIndexSelected,
    setLanguageDirectionsIndexSelected,
    descriptions,
    directions,
    setDirections,
    setDescriptions,
    clearErrors,
    resetField,
    poiList,
    pending,
    getPointById,
    updatePOIByPlace,
    getPdfById,
  };
};
