/**
 * Mawidi Demo Scheduler - useBookingForm Hook
 * Manages booking form state, validation, and submission
 */

"use client";

import { useState, useCallback } from "react";
import type {
  BookingData,
  UserInfo,
  FormErrors,
} from "../types/scheduler.types";
import {
  validateEmail,
  validatePhoneNumber,
  validateName,
  validateMessage,
  sanitizeInput,
} from "../utils/validationHelpers";
import {
  saveBookingToStorage,
  getBookingFromStorage,
} from "../utils/storageHelpers";
import {
  isValidBookingDate,
  parseValidBookingDate,
} from "../utils/dateValidation";

// Stable empty references to prevent re-renders
const EMPTY_INITIAL_DATA: Partial<BookingData> = {};
const EMPTY_OPTIONS: UseBookingFormOptions = {};

export interface UseBookingFormOptions {
  /** Initial booking data */
  initialData?: Partial<BookingData>;
  /** Callback when booking is successfully submitted */
  onSuccess?: (bookingData: BookingData, bookingReference: string) => void;
  /** Callback when submission fails */
  onError?: (error: Error) => void;
  /** n8n webhook URL for booking submission */
  webhookUrl?: string;
}

export interface UseBookingFormReturn {
  /** Current booking data */
  bookingData: Partial<BookingData>;
  /** Form validation errors */
  errors: FormErrors;
  /** Whether form is currently submitting */
  submitting: boolean;
  /** Whether form has been successfully submitted */
  submitted: boolean;
  /** Booking reference after successful submission */
  bookingReference: string | null;
  /** Update booking data */
  updateBookingData: (data: Partial<BookingData>) => void;
  /** Update user info specifically */
  updateUserInfo: (userInfo: Partial<UserInfo>) => void;
  /** Validate entire form */
  validateForm: () => boolean;
  /** Set form errors */
  setErrors: (errors: FormErrors) => void;
  /** Submit booking */
  submitBooking: () => Promise<void>;
  /** Reset form to initial state */
  resetForm: () => void;
  /** Save current state to storage */
  saveToStorage: () => void;
  /** Load state from storage */
  loadFromStorage: () => void;
}

/**
 * useBookingForm Hook
 *
 * Manages booking form state, validation, submission, and persistence
 * Handles all form logic and API communication
 *
 * @example
 * ```tsx
 * const {
 *   bookingData,
 *   updateBookingData,
 *   submitBooking,
 *   submitting
 * } = useBookingForm({
 *   onSuccess: (data, ref) => console.log('Booked!', ref),
 *   webhookUrl: process.env.NEXT_PUBLIC_N8N_WEBHOOK_URL
 * });
 * ```
 */
export function useBookingForm({
  initialData = EMPTY_INITIAL_DATA,
  onSuccess,
  onError,
  webhookUrl,
}: UseBookingFormOptions = EMPTY_OPTIONS): UseBookingFormReturn {
  const [bookingData, setBookingData] = useState<Partial<BookingData>>(() => {
    // Try to load from storage first
    const stored = getBookingFromStorage();
    if (stored) {
      // Validate the restored date using shared date validation
      // This prevents epoch dates and past dates from being loaded
      const validDate = parseValidBookingDate(stored.selectedDate, {
        requireFuture: true,
        allowToday: true,
      });

      return {
        ...stored,
        selectedDate: validDate,
      } as Partial<BookingData>;
    }
    return initialData;
  });

  const [errors, setErrors] = useState<FormErrors>({});
  const [submitting, setSubmitting] = useState(false);
  const [submitted, setSubmitted] = useState(false);
  const [bookingReference, setBookingReference] = useState<string | null>(null);
  const [meetingLink, setMeetingLink] = useState<string | null>(null);

  /**
   * Update booking data
   */
  const updateBookingData = useCallback((data: Partial<BookingData>) => {
    setBookingData((prev) => ({
      ...prev,
      ...data,
    }));
  }, []);

  /**
   * Update user info specifically
   */
  const updateUserInfo = useCallback((userInfo: Partial<UserInfo>) => {
    setBookingData((prev) => ({
      ...prev,
      userInfo: {
        ...(prev as BookingData).userInfo,
        ...userInfo,
      } as UserInfo,
    }));
  }, []);

  /**
   * Validate entire form
   */
  const validateForm = useCallback((): boolean => {
    const newErrors: FormErrors = {};

    // Validate duration
    if (!bookingData.meetingDuration) {
      newErrors.duration = "Please select a meeting duration";
    }

    // Validate date using shared date validation
    if (!bookingData.selectedDate) {
      newErrors.date = "Please select a date";
    } else {
      const dateValidation = isValidBookingDate(bookingData.selectedDate, {
        requireFuture: false, // Future check is done elsewhere
      });
      if (!dateValidation.valid) {
        newErrors.date =
          dateValidation.error ||
          "Invalid date selected. Please select a valid date.";
      }
    }

    // Validate time
    if (!bookingData.selectedTime) {
      newErrors.time = "Please select a time slot";
    }

    // Validate user info
    const fullBooking = bookingData as BookingData;
    if (!fullBooking.userInfo) {
      newErrors.name = "Please provide your information";
    } else {
      const { name, email, phone, message } = fullBooking.userInfo;

      // Name validation
      const nameResult = validateName(name || "");
      if (!nameResult.valid) {
        newErrors.name = nameResult.error;
      }

      // Email validation
      const emailResult = validateEmail(email || "");
      if (!emailResult.valid) {
        newErrors.email = emailResult.error;
      }

      // Phone validation (required)
      if (!phone) {
        newErrors.phone = "Phone number is required";
      } else {
        const phoneResult = validatePhoneNumber(phone);
        if (!phoneResult.valid) {
          newErrors.phone = phoneResult.error;
        }
      }

      // Message validation
      const messageResult = validateMessage(message || "");
      if (!messageResult.valid) {
        newErrors.message = messageResult.error;
      }
    }

    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  }, [bookingData]);

  /**
   * Get CSRF token from cookie
   */
  const getCSRFToken = useCallback((): string | null => {
    if (typeof document === "undefined") return null;
    const match = document.cookie.match(/csrf-token=([^;]+)/);
    return match ? match[1] : null;
  }, []);

  /**
   * Get reCAPTCHA token for bot protection with retry logic
   */
  const getRecaptchaToken = useCallback(async (): Promise<string | null> => {
    if (typeof window === "undefined") return null;

    const siteKey = process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY;
    if (!siteKey) {
      // reCAPTCHA not configured - skip
      console.log("reCAPTCHA not configured, skipping token generation");
      return null;
    }

    try {
      // Wait for grecaptcha to be loaded with retry logic
      let retries = 0;
      const maxRetries = 10;
      const retryDelay = 200; // ms

      while (!(window as any).grecaptcha?.ready && retries < maxRetries) {
        console.log(
          `Waiting for reCAPTCHA to load... (attempt ${retries + 1}/${maxRetries})`,
        );
        await new Promise((resolve) => setTimeout(resolve, retryDelay));
        retries++;
      }

      if (!(window as any).grecaptcha?.ready) {
        console.warn(
          "reCAPTCHA not loaded after retries, proceeding without token",
        );
        return null;
      }

      // Wait for grecaptcha.ready
      return new Promise((resolve) => {
        (window as any).grecaptcha.ready(async () => {
          try {
            const token = await (window as any).grecaptcha.execute(siteKey, {
              action: "demo_booking",
            });
            console.log("reCAPTCHA token generated successfully");
            resolve(token);
          } catch (error) {
            console.error("Failed to execute reCAPTCHA:", error);
            resolve(null);
          }
        });
      });
    } catch (error) {
      console.error("Failed to get reCAPTCHA token:", error);
      return null;
    }
  }, []);

  /**
   * Submit booking to API endpoint with database persistence and n8n webhook
   */
  const submitBooking = useCallback(async () => {
    console.log("🚀 submitBooking called");

    // Validate form first
    if (!validateForm()) {
      console.error("❌ Form validation failed");
      return;
    }

    console.log("✅ Form validation passed");
    setSubmitting(true);

    try {
      // Get reCAPTCHA token for bot protection
      console.log("Getting reCAPTCHA token...");
      const recaptchaToken = await getRecaptchaToken();
      console.log(
        "reCAPTCHA token:",
        recaptchaToken ? "obtained" : "not available",
      );

      // Prepare submission data for API
      const fullBooking = bookingData as BookingData;

      // Convert duration to backend format
      const durationMap: Record<number, string> = {
        30: "30min",
        60: "1hr",
        90: "1.5hr",
        120: "2hr",
      };
      const durationValue = durationMap[bookingData.meetingDuration || 30];

      // Format date in YYYY-MM-DD format WITHOUT timezone conversion
      // This prevents the bug where selecting Nov 12 saves as Nov 11 due to UTC shift
      const formatDateOnly = (date: Date): string => {
        const year = date.getFullYear();
        const month = String(date.getMonth() + 1).padStart(2, "0");
        const day = String(date.getDate()).padStart(2, "0");
        return `${year}-${month}-${day}`;
      };

      const submissionData = {
        fullName: sanitizeInput(fullBooking.userInfo?.name || ""),
        email: sanitizeInput(fullBooking.userInfo?.email || ""),
        telephone: fullBooking.userInfo?.phone
          ? sanitizeInput(fullBooking.userInfo.phone)
          : "",
        appointmentDate: bookingData.selectedDate
          ? formatDateOnly(bookingData.selectedDate)
          : "",
        appointmentTime: bookingData.selectedTime,
        duration: durationValue,
        specialRequirements: sanitizeInput(fullBooking.userInfo?.message || ""),
        language:
          typeof window !== "undefined" &&
          window.location.pathname.includes("/ar/")
            ? "ar"
            : "en",
        timezone: bookingData.timezone || "Asia/Qatar", // Include timezone for Google Calendar
        recaptchaToken, // Include reCAPTCHA token if available
      };

      // Get CSRF token
      console.log("Getting CSRF token...");
      const csrfToken = getCSRFToken();
      console.log("CSRF token:", csrfToken ? "found" : "NOT FOUND");

      if (!csrfToken) {
        console.error("❌ CSRF token missing from cookies");
        throw new Error(
          "CSRF token not found. Please refresh the page and try again.",
        );
      }

      console.log("📤 Submitting to API:", submissionData);

      // Submit to API endpoint
      const response = await fetch("/api/demo/book", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "x-csrf-token": csrfToken,
        },
        body: JSON.stringify(submissionData),
      });

      console.log("📥 API Response status:", response.status);
      const result = await response.json();
      console.log("📥 API Response data:", result);

      if (!response.ok) {
        console.error("❌ API returned error:", response.status, result);

        // Better error messages based on status code and error content
        let errorMessage =
          result.error || "Booking submission failed. Please try again.";

        if (
          response.status === 409 ||
          errorMessage.toLowerCase().includes("already booked")
        ) {
          errorMessage =
            "This time slot is already booked. Please select another time.";
        } else if (response.status === 429) {
          errorMessage =
            "Too many booking attempts. Please wait a moment and try again.";
        } else if (response.status === 400) {
          errorMessage =
            result.error ||
            "Invalid booking information. Please check your details and try again.";
        } else if (response.status === 500) {
          errorMessage = "Server error. Please try again in a moment.";
        }

        throw new Error(errorMessage);
      }

      console.log("✅ Booking created successfully:", result);

      // Generate booking reference from response or create one
      const reference =
        result.bookingId ||
        `BK-${new Date().getFullYear()}-${Math.random().toString(36).substring(2, 8).toUpperCase()}`;
      console.log("📝 Booking reference:", reference);

      // Extract Google Meet link if available
      const googleMeetLink = result.meetingLink || null;
      if (googleMeetLink) {
        console.log("🎥 Google Meet link received:", googleMeetLink);
      } else {
        console.log(
          "ℹ️  No Google Meet link in response (will be sent via email)",
        );
      }

      // Save to storage
      saveBookingToStorage(bookingData as BookingData);

      // Update state
      setBookingReference(reference);
      setMeetingLink(googleMeetLink);
      setSubmitted(true);

      // Call success callback
      onSuccess?.(bookingData as BookingData, reference);
    } catch (error) {
      console.error("💥 Booking submission error:", error);
      const err =
        error instanceof Error ? error : new Error("Booking submission failed");
      setErrors({ submit: err.message });
      console.error("Setting error state:", err.message);
      onError?.(err);
      throw err;
    } finally {
      console.log("🏁 Submit complete, setting submitting to false");
      setSubmitting(false);
    }
  }, [
    bookingData,
    validateForm,
    getCSRFToken,
    getRecaptchaToken,
    onSuccess,
    onError,
  ]);

  /**
   * Reset form to initial state
   */
  const resetForm = useCallback(() => {
    setBookingData(initialData);
    setErrors({});
    setSubmitting(false);
    setSubmitted(false);
    setBookingReference(null);
    setMeetingLink(null);
    // Clear storage
    if (typeof window !== "undefined") {
      window.localStorage.removeItem("mawidi_booking_draft");
    }
  }, [initialData]);

  /**
   * Save current state to storage
   */
  const saveToStorage = useCallback(() => {
    if (bookingData.meetingDuration && bookingData.selectedDate) {
      saveBookingToStorage(bookingData as BookingData);
    }
  }, [bookingData]);

  /**
   * Load state from storage
   */
  const loadFromStorage = useCallback(() => {
    const stored = getBookingFromStorage();
    if (stored) {
      // Validate the restored date using shared date validation
      // This prevents epoch dates and past dates from being loaded
      const validDate = parseValidBookingDate(stored.selectedDate, {
        requireFuture: true,
        allowToday: true,
      });

      setBookingData({
        ...stored,
        selectedDate: validDate,
      } as Partial<BookingData>);
    }
  }, []);

  return {
    bookingData,
    errors,
    submitting,
    submitted,
    bookingReference,
    meetingLink,
    updateBookingData,
    updateUserInfo,
    validateForm,
    setErrors,
    submitBooking,
    resetForm,
    saveToStorage,
    loadFromStorage,
  };
}
