import { useState, useEffect } from "react";

interface ValidationRule {
  isRequired?: boolean;
  maxLength?: number;
  minLength?: number;
  excludedCharacters?: string[];
  regex?: string | any;
  alpha?: boolean;
  email?: boolean;
  numeric?: boolean;
  date?: boolean;
  alphaDash?: boolean;
  alphaSpace?: boolean;
  sameAsField?: string;
}

interface ErrorMessage {
  isRequired?: string;
  maxLength?: string;
  minLength?: string;
  excludedCharacters?: string;
  regex?: string;
  alpha?: string;
  email?: string;
  numeric?: string;
  date?: string;
  alphaDash?: string;
  alphaSpace?: string;
  sameAsField?: string;
}

interface Validation {
  rules: { [key: string]: ValidationRule };
  messages?: { [key: string]: ErrorMessage };
}

interface ValidationErrors {
  errors: Record<string, string>;
  status: boolean;
}

const isRequiredCheck = (data: any, errorMessage: string) =>
  !data ? errorMessage : "";

const maxLengthCheck = (data: any, max: number, errorMessage: string) =>
  data.length > max ? errorMessage : "";

const minLengthCheck = (data: any, min: number, errorMessage: string) =>
  data.length < min ? errorMessage : "";

const excludedCharactersCheck = (
  data: any,
  chars: string[],
  errorMessage: string
) => (chars.some((char) => data.includes(char)) ? errorMessage : "");

const regexCheck = (data: any, regex: string, errorMessage: string) =>
  new RegExp(regex).test(data) ? "" : errorMessage;

const alphaCheck = (data: any, errorMessage: string) =>
  /^[A-Za-z]+$/.test(data) ? "" : errorMessage;

const emailCheck = (data: string, errorMessage: string) => {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(data) ? "" : errorMessage;
};

const alphaWithDashCheck = (data: string, errorMessage: string) => {
  const regex = /^[A-Za-z]+(-[A-Za-z]+)*$/;
  return regex.test(data) ? "" : errorMessage;
};

const numericCheck = (data: string, errorMessage: string) =>
  /^\d+$/.test(data) ? "" : errorMessage;

const isDateCheck = (data: string, errorMessage: string) => {
  const regex = /^\d{4}-\d{2}-\d{2}$/; // Example format YYYY-MM-DD
  const date = new Date(data);
  return regex.test(data) && !isNaN(date.getTime()) ? "" : errorMessage;
};

const alphaWithSpaceCheck = (data: string, errorMessage: string) => {
  const regex = /^[A-Za-z]+( [A-Za-z]+)*$/;
  return regex.test(data) ? "" : errorMessage;
};

const sameAsFieldCheck = (
  data: string,
  errorMessage: string,
  fieldValue: string
) => (data === fieldValue ? "" : errorMessage);

const useValidation = (
  data: { fields: Record<string, any>; validation: Validation },
  isMultiple = false,
  submit: boolean = true,
  debounceDelay = 300,
  validateAll = false
) => {
  const [errors, setErrors] = useState<ValidationErrors>({
    errors: {},
    status: true,
  });

  const { fields, validation } = data;
  const [fieldsInitailStaus, setFieldsInitailStaus] = useState<any>();
  const [submitted, setsubmitted] = useState(true);

  useEffect(() => {
    let status = { ...fields };
    Object.keys(fields).forEach((field) => (status[field] = false));
    setFieldsInitailStaus(status);
    setsubmitted(submit);
  }, []);

  const validateC = () => {
    const newErrors: Record<string, string> | any = {};
    Object.keys(fields).forEach((field) => {
      const multipleMessages: string[] = [];
      const value = fields[field];
      let error = "";

      const rules = validation.rules[field];
      const messages = validation?.messages?.[field];
      let isRequired = false;
      if (rules?.isRequired) {
        error = isRequiredCheck(
          value,
          messages?.isRequired || `Please enter the ${field}`
        );
        if(error?.length){
          isRequired = true;
          multipleMessages.push(error);
        }
      }
      if ((!error || isMultiple ) && rules?.maxLength !== undefined && !isRequired) {
        error = maxLengthCheck(
          value,
          rules.maxLength,
          messages?.maxLength ||
            `The ${field} length should be at most ${rules.maxLength}`
        );
        error?.length && multipleMessages.push(error);
      }
      if ((!error || isMultiple ) && rules?.minLength !== undefined && !isRequired) {
        error = minLengthCheck(
          value,
          rules.minLength,
          messages?.minLength ||
            `The ${field} length should be at least ${rules.minLength}`
        );
        error?.length && multipleMessages.push(error);
      }
      if ((!error || isMultiple ) && rules?.excludedCharacters && !isRequired) {
        error = excludedCharactersCheck(
          value,
          rules.excludedCharacters,
          messages?.excludedCharacters || `Please enter valid ${field}`
        );
        error?.length && multipleMessages.push(error);
      }
      if ((!error || isMultiple ) && rules?.regex && !isRequired) {
        error = regexCheck(
          value,
          rules.regex,
          messages?.regex || `The ${field} format is invalid`
        );
        error?.length && multipleMessages.push(error);
      }
      if ((!error || isMultiple ) && rules?.alpha && !isRequired) {
        error = alphaCheck(
          value,
          messages?.alpha || `Please enter valid ${field}`
        );
        error?.length && multipleMessages.push(error);
      }
      if ((!error || isMultiple ) && rules?.email && !isRequired) {
        error = emailCheck(
          value,
          messages?.email || `Please enter a valid ${field}`
        );
        error?.length && multipleMessages.push(error);
      }
      if ((!error || isMultiple ) && rules?.numeric && !isRequired) {
        error = numericCheck(
          value,
          messages?.numeric || `Please enter a valid ${field}`
        );
        error?.length && multipleMessages.push(error);
      }
      if ((!error || isMultiple ) && rules?.date && !isRequired) {
        error = isDateCheck(
          value,
          messages?.date || `Please enter a valid ${field}`
        );
        error?.length && multipleMessages.push(error);
      }
      if ((!error || isMultiple ) && rules?.alphaDash && !isRequired) {
        error = alphaWithDashCheck(
          value,
          messages?.alphaDash || `Please enter valid ${field}`
        );
        error?.length && multipleMessages.push(error);
      }
      if ((!error || isMultiple ) && rules?.alphaSpace && !isRequired) {
        error = alphaWithSpaceCheck(
          value,
          messages?.alphaSpace || `Please enter valid ${field}`
        );
        error?.length && multipleMessages.push(error);
      }
      if ((!error || isMultiple ) && rules?.sameAsField && !isRequired) {
        const otherFieldValue = fields[rules.sameAsField];
        error = sameAsFieldCheck(
          value,
          messages?.sameAsField ||
            `Please ensure ${field} matches ${rules.sameAsField}`,
          otherFieldValue
        );
        error?.length && multipleMessages.push(error);
      }
      if (!error.length) {
        setFieldsInitailStaus({ ...fieldsInitailStaus, [field]: true });
      }
      if (fieldsInitailStaus?.[field] == true || submitted == true) {
        newErrors[field] = !isMultiple ? error : multipleMessages;
      }
    });

    if (JSON.stringify(errors.errors) !== JSON.stringify(newErrors)) {
      const status = Object.values(newErrors).some(
        (error: any) => error.length
      );
      setErrors({ errors: newErrors, status });
    }
  };

  useEffect(() => {
    const handler = setTimeout(() => {
      validateC();
    }, debounceDelay);

    return () => {
      clearTimeout(handler);
    };
  }, [fields, validation, debounceDelay, submitted]);

  useEffect(() => {
    validateAll && setsubmitted(true);
  }, [validateAll]);

  return [errors];
};

export default useValidation;
