/* global React, LR_IMAGES */

const BOOKING_DURATION_MINUTES = 60;
const GOOGLE_HEALTH_CHECK_INTERVAL = 30000;
const CITAS_LOOKRENDER_CALENDAR_ID = 'kinoprados@gmail.com';
const AGENDA_CALENDAR_ID = 'egs48vf2oj15pm7b59l4al8ngc@group.calendar.google.com';
const FAMILY_CALENDAR_ID = 'family09004856225076930200@group.calendar.google.com';
const BLOCKING_ICS_URLS = [
  'https://calendar.google.com/calendar/ical/kinoprados%40gmail.com/public/basic.ics',
  'https://calendar.google.com/calendar/ical/family09004856225076930200%40group.calendar.google.com/public/basic.ics',
  'https://calendar.google.com/calendar/ical/egs48vf2oj15pm7b59l4al8ngc%40group.calendar.google.com/public/basic.ics',
];
const BLOCKING_CALENDAR_IDS = [
  CITAS_LOOKRENDER_CALENDAR_ID,
  FAMILY_CALENDAR_ID,
  AGENDA_CALENDAR_ID,
];
const DIRECT_GOOGLE_PROXY = 'http://lookrender.synology.me:3009';

function pad2(value) {
  return String(value).padStart(2, '0');
}

function toDateKey(date) {
  return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
}

function fromDateKey(dateKey, hour) {
  const [year, month, day] = dateKey.split('-').map(Number);
  return new Date(year, month - 1, day, hour, 0, 0, 0);
}

function addMinutes(date, minutes) {
  return new Date(date.getTime() + minutes * 60 * 1000);
}

function buildBookingDays(count) {
  const today = new Date();
  const days = [];
  for (let i = 0; days.length < count && i < 45; i += 1) {
    const date = new Date(today.getFullYear(), today.getMonth(), today.getDate() + i);
    const day = date.getDay();
    if (day !== 0 && day !== 6) days.push(date);
  }
  return days;
}

function buildMonthDays(date) {
  const first = new Date(date.getFullYear(), date.getMonth(), 1);
  const last = new Date(date.getFullYear(), date.getMonth() + 1, 0);
  const offset = (first.getDay() + 6) % 7;
  const cells = [];
  for (let i = 0; i < offset; i += 1) cells.push(null);
  for (let day = 1; day <= last.getDate(); day += 1) {
    cells.push(new Date(date.getFullYear(), date.getMonth(), day));
  }
  return cells;
}

const BOOKING_HOURS = [10, 11, 12, 13, 15, 16];

function isLocalHost() {
  return ['localhost', '127.0.0.1'].includes(window.location.hostname);
}

function unfoldIcsLines(text) {
  return text.replace(/\r\n/g, '\n').split('\n').reduce((lines, line) => {
    if (/^[ \t]/.test(line) && lines.length > 0) {
      lines[lines.length - 1] += line.slice(1);
    } else {
      lines.push(line);
    }
    return lines;
  }, []);
}

function parseIcsDate(value) {
  if (!value) return null;
  const clean = value.trim();
  const match = clean.match(/^(\d{4})(\d{2})(\d{2})(?:T(\d{2})(\d{2})(\d{2})?)?(Z)?$/);
  if (!match) return null;
  const [, year, month, day, hour = '00', minute = '00', second = '00', utc] = match;
  if (utc) return new Date(Date.UTC(+year, +month - 1, +day, +hour, +minute, +(second || '0')));
  return new Date(+year, +month - 1, +day, +hour, +minute, +(second || '0'));
}

function parseIcsBusy(text) {
  const lines = unfoldIcsLines(text);
  const busy = [];
  let event = null;
  for (const line of lines) {
    if (line === 'BEGIN:VEVENT') event = {};
    if (line === 'END:VEVENT') {
      if (event?.start && event?.end) busy.push({ start: event.start.toISOString(), end: event.end.toISOString() });
      event = null;
      continue;
    }
    if (!event) continue;
    const sep = line.indexOf(':');
    if (sep < 0) continue;
    const key = line.slice(0, sep).split(';')[0];
    const value = line.slice(sep + 1);
    if (key === 'DTSTART') event.start = parseIcsDate(value);
    if (key === 'DTEND') event.end = parseIcsDate(value);
  }
  return busy;
}

async function fetchIcsBusy(timeMin, timeMax, signal) {
  const min = new Date(timeMin);
  const max = new Date(timeMax);
  const lists = await Promise.all(BLOCKING_ICS_URLS.map(async (url) => {
    const res = await fetch(url, { signal });
    if (!res.ok) throw new Error('ics');
    return parseIcsBusy(await res.text()).filter((event) => {
      const start = new Date(event.start);
      const end = new Date(event.end);
      return start < max && end > min;
    });
  }));
  return lists.flat();
}

async function fetchDirectCalendarBusy(timeMin, timeMax, signal) {
  const lists = await Promise.all(BLOCKING_CALENDAR_IDS.map(async (calendarId) => {
    const params = new URLSearchParams({ calendarId, timeMin, timeMax });
    const res = await fetch(`${DIRECT_GOOGLE_PROXY}/google/events?${params}`, { signal });
    if (!res.ok) throw new Error('direct-calendar');
    const events = await res.json();
    return Array.isArray(events)
      ? events
        .filter((event) => event.status !== 'cancelled' && event.start && event.end)
        .map((event) => ({ start: event.start, end: event.end, calendarId }))
      : [];
  }));
  return lists.flat();
}

async function fetchBookingAvailability(timeMin, timeMax, signal) {
  try {
    const params = new URLSearchParams({
      action: 'availability',
      timeMin,
      timeMax,
    });
    const endpoint = isLocalHost()
      ? `https://eidoraprojects.com/calendar.php?${params}`
      : `/calendar.php?${params}`;
    const res = await fetch(endpoint, { signal, credentials: isLocalHost() ? 'omit' : 'same-origin' });
    if (!res.ok) throw new Error('calendar');
    const data = await res.json();
    return {
      busy: Array.isArray(data.busy) ? data.busy : [],
      source: data.source || 'unknown',
    };
  } catch (err) {
    if (err.name === 'AbortError') throw err;
    return {
      busy: await fetchIcsBusy(timeMin, timeMax, signal),
      source: 'ics',
    };
  }
}

async function fetchGoogleCalendarHealth(signal) {
  try {
    const endpoint = isLocalHost()
      ? 'https://eidoraprojects.com/calendar.php?action=health'
      : '/calendar.php?action=health';
    const res = await fetch(endpoint, { signal, credentials: isLocalHost() ? 'omit' : 'same-origin' });
    if (!res.ok) throw new Error('calendar-health');
    const data = await res.json();
    return data?.google?.connected === true;
  } catch (_) {
    return false;
  }
}

async function createBookingEvent(payload) {
  if (isLocalHost()) {
    try {
      const res = await fetch('https://eidoraprojects.com/calendar.php?action=book', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload),
      });
      const data = await res.json().catch(() => ({}));
      if (res.ok) return { res, data };
    } catch (_) {}

    return {
      res: { ok: true },
      data: {
        fallbackSent: true,
        localMailto: buildBookingFallbackMailto(payload),
      },
    };
  }

  const res = await fetch('/calendar.php?action=book', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  });
  const data = await res.json().catch(() => ({}));
  return { res, data };
}

function buildBookingFallbackMailto(payload) {
  const start = new Date(payload.start);
  const end = new Date(payload.end);
  const dateLabel = `${start.toLocaleDateString('es-ES', { day: 'numeric', month: 'long', year: 'numeric' })} · ${pad2(start.getHours())}:00-${pad2(end.getHours())}:00`;
  const subject = `Solicitud de cita EIDORA pendiente - ${payload.name}`;
  const body = [
    'Solicitud de cita recibida desde eidoraprojects.com',
    '',
    `Nombre: ${payload.name}`,
    `Email: ${payload.email}`,
    `Telefono: ${payload.phone}`,
    `Fecha: ${dateLabel} (Europe/Madrid)`,
    'Google Meet: Joaquin enviara el enlace cuando confirme la cita.',
    '',
    `Info del proyecto: ${payload.notes || '-'}`,
  ].join('\n');

  return `mailto:info@eidoraprojects.com?cc=${encodeURIComponent(payload.email)}&subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
}

function Contact() {
  const t = window.useT();
  const photo = LR_IMAGES.pick('1745358941246.jpg');
  const [status, setStatus] = React.useState('idle'); // idle | sending | ok | error
  const [errorMsg, setErrorMsg] = React.useState('');
  const [mode, setMode] = React.useState('meeting'); // meeting | brief
  const [bookingStep, setBookingStep] = React.useState('date'); // date | time | details | booked
  const [calendarMonth, setCalendarMonth] = React.useState(() => new Date());
  const bookingDays = React.useMemo(() => buildBookingDays(30), []);
  const monthDays = React.useMemo(() => buildMonthDays(calendarMonth), [calendarMonth]);
  const [selectedDate, setSelectedDate] = React.useState(() => toDateKey(bookingDays[0]));
  const [selectedTime, setSelectedTime] = React.useState('');
  const [calendarEvents, setCalendarEvents] = React.useState([]);
  const [calendarStatus, setCalendarStatus] = React.useState('idle'); // idle | loading | ok | error
  const [googleConnectionStatus, setGoogleConnectionStatus] = React.useState('unknown'); // unknown | loading | connected | fallback
  const [bookingStatus, setBookingStatus] = React.useState('idle'); // idle | sending | ok | error
  const [bookingError, setBookingError] = React.useState('');
  const [bookedEvent, setBookedEvent] = React.useState(null);
  const [copiedMeetLink, setCopiedMeetLink] = React.useState(false);
  const mountedAt = React.useRef(Date.now());

  React.useEffect(() => {
    if (!window.gsap) return;
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
    const ctx = gsap.context(() => {
      gsap.from('.contact-section h2, .contact-section p, .contact-section ul, .contact-section form', {
        y: 24, opacity: 0, duration: 0.7, ease: 'expo.out', stagger: 0.08,
        scrollTrigger: { trigger: '.contact-section', start: 'top 75%', once: true },
      });
    });
    return () => ctx.revert();
  }, []);

  React.useEffect(() => {
    if (mode !== 'meeting') return;
    const controller = new AbortController();
    const timeMin = new Date().toISOString();
    const timeMax = addMinutes(bookingDays[bookingDays.length - 1], 24 * 60).toISOString();
    setCalendarStatus('loading');
    setGoogleConnectionStatus('loading');
    fetchGoogleCalendarHealth(controller.signal)
      .then((connected) => {
        setGoogleConnectionStatus(connected ? 'connected' : 'fallback');
      });
    fetchBookingAvailability(timeMin, timeMax, controller.signal)
      .then(({ busy, source }) => {
        setCalendarEvents(busy);
        setCalendarStatus('ok');
        if (source === 'oauth') setGoogleConnectionStatus('connected');
      })
      .catch((err) => {
        if (err.name === 'AbortError') return;
        setCalendarStatus('error');
        setGoogleConnectionStatus('fallback');
      });

    return () => controller.abort();
  }, [mode, bookingDays]);

  React.useEffect(() => {
    if (mode !== 'meeting') return;
    const controller = new AbortController();
    let stopped = false;

    const checkHealth = () => {
      fetchGoogleCalendarHealth(controller.signal)
        .then((connected) => {
          if (stopped) return;
          setGoogleConnectionStatus(connected ? 'connected' : 'fallback');
        });
    };
    const checkHealthIfVisible = () => {
      if (document.visibilityState !== 'hidden') checkHealth();
    };

    checkHealth();
    const interval = window.setInterval(checkHealth, GOOGLE_HEALTH_CHECK_INTERVAL);
    window.addEventListener('focus', checkHealth);
    window.addEventListener('online', checkHealth);
    document.addEventListener('visibilitychange', checkHealthIfVisible);
    return () => {
      stopped = true;
      window.clearInterval(interval);
      window.removeEventListener('focus', checkHealth);
      window.removeEventListener('online', checkHealth);
      document.removeEventListener('visibilitychange', checkHealthIfVisible);
      controller.abort();
    };
  }, [mode]);

  const getSlotsForDate = React.useCallback((dateKey) => {
    const now = new Date();
    return BOOKING_HOURS.map((hour) => {
      const start = fromDateKey(dateKey, hour);
      const end = addMinutes(start, BOOKING_DURATION_MINUTES);
      const isPast = start.getTime() <= now.getTime() + 2 * 60 * 60 * 1000;
      const busy = calendarEvents.some((event) => {
        const eventStart = new Date(event.start);
        const eventEnd = new Date(event.end);
        return start < eventEnd && end > eventStart;
      });
      return { hour, label: `${pad2(hour)}:00`, disabled: isPast || busy };
    });
  }, [calendarEvents]);

  const availableDays = React.useMemo(() => {
    if (calendarStatus === 'loading') return [];
    const daysWithSlots = bookingDays.filter((date) =>
      getSlotsForDate(toDateKey(date)).some((slot) => !slot.disabled)
    );
    return daysWithSlots.length > 0 ? daysWithSlots : bookingDays;
  }, [bookingDays, calendarStatus, getSlotsForDate]);

  React.useEffect(() => {
    if (calendarStatus === 'loading' || availableDays.length === 0) return;
    if (!availableDays.some((date) => toDateKey(date) === selectedDate)) {
      setSelectedDate(toDateKey(availableDays[0]));
      setSelectedTime('');
    }
  }, [availableDays, calendarStatus, selectedDate]);

  const availableTimes = React.useMemo(() => getSlotsForDate(selectedDate), [getSlotsForDate, selectedDate]);

  const onBookingSubmit = async (e) => {
    e.preventDefault();
    if (bookingStatus === 'sending' || !selectedTime) return;
    setBookingStatus('sending');
    setBookingError('');

    const form = e.currentTarget;
    const fd = new FormData(form);
    const nombre = String(fd.get('booking_nombre') || '').trim();
    const email = String(fd.get('booking_email') || '').trim();
    const telefono = String(fd.get('booking_phone') || '').trim();
    const notas = String(fd.get('booking_notes') || '').trim();
    const start = fromDateKey(selectedDate, Number(selectedTime));
    const end = addMinutes(start, BOOKING_DURATION_MINUTES);

    try {
      const { res, data } = await createBookingEvent({
        name: nombre,
        email,
        phone: telefono,
        notes: notas,
        calendarId: CITAS_LOOKRENDER_CALENDAR_ID,
        start: start.toISOString(),
        end: end.toISOString(),
      });
      if (!res.ok || (!data.id && !data.hangoutLink && !data.fallbackSent)) throw new Error('booking');
      if (data.localMailto) window.location.href = data.localMailto;
      setBookedEvent(data);
      setBookingStatus('ok');
      setBookingStep('booked');
      form.reset();
    } catch (_) {
      setBookingStatus('error');
      setBookingError('No hemos podido reservar la cita. Escríbenos a info@eidoraprojects.com y lo cerramos manualmente.');
    }
  };

  const copyMeetingLink = async () => {
    if (!bookedEvent?.hangoutLink) return;
    try {
      await navigator.clipboard.writeText(bookedEvent.hangoutLink);
    } catch (_) {
      const input = document.createElement('input');
      input.value = bookedEvent.hangoutLink;
      input.setAttribute('readonly', '');
      input.style.position = 'fixed';
      input.style.opacity = '0';
      document.body.appendChild(input);
      input.select();
      document.execCommand('copy');
      document.body.removeChild(input);
    }
    setCopiedMeetLink(true);
    window.setTimeout(() => setCopiedMeetLink(false), 2200);
  };

  const onSubmit = async (e) => {
    e.preventDefault();
    if (status === 'sending') return;
    setStatus('sending');
    setErrorMsg('');
    const form = e.currentTarget;
    const fd = new FormData(form);
    fd.append('ttp', String(Date.now() - mountedAt.current));
    try {
      const contactEndpoint = isLocalHost() ? 'https://eidoraprojects.com/contact.php' : '/contact.php';
      const res = await fetch(contactEndpoint, {
        method: 'POST',
        body: new URLSearchParams(fd),
        headers: { 'Accept': 'application/json' },
        credentials: isLocalHost() ? 'omit' : 'same-origin',
      });
      const data = await res.json().catch(() => ({}));
      if (res.ok && data.ok) {
        setStatus('ok');
        form.reset();
      } else {
        setStatus('error');
        const map = {
          rate:       t('contact.form.error.rate'),
          validation: t('contact.form.error.validation'),
          injection:  t('contact.form.error.injection'),
          method:     t('contact.form.error.method'),
          origin:     t('contact.form.error.origin'),
          referer:    t('contact.form.error.origin'),
          payload:    t('contact.form.error.payload'),
          send:       t('contact.form.error.send'),
        };
        setErrorMsg(map[data.error] || t('contact.form.error.default'));
      }
    } catch (_) {
      setStatus('error');
      setErrorMsg(t('contact.form.error.network'));
    }
  };

  return (
    <section id="conversemos" data-screen-label="06 Hablemos" className="contact-section" aria-label={t('contact.aria_label')} style={{
      background: 'var(--lr-tierra-profunda)',
      color: 'var(--lr-cal-blanca)',
      padding: 'clamp(48px, 4vw, 80px) clamp(24px, 4vw, 56px) clamp(48px, 4vw, 80px)',
      position: 'relative', overflow: 'hidden',
    }}>
      <div role="img" aria-label={t('contact.aria_label')} style={{
        position: 'absolute', inset: 0,
        backgroundImage: `url(${photo.src})`,
        backgroundSize: 'cover', backgroundPosition: 'center',
        opacity: 0.18, filter: 'saturate(0.7)',
      }} />
      <div style={{ maxWidth: 1320, margin: '0 auto', position: 'relative' }}>
        <div className="contact-header-grid" style={{ display: 'grid', gridTemplateColumns: '320px 1fr', gap: 64, alignItems: 'flex-end', marginBottom: 'clamp(20px, 2vw, 36px)' }}>
          <div>
            <div style={{
              fontFamily: 'var(--font-ui)', fontWeight: 700, fontSize: 11,
              letterSpacing: '0.32em', textTransform: 'uppercase',
              color: 'var(--lr-arena-calida)', marginBottom: 16,
            }}>{t('contact.header.label')}</div>
          </div>
          <h2 style={{
            fontFamily: 'var(--font-display)', fontWeight: 400,
            fontSize: 'clamp(32px, 3.8vw, 56px)', lineHeight: 1.08,
            letterSpacing: '-0.022em',
            color: 'var(--lr-cal-blanca)', margin: 0, maxWidth: 1100,
          }}>
            {t('contact.header.title').replace(t('contact.header.cta'), '').trimEnd()}
            {' '}<em style={{ fontFamily: 'var(--font-italic)', fontStyle: 'italic', color: 'var(--lr-arena-calida)' }}>{t('contact.header.cta')}</em>
          </h2>
        </div>

        <div className="contact-body-grid" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 'clamp(40px, 4vw, 80px)' }}>
          <div>
            <p style={{ fontFamily: 'var(--font-body)', fontSize: 17, lineHeight: 1.55, color: 'rgba(243,238,231,0.85)', margin: '0 0 clamp(28px, 3vw, 44px)', maxWidth: '52ch', whiteSpace: 'pre-line' }}>
              {t('contact.body.description')}
            </p>
            <ul style={{ listStyle: 'none', padding: 0, margin: 0,
              borderTop: '1px solid rgba(243,238,231,0.18)' }}>
              {[
                [t('contact.nap.email.label'),  'info@eidoraprojects.com',  'mailto:info@eidoraprojects.com'],
                [t('contact.nap.phone.label'),  '+34 614 32 55 64',         'tel:+34614325564'],
                [t('contact.nap.studio.label'), t('contact.nap.studio.value'), null],
              ].map(([k, v, href], i) => (
                <li key={i} className="contact-nap-item" style={{
                  display: 'grid', gridTemplateColumns: '180px 1fr',
                  padding: '20px 0',
                  borderBottom: '1px solid rgba(243,238,231,0.18)',
                }}>
                  <span style={{
                    fontFamily: 'var(--font-ui)', fontWeight: 700, fontSize: 10,
                    letterSpacing: '0.32em', textTransform: 'uppercase',
                    color: 'var(--lr-arena-calida)',
                  }}>{k}</span>
                  {href ? (
                    <a href={href}
                      target={href.startsWith('http') ? '_blank' : undefined}
                      rel={href.startsWith('http') ? 'noopener noreferrer' : undefined}
                      style={{
                        fontFamily: 'var(--font-display)', fontSize: 22, fontWeight: 400,
                        color: 'var(--lr-cal-blanca)', letterSpacing: '-0.01em',
                        textDecoration: 'none', borderBottom: 'none',
                      }}>{v}</a>
                  ) : (
                    <span style={{
                      fontFamily: 'var(--font-display)', fontSize: 22, fontWeight: 400,
                      color: 'var(--lr-cal-blanca)', letterSpacing: '-0.01em',
                    }}>{v}</span>
                  )}
                </li>
              ))}
            </ul>
          </div>

          <div className="contact-form" style={{
            background: 'rgba(243,238,231,0.14)', padding: 'clamp(28px, 2.6vw, 40px) clamp(24px, 2.6vw, 40px) clamp(24px, 2.4vw, 36px)',
            borderTop: '1px solid var(--lr-terracota)',
          }}>
            {/* Tabs: Agendar cita / Enviar briefing */}
            <div role="tablist" aria-label={t('contact.modes.label')} className="contact-mode-tabs" style={{
              display: 'grid', gridTemplateColumns: '1fr 1fr',
              borderBottom: '1px solid rgba(243,238,231,0.18)',
              marginBottom: 24,
            }}>
              {[
                { key: 'meeting', label: t('contact.modes.meeting') },
                { key: 'brief',   label: t('contact.modes.brief') },
              ].map((m) => {
                const active = mode === m.key;
                return (
                  <button key={m.key} type="button" role="tab" aria-selected={active}
                    onClick={() => setMode(m.key)}
                    style={{
                      fontFamily: 'var(--font-ui)', fontWeight: 700, fontSize: 11,
                      letterSpacing: '0.28em', textTransform: 'uppercase',
                      color: active ? 'var(--lr-arena-calida)' : 'rgba(243,238,231,0.5)',
                      background: 'transparent', border: 'none',
                      borderBottom: active ? '2px solid var(--lr-terracota)' : '2px solid transparent',
                      padding: '14px 8px', cursor: 'pointer', minHeight: 44,
                      transition: 'color 220ms var(--ease-standard), border-color 220ms',
                    }}>
                    {m.label}
                  </button>
                );
              })}
            </div>

            <div role="tabpanel" style={{
              overflow: 'hidden',
              display: mode === 'meeting' ? 'block' : 'none',
              border: '1px solid rgba(243,238,231,0.24)',
              background: 'var(--eidora-lino)',
              color: 'var(--eidora-cafe)',
            }}>
              <div className="booking-shell">
                <div className="booking-steps" aria-label="Pasos de reserva">
                  {[
                    ['date', '01', 'Fecha'],
                    ['time', '02', 'Hora'],
                    ['details', '03', 'Datos'],
                  ].map(([key, number, label]) => (
                    <button
                      key={key}
                      type="button"
                      disabled={key === 'time' && !selectedDate || key === 'details' && !selectedTime || bookingStep === 'booked'}
                      onClick={() => setBookingStep(key)}
                      className={bookingStep === key ? 'booking-step is-active' : 'booking-step'}
                    >
                      <span>{number}</span>{label}
                    </button>
                  ))}
                </div>

                <div className="booking-panels">
                {bookingStep === 'date' && (
                  <div className="booking-panel booking-panel-date">
                    <div className="booking-panel-head booking-panel-head-row">
                      <h3>Selecciona fecha</h3>
                      <span
                        className={`booking-google-dot ${googleConnectionStatus === 'connected' ? 'is-connected' : ''} ${googleConnectionStatus === 'loading' ? 'is-loading' : ''}`}
                        aria-label={googleConnectionStatus === 'connected'
                          ? 'Google conectado. Se creará Google Meet automáticamente.'
                          : googleConnectionStatus === 'loading'
                            ? 'Comprobando conexión con Google.'
                            : 'Google no conectado. La cita se confirmará manualmente por email.'}
                        title={googleConnectionStatus === 'connected'
                          ? 'Google conectado: se creará Google Meet automáticamente.'
                          : googleConnectionStatus === 'loading'
                            ? 'Comprobando conexión con Google.'
                            : 'Google no conectado: se enviará la solicitud por email para confirmación manual.'}
                      />
                    </div>
                    {calendarStatus === 'loading' && <p className="booking-note">Cargando días disponibles...</p>}
                    <div className="booking-month-head">
                      <button
                        type="button"
                        aria-label="Mes anterior"
                        onClick={() => setCalendarMonth(new Date(calendarMonth.getFullYear(), calendarMonth.getMonth() - 1, 1))}
                      >‹</button>
                      <strong>{calendarMonth.toLocaleDateString('es-ES', { month: 'long', year: 'numeric' })}</strong>
                      <button
                        type="button"
                        aria-label="Mes siguiente"
                        onClick={() => setCalendarMonth(new Date(calendarMonth.getFullYear(), calendarMonth.getMonth() + 1, 1))}
                      >›</button>
                    </div>
                    <div className="booking-weekdays" aria-hidden="true">
                      {['L', 'M', 'X', 'J', 'V', 'S', 'D'].map((day) => <span key={day}>{day}</span>)}
                    </div>
                    <div className="booking-date-grid booking-month-grid">
                      {monthDays.map((date, index) => {
                        if (!date) return <span key={`blank-${index}`} className="booking-date-blank" />;
                        const dateKey = toDateKey(date);
                        const active = selectedDate === dateKey;
                        const todayKey = toDateKey(new Date());
                        const isPast = dateKey < todayKey;
                        const isWeekend = date.getDay() === 0 || date.getDay() === 6;
                        const hasSlots = availableDays.some((availableDate) => toDateKey(availableDate) === dateKey);
                        const disabled = isPast || isWeekend || !hasSlots;
                        return (
                          <button
                            type="button"
                            key={dateKey}
                            disabled={disabled}
                            className={[
                              'booking-date',
                              active ? 'is-active' : '',
                              isPast ? 'is-past' : '',
                              isWeekend ? 'is-weekend' : '',
                              !hasSlots && !isPast && !isWeekend ? 'is-unavailable' : '',
                            ].filter(Boolean).join(' ')}
                            onClick={() => {
                              if (disabled) return;
                              setSelectedDate(dateKey);
                              setSelectedTime('');
                              setBookingStep('time');
                            }}
                          >
                            <strong>{date.getDate()}</strong>
                          </button>
                        );
                      })}
                    </div>
                  </div>
                )}

                {bookingStep === 'time' && (
                  <div className="booking-panel">
                    <div className="booking-panel-head">
                      <h3>Selecciona hora</h3>
                      <p>{fromDateKey(selectedDate, 12).toLocaleDateString('es-ES', { day: 'numeric', month: 'long', year: 'numeric' })} · Hora de Madrid</p>
                    </div>
                    {calendarStatus === 'loading' && <p className="booking-note">Consultando disponibilidad...</p>}
                    {calendarStatus === 'error' && <p className="booking-note">No se pudo consultar Google Calendar. Puedes elegir hora y la confirmaremos manualmente.</p>}
                    <div className="booking-time-grid">
                      {availableTimes.map((slot) => (
                        <button
                          type="button"
                          key={slot.hour}
                          disabled={slot.disabled}
                          className={selectedTime === String(slot.hour) ? 'booking-time is-active' : 'booking-time'}
                          onClick={() => {
                            setSelectedTime(String(slot.hour));
                            setBookingStep('details');
                          }}
                        >
                          {slot.label}
                        </button>
                      ))}
                    </div>
                  </div>
                )}

                {bookingStep === 'details' && (
                  <form className="booking-panel booking-details" onSubmit={onBookingSubmit}>
                    <div className="booking-panel-head">
                      <h3>Confirma tus datos</h3>
                      <p>{fromDateKey(selectedDate, Number(selectedTime)).toLocaleDateString('es-ES', { day: 'numeric', month: 'long' })} · {pad2(selectedTime)}:00 · Google Meet</p>
                    </div>
                    <label>Nombre<input name="booking_nombre" type="text" required autoComplete="name" /></label>
                    <label>Email<input name="booking_email" type="email" required autoComplete="email" /></label>
                    <label>Teléfono<input name="booking_phone" type="tel" required autoComplete="tel" /></label>
                    <label>Info del proyecto<textarea name="booking_notes" rows="3" /></label>
                    <div aria-hidden="true" style={{ position: 'absolute', left: '-9999px', width: 1, height: 1, overflow: 'hidden' }}>
                      <label>Website<input name="website" type="text" tabIndex={-1} autoComplete="off" /></label>
                    </div>
                    <button type="submit" disabled={bookingStatus === 'sending'}>
                      {bookingStatus === 'sending' ? 'Reservando...' : 'Confirmar cita'}
                    </button>
                    {bookingStatus === 'error' && <p className="booking-error" role="alert">{bookingError}</p>}
                  </form>
                )}

                {bookingStep === 'booked' && (
                  <div className="booking-panel booking-success">
                    <h3>{bookedEvent?.fallbackSent ? 'Solicitud recibida' : 'Cita reservada'}</h3>
                    <p>{bookedEvent?.fallbackSent ? 'Hemos enviado la solicitud por email. Joaquin enviará el enlace de reunión cuando confirme la cita.' : 'Hemos creado la reunión en Google Calendar y enviado la confirmación por email.'}</p>
                    {bookedEvent?.hangoutLink && (
                      <div className="booking-success-actions">
                        <button type="button" onClick={copyMeetingLink}>
                          {copiedMeetLink ? 'Enlace copiado' : 'Copiar enlace de reunión'}
                        </button>
                        <a href={bookedEvent.hangoutLink} target="_blank" rel="noopener noreferrer">Abrir Google Meet</a>
                      </div>
                    )}
                  </div>
                )}
                </div>
              </div>
            </div>

            <div style={{
              display: mode === 'brief' ? 'block' : 'none',
              background: 'var(--eidora-lino)',
              color: 'var(--eidora-cafe)',
              border: '1px solid rgba(243,238,231,0.24)',
            }}>
            <form onSubmit={onSubmit} noValidate autoComplete="on" style={{
              boxSizing: 'border-box',
              minHeight: 700,
              padding: 'clamp(24px, 2.6vw, 36px)',
            }}>
            <div style={{
              fontFamily: 'var(--font-ui)', fontWeight: 700, fontSize: 11,
              letterSpacing: '0.32em', textTransform: 'uppercase',
              color: 'var(--eidora-cafe)', marginBottom: 24,
            }}>{t('contact.form.title')}</div>

            {/* Honeypot - invisible para humanos, los bots lo rellenan */}
            <div aria-hidden="true" style={{
              position: 'absolute', left: '-9999px', top: 'auto',
              width: 1, height: 1, overflow: 'hidden',
            }}>
              <label htmlFor="website">{t('contact.form.honeypot.label')}</label>
              <input id="website" name="website" type="text" tabIndex={-1} autoComplete="off" defaultValue="" />
            </div>

            {[
              { id: 'nombre',   label: t('contact.form.nombre.label'),   type: 'text',  ac: 'name',         required: true,  max: 200 },
              { id: 'email',    label: t('contact.form.email.label'),    type: 'email', ac: 'email',        required: true,  max: 200 },
              { id: 'proyecto', label: t('contact.form.proyecto.label'), type: 'text',  ac: 'organization', required: false, max: 500 },
            ].map(({ id, label, type, ac, required, max }) => (
              <div key={id} style={{ marginBottom: 16 }}>
                <label htmlFor={id} style={{
                  display: 'block',
                  fontFamily: 'var(--font-ui)', fontWeight: 600, fontSize: 10,
                  letterSpacing: '0.24em', textTransform: 'uppercase',
                  color: 'var(--lr-tierra-500)', marginBottom: 8,
                }}>{label}{required ? ' *' : ''}</label>
                <input
                  id={id} name={id} type={type}
                  required={required} maxLength={max}
                  autoComplete={ac}
                  inputMode={type === 'email' ? 'email' : undefined}
                  spellCheck={type === 'email' ? false : undefined}
                  style={{
                    width: '100%', padding: '12px 0',
                    background: 'rgba(250,250,247,0.38)', color: 'var(--eidora-cafe)',
                    border: '1px solid rgba(61,53,48,0.22)', borderRadius: 'var(--radius-xs)',
                    fontFamily: 'var(--font-body)', fontSize: 16,
                    outline: 'none',
                    padding: '12px 14px',
                  }} />
              </div>
            ))}
            <div style={{ marginBottom: 16 }}>
              <label htmlFor="mensaje" style={{
                display: 'block',
                fontFamily: 'var(--font-ui)', fontWeight: 600, fontSize: 10,
                letterSpacing: '0.24em', textTransform: 'uppercase',
                color: 'var(--lr-tierra-500)', marginBottom: 8,
              }}>{t('contact.form.mensaje.label')}</label>
              <textarea id="mensaje" name="mensaje" rows="3" maxLength={5000} style={{
                width: '100%', padding: '12px 14px',
                background: 'rgba(250,250,247,0.38)', color: 'var(--eidora-cafe)',
                border: '1px solid rgba(61,53,48,0.22)', borderRadius: 'var(--radius-xs)',
                fontFamily: 'var(--font-body)', fontSize: 16,
                resize: 'vertical', outline: 'none',
              }} />
            </div>

            <button type="submit" disabled={status === 'sending' || status === 'ok'}
              onMouseEnter={(e) => { if (status === 'idle' || status === 'error') e.currentTarget.style.background = 'var(--lr-terracota-700)'; }}
              onMouseLeave={(e) => { if (status === 'idle' || status === 'error') e.currentTarget.style.background = 'var(--lr-terracota)'; }}
              style={{
              fontFamily: 'var(--font-ui)', fontWeight: 700, fontSize: 12,
              letterSpacing: '0.18em', textTransform: 'uppercase',
              background: status === 'ok' ? 'rgba(61,53,48,0.18)' : 'var(--eidora-terracota)',
              color: 'var(--eidora-hueso)',
              border: 'none', borderRadius: 2,
              padding: '20px 36px',
              minHeight: 44,
              cursor: status === 'sending' ? 'wait' : (status === 'ok' ? 'default' : 'pointer'),
              marginTop: 12,
              opacity: status === 'sending' ? 0.7 : 1,
              transition: 'background 240ms var(--ease-standard), opacity 240ms',
            }}>
              {status === 'sending' && t('contact.form.submit.sending')}
              {status === 'ok' && t('contact.form.submit.success')}
              {(status === 'idle' || status === 'error') && t('contact.form.submit.idle')}
            </button>

            {status === 'ok' && (
              <div role="status" style={{
                marginTop: 18,
                fontFamily: 'var(--font-body)', fontSize: 14, lineHeight: 1.55,
                color: 'var(--lr-tierra-500)',
              }}>{t('contact.form.success_message')}</div>
            )}
            {status === 'error' && (
              <div role="alert" style={{
                marginTop: 18,
                fontFamily: 'var(--font-body)', fontSize: 14, lineHeight: 1.55,
                color: 'var(--eidora-cafe)',
                padding: '10px 14px',
                background: 'rgba(185, 120, 87, 0.18)',
                borderLeft: '2px solid var(--lr-terracota)',
              }}>{errorMsg}</div>
            )}
            </form>
            </div>
          </div>
        </div>
      </div>

      <style>{`
        .contact-form input:focus-visible,
        .contact-form textarea:focus-visible {
          outline: none;
          border-bottom-color: var(--lr-terracota) !important;
          border-bottom-width: 2px !important;
          padding-bottom: 11px !important;
        }
        .contact-form button[type="submit"]:active {
          transform: scale(0.97);
          transition: transform 80ms var(--ease-standard);
        }
        .booking-shell {
          box-sizing: border-box;
          padding: clamp(24px, 2.6vw, 36px);
          height: 700px;
        }
        .booking-steps {
          display: grid;
          grid-template-columns: repeat(3, 1fr);
          gap: 1px;
          margin-bottom: 28px;
          border-bottom: 1px solid rgba(61,53,48,0.18);
        }
        .booking-panels {
          min-height: 548px;
        }
        .booking-panel {
          min-height: 548px;
        }
        .booking-panel-date {
          display: flex;
          flex-direction: column;
        }
        .booking-step {
          border: 0;
          background: transparent;
          color: rgba(61,53,48,0.55);
          font-family: var(--font-ui);
          font-size: 10px;
          font-weight: 700;
          letter-spacing: 0.22em;
          min-height: 44px;
          padding: 0 8px 14px;
          text-transform: uppercase;
        }
        .booking-step span {
          display: block;
          margin-bottom: 6px;
          letter-spacing: 0;
        }
        .booking-step.is-active {
          color: var(--eidora-cafe);
          border-bottom: 2px solid var(--eidora-terracota);
        }
        .booking-panel-head h3,
        .booking-success h3 {
          color: var(--eidora-cafe);
          font-family: var(--font-display);
          font-size: clamp(28px, 2.4vw, 38px);
          font-weight: 400;
          letter-spacing: -0.01em;
          line-height: 1.1;
          margin: 0 0 8px;
        }
        .booking-panel-head-row {
          align-items: flex-start;
          display: flex;
          gap: 12px;
          justify-content: space-between;
        }
        .booking-google-dot {
          background: var(--eidora-lino);
          border: 1px solid var(--eidora-cafe);
          border-radius: var(--radius-pill);
          flex: 0 0 auto;
          height: 10px;
          margin-top: 14px;
          width: 10px;
        }
        .booking-google-dot.is-connected {
          background: var(--eidora-cafe);
        }
        .booking-google-dot.is-loading {
          background: var(--eidora-lino);
          border-color: var(--eidora-terracota);
        }
        .booking-panel-head p,
        .booking-success p,
        .booking-note {
          color: var(--lr-tierra-500);
          font-family: var(--font-body);
          font-size: 15px;
          line-height: 1.55;
          margin: 0 0 24px;
        }
        .booking-date-grid {
          display: grid;
          grid-template-columns: repeat(7, 1fr);
          gap: 8px;
        }
        .booking-month-head {
          align-items: center;
          border-bottom: 1px solid rgba(61,53,48,0.14);
          display: grid;
          grid-template-columns: 44px 1fr 44px;
          margin-bottom: 12px;
          padding-bottom: 12px;
        }
        .booking-month-head strong {
          color: var(--eidora-cafe);
          font-family: var(--font-ui);
          font-size: 11px;
          font-weight: 700;
          letter-spacing: 0.18em;
          text-align: center;
          text-transform: uppercase;
        }
        .booking-month-head button {
          background: transparent;
          border: 1px solid rgba(61,53,48,0.18);
          border-radius: var(--radius-xs);
          color: var(--eidora-cafe);
          cursor: pointer;
          font-family: var(--font-display);
          font-size: 24px;
          height: 36px;
          line-height: 1;
          padding: 0;
        }
        .booking-weekdays {
          display: grid;
          grid-template-columns: repeat(7, 1fr);
          gap: 8px;
          margin-bottom: 8px;
        }
        .booking-weekdays span {
          color: var(--lr-tierra-500);
          font-family: var(--font-ui);
          font-size: 9px;
          font-weight: 700;
          letter-spacing: 0.14em;
          text-align: center;
        }
        .booking-date-blank {
          min-height: 48px;
        }
        .booking-date,
        .booking-time {
          background: rgba(250,250,247,0.42);
          border: 1px solid rgba(61,53,48,0.18);
          border-radius: var(--radius-xs);
          color: var(--eidora-cafe);
          cursor: pointer;
          font-family: var(--font-body);
          min-height: 64px;
          padding: 9px 6px;
          transition: border-color 180ms var(--ease-standard), background 180ms var(--ease-standard);
        }
        .booking-date {
          align-items: center;
          display: flex;
          justify-content: center;
          min-height: 48px;
        }
        .booking-date span,
        .booking-date small {
          display: block;
          color: var(--lr-tierra-500);
          font-family: var(--font-ui);
          font-size: 9px;
          font-weight: 700;
          letter-spacing: 0.14em;
          text-transform: uppercase;
        }
        .booking-date strong {
          display: block;
          font-family: var(--font-display);
          font-size: 22px;
          font-weight: 400;
          line-height: 1.1;
        }
        .booking-date.is-past,
        .booking-date.is-weekend,
        .booking-date.is-unavailable {
          background: rgba(61,53,48,0.05);
          border-color: rgba(61,53,48,0.08);
          color: rgba(61,53,48,0.28);
          cursor: not-allowed;
        }
        .booking-date.is-active,
        .booking-time.is-active {
          background: var(--eidora-cafe);
          border-color: var(--eidora-cafe);
          color: var(--eidora-hueso);
        }
        .booking-date.is-active span,
        .booking-date.is-active small {
          color: rgba(250,250,247,0.72);
        }
        .booking-time-grid {
          display: grid;
          grid-template-columns: repeat(3, 1fr);
          gap: 10px;
        }
        .booking-time {
          font-family: var(--font-ui);
          font-size: 12px;
          font-weight: 700;
          letter-spacing: 0.12em;
          min-height: 54px;
        }
        .booking-time:disabled,
        .booking-step:disabled {
          cursor: not-allowed;
          opacity: 0.34;
        }
        .booking-details {
          display: grid;
          gap: 10px;
        }
        .booking-details label {
          color: var(--lr-tierra-500);
          display: grid;
          font-family: var(--font-ui);
          font-size: 10px;
          font-weight: 700;
          gap: 7px;
          letter-spacing: 0.22em;
          text-transform: uppercase;
        }
        .booking-details input,
        .booking-details textarea {
          background: rgba(250,250,247,0.38);
          border: 1px solid rgba(61,53,48,0.22);
          border-radius: var(--radius-xs);
          color: var(--eidora-cafe);
          font-family: var(--font-body);
          font-size: 16px;
          letter-spacing: 0;
          padding: 10px 14px;
          text-transform: none;
        }
        .booking-details textarea {
          min-height: 84px;
          resize: vertical;
        }
        .booking-details button,
        .booking-success button,
        .booking-success a {
          align-items: center;
          background: var(--eidora-terracota);
          border: 0;
          border-radius: var(--radius-xs);
          color: var(--eidora-hueso);
          display: inline-flex;
          font-family: var(--font-ui);
          font-size: 12px;
          font-weight: 700;
          justify-content: center;
          letter-spacing: 0.18em;
          min-height: 42px;
          padding: 14px 28px;
          text-decoration: none;
          text-transform: uppercase;
        }
        .booking-success-actions {
          align-items: flex-start;
          display: flex;
          flex-direction: column;
          gap: 10px;
        }
        .booking-success a {
          background: transparent;
          border: 1px solid rgba(61,53,48,0.22);
          color: var(--eidora-cafe);
        }
        .booking-error {
          background: rgba(185,120,87,0.14);
          border-left: 2px solid var(--eidora-terracota);
          color: var(--eidora-cafe);
          font-family: var(--font-body);
          font-size: 14px;
          line-height: 1.5;
          margin: 0;
          padding: 10px 12px;
        }
      `}</style>
      <style>{`
        @media (max-width: 767px) {
          .contact-section {
            padding: 120px 24px 80px !important;
          }
          .contact-header-grid {
            grid-template-columns: 1fr !important;
          }
          .contact-body-grid {
            grid-template-columns: 1fr !important;
            gap: 56px !important;
          }
          .contact-form {
            padding: 28px 24px 24px !important;
          }
          .contact-nap-item span:last-child {
            overflow-wrap: anywhere !important;
            font-size: clamp(18px, 5vw, 22px) !important;
          }
          .contact-form button {
            width: 100% !important;
          }
          .booking-shell {
            height: auto !important;
            min-height: 560px !important;
          }
          .booking-panels,
          .booking-panel {
            min-height: 420px !important;
          }
          .booking-date-grid {
            grid-template-columns: repeat(3, 1fr) !important;
          }
          .booking-month-grid,
          .booking-weekdays {
            grid-template-columns: repeat(7, 1fr) !important;
          }
        }
        @media (max-width: 479px) {
          .contact-section {
            padding: 88px 16px 60px !important;
          }
          .contact-form {
            padding: 24px 18px 22px !important;
          }
          .contact-nap-item {
            grid-template-columns: 1fr !important;
            gap: 4px !important;
          }
          .contact-header-grid {
            gap: 28px !important;
            margin-bottom: 56px !important;
          }
          .booking-shell {
            padding: 22px 18px !important;
          }
          .booking-date-grid {
            grid-template-columns: repeat(2, 1fr) !important;
          }
          .booking-month-grid,
          .booking-weekdays {
            grid-template-columns: repeat(7, 1fr) !important;
            gap: 5px !important;
          }
          .booking-date {
            min-height: 42px !important;
            padding: 6px 4px !important;
          }
          .booking-date strong {
            font-size: 19px !important;
          }
          .booking-time-grid {
            grid-template-columns: repeat(2, 1fr) !important;
          }
        }
      `}</style>
    </section>
  );
}

window.Contact = Contact;
