"use client";

import React from "react";
import { useEffect, useState, useCallback, useMemo } from "react";
import { Permission } from "../auth-context";
import { api } from "../api";
import { Header } from "../components/Header";
import { useRequireAuth } from "../hooks/useRequireAuth";
import { components } from "../generated/api";
import constants from "../../../shared/constants.json";
import { formatDate, formatTime, getDateRange } from "../utils/date";
import { sharedStyles } from "../styles/shared";

const { slotDurationMinutes, maxAdvanceDays, minAdvanceDays, noteMaxLength } = constants.booking;

type BookableSlot = components["schemas"]["BookableSlot"];
type AvailableSlotsResponse = components["schemas"]["AvailableSlotsResponse"];
type AppointmentResponse = components["schemas"]["AppointmentResponse"];

const pageStyles: Record<string, React.CSSProperties> = {
  main: {
    minHeight: "100vh",
    background: "linear-gradient(135deg, #0f0f23 0%, #1a1a3e 50%, #2d1b4e 100%)",
    display: "flex",
    flexDirection: "column",
  },
  loader: {
    flex: 1,
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    fontFamily: "'DM Sans', system-ui, sans-serif",
    color: "rgba(255, 255, 255, 0.5)",
  },
  content: {
    flex: 1,
    padding: "2rem",
    maxWidth: "900px",
    margin: "0 auto",
    width: "100%",
  },
  pageTitle: {
    fontFamily: "'DM Sans', system-ui, sans-serif",
    fontSize: "1.75rem",
    fontWeight: 600,
    color: "#fff",
    marginBottom: "0.5rem",
  },
  pageSubtitle: {
    fontFamily: "'DM Sans', system-ui, sans-serif",
    color: "rgba(255, 255, 255, 0.5)",
    fontSize: "0.9rem",
    marginBottom: "1.5rem",
  },
  successBanner: {
    background: "rgba(34, 197, 94, 0.15)",
    border: "1px solid rgba(34, 197, 94, 0.3)",
    color: "#4ade80",
    padding: "1rem",
    borderRadius: "8px",
    marginBottom: "1rem",
    fontFamily: "'DM Sans', system-ui, sans-serif",
    fontSize: "0.875rem",
  },
  section: {
    marginBottom: "2rem",
  },
  sectionTitle: {
    fontFamily: "'DM Sans', system-ui, sans-serif",
    fontSize: "1.1rem",
    fontWeight: 500,
    color: "#fff",
    marginBottom: "1rem",
  },
  dateGrid: {
    display: "flex",
    flexWrap: "wrap",
    gap: "0.5rem",
  },
  dateButton: {
    fontFamily: "'DM Sans', system-ui, sans-serif",
    padding: "0.75rem 1rem",
    background: "rgba(255, 255, 255, 0.03)",
    border: "1px solid rgba(255, 255, 255, 0.08)",
    borderRadius: "10px",
    cursor: "pointer",
    minWidth: "90px",
    textAlign: "center" as const,
    transition: "all 0.2s",
  },
  dateButtonSelected: {
    background: "rgba(167, 139, 250, 0.15)",
    border: "1px solid #a78bfa",
  },
  dateButtonDisabled: {
    opacity: 0.4,
    cursor: "not-allowed",
    background: "rgba(255, 255, 255, 0.01)",
    border: "1px solid rgba(255, 255, 255, 0.04)",
  },
  dateWeekday: {
    color: "#fff",
    fontWeight: 500,
    fontSize: "0.875rem",
    marginBottom: "0.25rem",
  },
  dateDay: {
    color: "rgba(255, 255, 255, 0.5)",
    fontSize: "0.8rem",
  },
  slotGrid: {
    display: "flex",
    flexWrap: "wrap",
    gap: "0.5rem",
  },
  slotButton: {
    fontFamily: "'DM Sans', system-ui, sans-serif",
    padding: "0.6rem 1.25rem",
    background: "rgba(255, 255, 255, 0.03)",
    border: "1px solid rgba(255, 255, 255, 0.08)",
    borderRadius: "8px",
    color: "#fff",
    cursor: "pointer",
    fontSize: "0.9rem",
    transition: "all 0.2s",
  },
  slotButtonSelected: {
    background: "rgba(167, 139, 250, 0.15)",
    border: "1px solid #a78bfa",
  },
  emptyState: {
    fontFamily: "'DM Sans', system-ui, sans-serif",
    color: "rgba(255, 255, 255, 0.4)",
    padding: "1rem 0",
  },
  confirmCard: {
    background: "rgba(255, 255, 255, 0.03)",
    border: "1px solid rgba(255, 255, 255, 0.08)",
    borderRadius: "12px",
    padding: "1.5rem",
    maxWidth: "400px",
  },
  confirmTitle: {
    fontFamily: "'DM Sans', system-ui, sans-serif",
    fontSize: "1.1rem",
    fontWeight: 500,
    color: "#fff",
    marginBottom: "1rem",
  },
  confirmTime: {
    fontFamily: "'DM Sans', system-ui, sans-serif",
    color: "rgba(255, 255, 255, 0.7)",
    marginBottom: "1rem",
  },
  inputLabel: {
    fontFamily: "'DM Sans', system-ui, sans-serif",
    display: "block",
    color: "rgba(255, 255, 255, 0.7)",
    fontSize: "0.875rem",
    marginBottom: "0.5rem",
  },
  textarea: {
    fontFamily: "'DM Sans', system-ui, sans-serif",
    width: "100%",
    padding: "0.75rem",
    background: "rgba(255, 255, 255, 0.05)",
    border: "1px solid rgba(255, 255, 255, 0.1)",
    borderRadius: "8px",
    color: "#fff",
    fontSize: "0.875rem",
    minHeight: "80px",
    resize: "vertical" as const,
  },
  charCount: {
    fontFamily: "'DM Sans', system-ui, sans-serif",
    fontSize: "0.75rem",
    color: "rgba(255, 255, 255, 0.4)",
    textAlign: "right" as const,
    marginTop: "0.25rem",
  },
  charCountWarning: {
    color: "#f87171",
  },
  buttonRow: {
    display: "flex",
    gap: "0.75rem",
    marginTop: "1.5rem",
  },
  bookButton: {
    fontFamily: "'DM Sans', system-ui, sans-serif",
    flex: 1,
    padding: "0.75rem",
    background: "linear-gradient(135deg, #a78bfa 0%, #7c3aed 100%)",
    border: "none",
    borderRadius: "8px",
    color: "#fff",
    fontWeight: 500,
    cursor: "pointer",
    transition: "all 0.2s",
  },
  bookButtonDisabled: {
    opacity: 0.5,
    cursor: "not-allowed",
  },
  cancelButton: {
    fontFamily: "'DM Sans', system-ui, sans-serif",
    padding: "0.75rem 1.25rem",
    background: "rgba(255, 255, 255, 0.05)",
    border: "1px solid rgba(255, 255, 255, 0.1)",
    borderRadius: "8px",
    color: "rgba(255, 255, 255, 0.7)",
    cursor: "pointer",
    transition: "all 0.2s",
  },
};

const styles = { ...sharedStyles, ...pageStyles };

export default function BookingPage() {
  const { user, isLoading, isAuthorized } = useRequireAuth({
    requiredPermission: Permission.BOOK_APPOINTMENT,
    fallbackRedirect: "/",
  });

  const [selectedDate, setSelectedDate] = useState<Date | null>(null);
  const [availableSlots, setAvailableSlots] = useState<BookableSlot[]>([]);
  const [selectedSlot, setSelectedSlot] = useState<BookableSlot | null>(null);
  const [note, setNote] = useState("");
  const [isLoadingSlots, setIsLoadingSlots] = useState(false);
  const [isBooking, setIsBooking] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [successMessage, setSuccessMessage] = useState<string | null>(null);
  const [datesWithAvailability, setDatesWithAvailability] = useState<Set<string>>(new Set());
  const [isLoadingAvailability, setIsLoadingAvailability] = useState(true);

  // Memoize dates to prevent infinite re-renders
  const dates = useMemo(
    () => getDateRange(minAdvanceDays, maxAdvanceDays),
    [minAdvanceDays, maxAdvanceDays]
  );

  const fetchSlots = useCallback(async (date: Date) => {
    setIsLoadingSlots(true);
    setError(null);
    setAvailableSlots([]);
    setSelectedSlot(null);

    try {
      const dateStr = formatDate(date);
      const data = await api.get<AvailableSlotsResponse>(`/api/booking/slots?date=${dateStr}`);
      setAvailableSlots(data.slots);
    } catch (err) {
      console.error("Failed to fetch slots:", err);
      setError("Failed to load available slots");
    } finally {
      setIsLoadingSlots(false);
    }
  }, []);

  // Fetch availability for all dates on mount
  useEffect(() => {
    if (!user || !isAuthorized) return;

    const fetchAllAvailability = async () => {
      setIsLoadingAvailability(true);
      const availabilitySet = new Set<string>();

      // Fetch availability for all dates in parallel
      const promises = dates.map(async (date) => {
        try {
          const dateStr = formatDate(date);
          const data = await api.get<AvailableSlotsResponse>(`/api/booking/slots?date=${dateStr}`);
          if (data.slots.length > 0) {
            availabilitySet.add(dateStr);
          }
        } catch (err) {
          // Silently fail for individual dates - they'll just be marked as unavailable
          console.error(`Failed to fetch availability for ${formatDate(date)}:`, err);
        }
      });

      await Promise.all(promises);
      setDatesWithAvailability(availabilitySet);
      setIsLoadingAvailability(false);
    };

    fetchAllAvailability();
  }, [user, isAuthorized]); // Removed dates from dependencies - dates is memoized and stable

  useEffect(() => {
    if (selectedDate && user && isAuthorized) {
      fetchSlots(selectedDate);
    }
  }, [selectedDate, user, isAuthorized, fetchSlots]);

  const handleDateSelect = (date: Date) => {
    const dateStr = formatDate(date);
    // Only allow selection if date has availability
    if (datesWithAvailability.has(dateStr)) {
      setSelectedDate(date);
      setSuccessMessage(null);
    }
  };

  const handleSlotSelect = (slot: BookableSlot) => {
    setSelectedSlot(slot);
    setNote("");
    setError(null);
  };

  const handleBook = async () => {
    if (!selectedSlot) return;

    setIsBooking(true);
    setError(null);

    try {
      const appointment = await api.post<AppointmentResponse>("/api/booking", {
        slot_start: selectedSlot.start_time,
        note: note || null,
      });

      setSuccessMessage(
        `Appointment booked for ${formatTime(appointment.slot_start)} - ${formatTime(appointment.slot_end)}`
      );
      setSelectedSlot(null);
      setNote("");

      // Refresh slots to show the booked one is gone
      if (selectedDate) {
        await fetchSlots(selectedDate);
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to book appointment");
    } finally {
      setIsBooking(false);
    }
  };

  const cancelSlotSelection = () => {
    setSelectedSlot(null);
    setNote("");
    setError(null);
  };

  if (isLoading) {
    return (
      <main style={styles.main}>
        <div style={styles.loader}>Loading...</div>
      </main>
    );
  }

  if (!isAuthorized) {
    return null;
  }

  return (
    <main style={styles.main}>
      <Header currentPage="booking" />
      <div style={styles.content}>
        <h1 style={styles.pageTitle}>Book an Appointment</h1>
        <p style={styles.pageSubtitle}>
          Select a date to see available {slotDurationMinutes}-minute slots
        </p>

        {successMessage && <div style={styles.successBanner}>{successMessage}</div>}

        {error && <div style={styles.errorBanner}>{error}</div>}

        {/* Date Selection */}
        <div style={styles.section}>
          <h2 style={styles.sectionTitle}>Select a Date</h2>
          <div style={styles.dateGrid}>
            {dates.map((date) => {
              const dateStr = formatDate(date);
              const isSelected = selectedDate && formatDate(selectedDate) === dateStr;
              const hasAvailability = datesWithAvailability.has(dateStr);
              const isDisabled = !hasAvailability || isLoadingAvailability;

              return (
                <button
                  key={dateStr}
                  onClick={() => handleDateSelect(date)}
                  disabled={isDisabled}
                  style={{
                    ...styles.dateButton,
                    ...(isSelected ? styles.dateButtonSelected : {}),
                    ...(isDisabled ? styles.dateButtonDisabled : {}),
                  }}
                >
                  <div style={styles.dateWeekday}>
                    {date.toLocaleDateString("en-US", { weekday: "short" })}
                  </div>
                  <div style={styles.dateDay}>
                    {date.toLocaleDateString("en-US", { month: "short", day: "numeric" })}
                  </div>
                </button>
              );
            })}
          </div>
        </div>

        {/* Available Slots */}
        {selectedDate && (
          <div style={styles.section}>
            <h2 style={styles.sectionTitle}>
              Available Slots for{" "}
              {selectedDate.toLocaleDateString("en-US", {
                weekday: "long",
                month: "long",
                day: "numeric",
              })}
            </h2>

            {isLoadingSlots ? (
              <div style={styles.emptyState}>Loading slots...</div>
            ) : availableSlots.length === 0 ? (
              <div style={styles.emptyState}>No available slots for this date</div>
            ) : (
              <div style={styles.slotGrid}>
                {availableSlots.map((slot) => {
                  const isSelected = selectedSlot?.start_time === slot.start_time;
                  return (
                    <button
                      key={slot.start_time}
                      onClick={() => handleSlotSelect(slot)}
                      style={{
                        ...styles.slotButton,
                        ...(isSelected ? styles.slotButtonSelected : {}),
                      }}
                    >
                      {formatTime(slot.start_time)}
                    </button>
                  );
                })}
              </div>
            )}
          </div>
        )}

        {/* Booking Form */}
        {selectedSlot && (
          <div style={styles.confirmCard}>
            <h3 style={styles.confirmTitle}>Confirm Booking</h3>
            <p style={styles.confirmTime}>
              <strong>Time:</strong> {formatTime(selectedSlot.start_time)} -{" "}
              {formatTime(selectedSlot.end_time)}
            </p>

            <div>
              <label style={styles.inputLabel}>Note (optional, max {noteMaxLength} chars)</label>
              <textarea
                value={note}
                onChange={(e) => setNote(e.target.value.slice(0, noteMaxLength))}
                placeholder="Add a note about your appointment..."
                style={styles.textarea}
              />
              <div
                style={{
                  ...styles.charCount,
                  ...(note.length >= noteMaxLength ? styles.charCountWarning : {}),
                }}
              >
                {note.length}/{noteMaxLength}
              </div>
            </div>

            <div style={styles.buttonRow}>
              <button
                onClick={handleBook}
                disabled={isBooking}
                style={{
                  ...styles.bookButton,
                  ...(isBooking ? styles.bookButtonDisabled : {}),
                }}
              >
                {isBooking ? "Booking..." : "Book Appointment"}
              </button>
              <button
                onClick={cancelSlotSelection}
                disabled={isBooking}
                style={styles.cancelButton}
              >
                Cancel
              </button>
            </div>
          </div>
        )}
      </div>
    </main>
  );
}
