'use client';

import { useState, useEffect } from 'react';
import { useParams, useRouter, useSearchParams } from 'next/navigation';
import { useLanguage } from '@/context/LanguageContext';
import { useAuth } from '@/context/AuthContext';
import { eventsApi, ticketsApi, paymentOptionsApi, Event, PaymentOptionsConfig } from '@/lib/api';
import { formatDateLong, formatTime, formatRucDisplay, eventSpotsLeft, isEventSoldOut } from '@/lib/utils';
import { isSafeExternalUrl } from '@/lib/safeRedirect';
import toast from 'react-hot-toast';
import type {
  AttendeeInfo,
  BookingFormData,
  BookingResult,
  BookingStep,
  PaymentMethod,
} from './_types';
import { buildPaymentMethods, formatRuc, rucPattern } from './_logic/booking';
import { useLightningWatcher } from '@/hooks/useLightningWatcher';
import { PayingStep } from './_steps/PayingStep';
import { ManualPaymentStep } from './_steps/ManualPaymentStep';
import { PendingApprovalStep } from './_steps/PendingApprovalStep';
import { SuccessStep } from './_steps/SuccessStep';
import { BookingFormStep } from './_steps/BookingFormStep';

export default function BookingPage() {
  const params = useParams();
  const router = useRouter();
  const searchParams = useSearchParams();
  const { t, locale } = useLanguage();
  const { user } = useAuth();
  const [event, setEvent] = useState<Event | null>(null);
  const [paymentConfig, setPaymentConfig] = useState<PaymentOptionsConfig | null>(null);
  const [loading, setLoading] = useState(true);
  const [step, setStep] = useState<BookingStep>('form');
  const [submitting, setSubmitting] = useState(false);
  const [bookingResult, setBookingResult] = useState<BookingResult | null>(null);
  const [markingPaid, setMarkingPaid] = useState(false);

  // State for payer name (when paid under different name)
  const [paidUnderDifferentName, setPaidUnderDifferentName] = useState(false);
  const [payerName, setPayerName] = useState('');

  // Quantity from URL param (default 1)
  const initialQuantity = Math.max(1, parseInt(searchParams.get('qty') || '1', 10));
  const [ticketQuantity, setTicketQuantity] = useState(initialQuantity);

  // Attendees for multi-ticket bookings (ticket 1 uses main formData)
  const [attendees, setAttendees] = useState<AttendeeInfo[]>(() =>
    Array(Math.max(0, initialQuantity - 1)).fill(null).map(() => ({ firstName: '', lastName: '' }))
  );
  const [attendeeErrors, setAttendeeErrors] = useState<{ [key: number]: string }>({});

  const [formData, setFormData] = useState<BookingFormData>({
    firstName: '',
    lastName: '',
    email: '',
    phone: '',
    paymentMethod: '',
    ruc: '',
  });

  const [errors, setErrors] = useState<Partial<Record<keyof BookingFormData, string>>>({});

  // Terms & Privacy agreement (not persisted across page loads)
  const [agreedToTerms, setAgreedToTerms] = useState(false);
  const [termsError, setTermsError] = useState<string | null>(null);

  // Handle RUC input change
  const handleRucChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const formatted = formatRuc(e.target.value);
    setFormData({ ...formData, ruc: formatted });

    // Clear error on change
    if (errors.ruc) {
      setErrors({ ...errors, ruc: undefined });
    }
  };

  // Validate RUC on blur (optional field: base + "-" + check digit)
  const handleRucBlur = () => {
    if (!formData.ruc) return;
    if (!rucPattern.test(formData.ruc)) {
      setErrors({ ...errors, ruc: t('booking.form.errors.rucInvalidFormat') });
    }
  };

  useEffect(() => {
    if (params.eventId) {
      Promise.all([
        eventsApi.getById(params.eventId as string),
        paymentOptionsApi.getForEvent(params.eventId as string),
      ])
        .then(([eventRes, paymentRes]) => {
          if (!eventRes.event || !['published', 'unlisted'].includes(eventRes.event.status)) {
            toast.error('Event is not available for booking');
            router.push('/events');
            return;
          }

          // Redirect to external booking if enabled (only https:// targets are allowed)
          if (
            eventRes.event.externalBookingEnabled &&
            eventRes.event.externalBookingUrl &&
            isSafeExternalUrl(eventRes.event.externalBookingUrl)
          ) {
            window.location.href = eventRes.event.externalBookingUrl;
            return;
          }

          // Server-authoritative availability — same formula the booking API
          // enforces, so a sold-out event is caught here, not at submit time.
          if (isEventSoldOut(eventRes.event)) {
            toast.error(t('events.details.soldOut'));
            router.push(`/events/${eventRes.event.slug}`);
            return;
          }

          const spotsLeft = eventSpotsLeft(eventRes.event);
          setEvent(eventRes.event);
          // Cap quantity by available spots (never allow requesting more than spotsLeft)
          setTicketQuantity((q) => Math.min(q, Math.max(1, spotsLeft)));
          setAttendees((prev) => {
            const newQty = Math.min(initialQuantity, Math.max(1, spotsLeft));
            const need = Math.max(0, newQty - 1);
            if (need === prev.length) return prev;
            return Array(need).fill(null).map((_, i) => prev[i] ?? { firstName: '', lastName: '' });
          });
          setPaymentConfig(paymentRes.paymentOptions);
          // No payment method is pre-selected; the user must choose one.
        })
        .catch(() => router.push('/events'))
        .finally(() => setLoading(false));
    }
  }, [params.eventId, router]);

  // Auto-fill form fields when user is logged in
  useEffect(() => {
    if (user) {
      setFormData(prev => {
        // Split user's full name into first and last name
        const nameParts = (user.name || '').trim().split(' ');
        const firstName = nameParts[0] || '';
        const lastName = nameParts.slice(1).join(' ') || '';

        return {
          ...prev,
          firstName: prev.firstName || firstName,
          lastName: prev.lastName || lastName,
          email: prev.email || user.email || '',
          phone: prev.phone || user.phone || '',
          ruc: prev.ruc || formatRucDisplay(user.rucNumber),
        };
      });
    }
  }, [user]);

  // Clear the terms error as soon as the user agrees
  useEffect(() => {
    if (agreedToTerms && termsError) {
      setTermsError(null);
    }
  }, [agreedToTerms, termsError]);

  // Scroll to top when moving between booking steps (esp. mobile, where
  // the submit button sits at the bottom of a long form)
  useEffect(() => {
    window.scrollTo({ top: 0, behavior: 'smooth' });
  }, [step]);

  const formatDate = (dateStr: string) => formatDateLong(dateStr, locale as 'en' | 'es');
  const fmtTime = (dateStr: string) => formatTime(dateStr, locale as 'en' | 'es');

  const validateForm = (): boolean => {
    const newErrors: Partial<Record<keyof BookingFormData, string>> = {};
    const newAttendeeErrors: { [key: number]: string } = {};

    if (!formData.firstName.trim() || formData.firstName.length < 2) {
      newErrors.firstName = t('booking.form.errors.firstNameRequired');
    }

    // lastName is optional - only validate if provided
    if (formData.lastName.trim() && formData.lastName.length < 2) {
      newErrors.lastName = t('booking.form.errors.lastNameTooShort');
    }

    if (!formData.email.trim() || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
      newErrors.email = t('booking.form.errors.emailInvalid');
    }

    // phone is optional - only validate if provided
    if (formData.phone.trim() && formData.phone.length < 6) {
      newErrors.phone = t('booking.form.errors.phoneTooShort');
    }

    // RUC validation (optional field - base + "-" + check digit if filled)
    if (formData.ruc.trim() && !rucPattern.test(formData.ruc.trim())) {
      newErrors.ruc = t('booking.form.errors.rucInvalidFormat');
    }

    // Payment method must be explicitly chosen and currently enabled
    const availableMethods = buildPaymentMethods(paymentConfig, locale);
    if (
      !formData.paymentMethod ||
      !availableMethods.some((m) => m.id === formData.paymentMethod)
    ) {
      newErrors.paymentMethod = t('booking.form.errors.paymentMethodRequired');
    }

    // Validate additional attendees (if multi-ticket)
    attendees.forEach((attendee, index) => {
      if (!attendee.firstName.trim() || attendee.firstName.length < 2) {
        newAttendeeErrors[index] = locale === 'es'
          ? 'Ingresa el nombre del asistente'
          : 'Enter attendee name';
      }
    });

    setErrors(newErrors);
    setAttendeeErrors(newAttendeeErrors);

    let termsOk = true;
    if (!agreedToTerms) {
      setTermsError(t('booking.form.errors.termsRequired'));
      termsOk = false;
    } else {
      setTermsError(null);
    }

    return (
      Object.keys(newErrors).length === 0 &&
      Object.keys(newAttendeeErrors).length === 0 &&
      termsOk
    );
  };

  // Watch for Lightning payment confirmation while on the paying step.
  useLightningWatcher(
    step === 'paying',
    bookingResult?.ticketId,
    locale,
    () => setStep('success'),
    () => {}
  );

  // Handle "I Have Paid" button click
  const handleMarkPaymentSent = async () => {
    if (!bookingResult) return;

    // Validate payer name if paid under different name
    if (paidUnderDifferentName && !payerName.trim()) {
      toast.error(locale === 'es'
        ? 'Por favor ingresa el nombre del pagador'
        : 'Please enter the payer name');
      return;
    }

    setMarkingPaid(true);
    try {
      await ticketsApi.markPaymentSent(
        bookingResult.ticketId,
        paidUnderDifferentName ? payerName.trim() : undefined
      );
      setStep('pending_approval');
      toast.success(locale === 'es'
        ? 'Pago marcado como enviado. Esperando aprobación.'
        : 'Payment marked as sent. Waiting for approval.');
    } catch (error: any) {
      toast.error(error.message || 'Failed to mark payment as sent');
    } finally {
      setMarkingPaid(false);
    }
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!agreedToTerms) {
      setTermsError(t('booking.form.errors.termsRequired'));
      return;
    }
    if (!event || !validateForm()) return;

    setSubmitting(true);
    try {
      // Build attendees array: first attendee from main form, rest from attendees state
      const allAttendees = [
        { firstName: formData.firstName, lastName: formData.lastName },
        ...attendees
      ];

      const response = await ticketsApi.book({
        eventId: event.id,
        firstName: formData.firstName,
        lastName: formData.lastName,
        email: formData.email,
        phone: formData.phone,
        preferredLanguage: locale as 'en' | 'es',
        paymentMethod: formData.paymentMethod as PaymentMethod,
        ...(formData.ruc.trim() && { ruc: formData.ruc.trim() }),
        // Include attendees array for multi-ticket bookings
        ...(allAttendees.length > 1 && { attendees: allAttendees }),
      });

      const { ticket, tickets: ticketsList, bookingId, lightningInvoice } = response as any;
      const ticketCount = ticketsList?.length || 1;
      const primaryTicket = ticket || ticketsList?.[0];

      // If Lightning payment with invoice, go to paying step
      if (formData.paymentMethod === 'lightning' && lightningInvoice?.paymentRequest) {
        const result: BookingResult = {
          ticketId: primaryTicket.id,
          ticketIds: ticketsList?.map((t: any) => t.id),
          bookingId,
          qrCode: primaryTicket.qrCode,
          qrCodes: ticketsList?.map((t: any) => t.qrCode),
          paymentMethod: formData.paymentMethod as PaymentMethod,
          ticketCount,
          lightningInvoice: {
            paymentHash: lightningInvoice.paymentHash,
            paymentRequest: lightningInvoice.paymentRequest,
            amount: lightningInvoice.amount,
            fiatAmount: lightningInvoice.fiatAmount,
            fiatCurrency: lightningInvoice.fiatCurrency,
            expiry: lightningInvoice.expiry,
          },
        };
        setBookingResult(result);
        setStep('paying');
        // Payment confirmation is handled by the paying-step watcher effect.
      } else if (formData.paymentMethod === 'bank_transfer' || formData.paymentMethod === 'tpago') {
        // Manual payment methods - show payment details
        setBookingResult({
          ticketId: primaryTicket.id,
          ticketIds: ticketsList?.map((t: any) => t.id),
          bookingId,
          qrCode: primaryTicket.qrCode,
          qrCodes: ticketsList?.map((t: any) => t.qrCode),
          paymentMethod: formData.paymentMethod,
          ticketCount,
        });
        // Fetch full payment credentials now that we hold a ticket capability token
        try {
          const { paymentOptions } = await paymentOptionsApi.getForEvent(
            params.eventId as string,
            primaryTicket.id
          );
          setPaymentConfig(paymentOptions);
        } catch {
          // Keep the flags-only config from initial load if the gated fetch fails
        }
        setStep('manual_payment');
      } else {
        // Cash payment - go straight to success
        setBookingResult({
          ticketId: primaryTicket.id,
          ticketIds: ticketsList?.map((t: any) => t.id),
          bookingId,
          qrCode: primaryTicket.qrCode,
          qrCodes: ticketsList?.map((t: any) => t.qrCode),
          paymentMethod: formData.paymentMethod as PaymentMethod,
          ticketCount,
        });
        setStep('success');
        toast.success(t('booking.success.message'));
      }
    } catch (error: any) {
      toast.error(error.message || t('booking.form.errors.bookingFailed'));
      // Capacity race on the last seats: refresh availability so the page
      // reflects reality (sold-out block / lower quantity cap) instead of the
      // stale counts loaded when the form was opened.
      const message = String(error?.message || '');
      if (/sold out|seats available/i.test(message)) {
        try {
          const { event: freshEvent } = await eventsApi.getById(params.eventId as string);
          setEvent(freshEvent);
          const freshSpots = eventSpotsLeft(freshEvent);
          if (freshSpots > 0) {
            setTicketQuantity((q) => Math.min(q, freshSpots));
            setAttendees((prev) => prev.slice(0, Math.max(0, freshSpots - 1)));
          }
        } catch {
          // Keep the stale event state if the refresh fails
        }
      }
    } finally {
      setSubmitting(false);
    }
  };

  // Build payment methods list based on configuration
  const paymentMethods = buildPaymentMethods(paymentConfig, locale);

  if (loading) {
    return (
      <div className="section-padding">
        <div className="container-page max-w-2xl text-center">
          <div className="animate-spin w-8 h-8 border-4 border-primary-yellow border-t-transparent rounded-full mx-auto" />
        </div>
      </div>
    );
  }

  if (!event) {
    return null;
  }

  const spotsLeft = eventSpotsLeft(event);
  const isSoldOut = isEventSoldOut(event);

  // Paying step - waiting for Lightning payment (compact design)
  if (step === 'paying' && bookingResult && bookingResult.lightningInvoice) {
    return (
      <PayingStep
        invoice={bookingResult.lightningInvoice}
        qrCode={bookingResult.qrCode}
        locale={locale}
      />
    );
  }

  // Manual payment step - showing bank transfer details or TPago link
  if (step === 'manual_payment' && bookingResult && paymentConfig) {
    return (
      <ManualPaymentStep
        bookingResult={bookingResult}
        event={event}
        paymentConfig={paymentConfig}
        locale={locale}
        paidUnderDifferentName={paidUnderDifferentName}
        setPaidUnderDifferentName={setPaidUnderDifferentName}
        payerName={payerName}
        setPayerName={setPayerName}
        markingPaid={markingPaid}
        onMarkPaymentSent={handleMarkPaymentSent}
      />
    );
  }

  // Pending approval step - user has marked payment as sent
  if (step === 'pending_approval' && bookingResult) {
    return (
      <PendingApprovalStep
        bookingResult={bookingResult}
        event={event}
        locale={locale}
        t={t}
        formatDate={formatDate}
        fmtTime={fmtTime}
      />
    );
  }

  // Success step
  if (step === 'success' && bookingResult) {
    return (
      <SuccessStep
        bookingResult={bookingResult}
        event={event}
        locale={locale}
        t={t}
        formatDate={formatDate}
        fmtTime={fmtTime}
      />
    );
  }

  return (
    <BookingFormStep
      event={event}
      locale={locale}
      t={t}
      spotsLeft={spotsLeft}
      isSoldOut={isSoldOut}
      ticketQuantity={ticketQuantity}
      formData={formData}
      setFormData={setFormData}
      errors={errors}
      attendees={attendees}
      setAttendees={setAttendees}
      attendeeErrors={attendeeErrors}
      setAttendeeErrors={setAttendeeErrors}
      handleRucChange={handleRucChange}
      handleRucBlur={handleRucBlur}
      paymentMethods={paymentMethods}
      agreedToTerms={agreedToTerms}
      setAgreedToTerms={setAgreedToTerms}
      termsError={termsError}
      submitting={submitting}
      onSubmit={handleSubmit}
      formatDate={formatDate}
      fmtTime={fmtTime}
    />
  );
}
