import { useState, useEffect, useCallback } from 'react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner';
import { format, parseISO } from 'date-fns';
import {
  X, Pencil, Trash2, Save, Clock, MapPin, AlignLeft, Repeat, Star, Calendar, Loader2, LogOut,
} from 'lucide-react';
import axios from 'axios';
import api, { getErrorMessage } from '@/lib/api';
import type { CalendarEvent, Location as LocationType, RecurrenceRule, CalendarPermission, EventLockInfo } from '@/types';
import { useCalendars } from '@/hooks/useCalendars';
import { useConfirmAction } from '@/hooks/useConfirmAction';
import { useEventLock } from '@/hooks/useEventLock';
import { useEventInvitations, useConnectedUsersSearch } from '@/hooks/useEventInvitations';
import { formatUpdatedAt } from '@/components/shared/utils';
import CopyableField from '@/components/shared/CopyableField';
import EventLockBanner from './EventLockBanner';
import { InviteeList, InviteSearch, RsvpButtons } from './InviteeSection';
import LeaveEventDialog from './LeaveEventDialog';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { DatePicker } from '@/components/ui/date-picker';
import { Textarea } from '@/components/ui/textarea';
import { Select } from '@/components/ui/select';
import { Checkbox } from '@/components/ui/checkbox';
import { Label } from '@/components/ui/label';
import LocationPicker from '@/components/ui/location-picker';

// --- Helpers ---

function toDateOnly(dt: string): string {
  if (!dt) return '';
  return dt.split('T')[0];
}

function toDatetimeLocal(dt: string, fallbackTime = '09:00'): string {
  if (!dt) return '';
  if (dt.includes('T')) return dt.slice(0, 16);
  return `${dt}T${fallbackTime}`;
}

function formatForInput(dt: string, allDay: boolean, fallbackTime = '09:00'): string {
  if (!dt) return '';
  return allDay ? toDateOnly(dt) : toDatetimeLocal(dt, fallbackTime);
}

function adjustAllDayEndForDisplay(dateStr: string): string {
  if (!dateStr) return '';
  const d = new Date(dateStr.split('T')[0] + 'T12:00:00');
  d.setDate(d.getDate() - 1);
  const pad = (n: number) => n.toString().padStart(2, '0');
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
}

function adjustAllDayEndForSave(dateStr: string): string {
  if (!dateStr) return '';
  const d = new Date(dateStr + 'T12:00:00');
  d.setDate(d.getDate() + 1);
  const pad = (n: number) => n.toString().padStart(2, '0');
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
}

function nowLocal(): string {
  const now = new Date();
  const pad = (n: number) => n.toString().padStart(2, '0');
  return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}T${pad(now.getHours())}:${pad(now.getMinutes())}`;
}

function plusOneHour(dt: string): string {
  const d = new Date(dt);
  d.setHours(d.getHours() + 1);
  const pad = (n: number) => n.toString().padStart(2, '0');
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
}

function formatRecurrenceRule(rule: string): string {
  try {
    const parsed = JSON.parse(rule);
    const weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
    switch (parsed.type) {
      case 'every_n_days':
        return parsed.interval === 1 ? 'Every day' : `Every ${parsed.interval} days`;
      case 'weekly':
        return parsed.weekday != null ? `Weekly on ${weekdays[parsed.weekday]}` : 'Weekly';
      case 'monthly_nth_weekday':
        return parsed.week && parsed.weekday != null
          ? `Monthly on week ${parsed.week}, ${weekdays[parsed.weekday]}`
          : 'Monthly';
      case 'monthly_date':
        return parsed.day ? `Monthly on the ${parsed.day}${ordinal(parsed.day)}` : 'Monthly';
      default:
        return 'Recurring';
    }
  } catch {
    return 'Recurring';
  }
}

function ordinal(n: number): string {
  const s = ['th', 'st', 'nd', 'rd'];
  const v = n % 100;
  return s[(v - 20) % 10] || s[v] || s[0];
}

function parseRecurrenceRule(raw?: string): RecurrenceRule | null {
  if (!raw) return null;
  try {
    return JSON.parse(raw);
  } catch {
    return null;
  }
}

// Python weekday: 0=Monday, 6=Sunday
const WEEKDAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];

// --- Types ---

export interface CreateDefaults {
  start?: string;
  end?: string;
  allDay?: boolean;
  templateData?: Partial<CalendarEvent>;
  templateName?: string;
}

interface EventDetailPanelProps {
  event: CalendarEvent | null;
  isCreating?: boolean;
  createDefaults?: CreateDefaults | null;
  onClose: () => void;
  onSaved?: () => void;
  onDeleted?: () => void;
  locationName?: string;
  myPermission?: CalendarPermission | 'owner' | null;
  isSharedEvent?: boolean;
}

interface EditState {
  title: string;
  description: string;
  start_datetime: string;
  end_datetime: string;
  all_day: boolean;
  location_id: string;
  calendar_id: string;
  is_starred: boolean;
  recurrence_type: string;
  recurrence_interval: number;
  recurrence_weekday: number;
  recurrence_week: number;
  recurrence_day: number;
}

function buildEditStateFromEvent(event: CalendarEvent): EditState {
  const rule = parseRecurrenceRule(event.recurrence_rule);
  const isAllDay = event.all_day;
  const displayEnd = isAllDay ? adjustAllDayEndForDisplay(event.end_datetime) : event.end_datetime;
  return {
    title: event.title,
    description: event.description || '',
    start_datetime: formatForInput(event.start_datetime, isAllDay, '09:00'),
    end_datetime: formatForInput(displayEnd, isAllDay, '10:00'),
    all_day: isAllDay,
    location_id: event.location_id?.toString() || '',
    calendar_id: event.calendar_id?.toString() || '',
    is_starred: event.is_starred || false,
    recurrence_type: rule?.type || '',
    recurrence_interval: rule?.interval || 2,
    recurrence_weekday: rule?.weekday ?? 1,
    recurrence_week: rule?.week || 1,
    recurrence_day: rule?.day || 1,
  };
}

function buildCreateState(defaults: CreateDefaults | null, defaultCalendarId: string): EditState {
  const source = defaults?.templateData;
  const isAllDay = source?.all_day ?? defaults?.allDay ?? false;
  const defaultStart = nowLocal();
  const defaultEnd = plusOneHour(defaultStart);
  const rawStart = defaults?.start || defaultStart;
  const rawEnd = defaults?.end || defaultEnd;
  const displayEnd = isAllDay ? adjustAllDayEndForDisplay(rawEnd) : rawEnd;
  const rule = parseRecurrenceRule(source?.recurrence_rule);

  return {
    title: source?.title || '',
    description: source?.description || '',
    start_datetime: formatForInput(rawStart, isAllDay, '09:00'),
    end_datetime: formatForInput(displayEnd, isAllDay, '10:00'),
    all_day: isAllDay,
    location_id: source?.location_id?.toString() || '',
    calendar_id: source?.calendar_id?.toString() || defaultCalendarId,
    is_starred: source?.is_starred || false,
    recurrence_type: rule?.type || '',
    recurrence_interval: rule?.interval || 2,
    recurrence_weekday: rule?.weekday ?? 1,
    recurrence_week: rule?.week || 1,
    recurrence_day: rule?.day || 1,
  };
}

function buildRecurrencePayload(state: EditState): RecurrenceRule | null {
  if (!state.recurrence_type) return null;
  switch (state.recurrence_type) {
    case 'every_n_days':
      return { type: 'every_n_days', interval: state.recurrence_interval };
    case 'weekly':
      return { type: 'weekly' };
    case 'monthly_nth_weekday':
      return { type: 'monthly_nth_weekday', week: state.recurrence_week, weekday: state.recurrence_weekday };
    case 'monthly_date':
      return { type: 'monthly_date', day: state.recurrence_day };
    default:
      return null;
  }
}

// --- Component ---

export default function EventDetailPanel({
  event,
  isCreating = false,
  createDefaults,
  onClose,
  onSaved,
  onDeleted,
  locationName,
  myPermission,
  isSharedEvent = false,
}: EventDetailPanelProps) {
  const queryClient = useQueryClient();
  const { data: calendars = [], sharedData: sharedMemberships = [] } = useCalendars();
  const selectableCalendars = [
    ...calendars.filter((c) => !c.is_system),
    ...sharedMemberships
      .filter((m) => m.permission === 'create_modify' || m.permission === 'full_access')
      .map((m) => ({ id: m.calendar_id, name: m.calendar_name, color: m.local_color || m.calendar_color, is_default: false })),
  ];
  const defaultCalendar = calendars.find((c) => c.is_default);

  const { data: locations = [] } = useQuery({
    queryKey: ['locations'],
    queryFn: async () => {
      const { data } = await api.get<LocationType[]>('/locations');
      return data;
    },
    staleTime: 5 * 60 * 1000,
  });

  const { acquire: acquireLock, release: releaseLock, isAcquiring: isAcquiringLock } = useEventLock(
    isSharedEvent && event ? (typeof event.id === 'number' ? event.id : null) : null
  );
  const [lockInfo, setLockInfo] = useState<EventLockInfo | null>(null);


  // Event invitation hooks
  const eventNumericId = event && typeof event.id === 'number' ? event.id : null;
  const parentEventId = event?.parent_event_id ?? eventNumericId;
  const {
    invitees, invite, isInviting, respond: respondInvitation,
    isResponding, override: overrideInvitation, leave: leaveInvitation, isLeaving,
  } = useEventInvitations(parentEventId);
  const { connections } = useConnectedUsersSearch();
  const [showLeaveDialog, setShowLeaveDialog] = useState(false);

  const isInvitedEvent = !!event?.is_invited;
  const myInvitationStatus = event?.invitation_status ?? null;
  const myInvitationId = event?.invitation_id ?? null;

  const [isEditing, setIsEditing] = useState(isCreating);
  const [editState, setEditState] = useState<EditState>(() =>
    isCreating
      ? buildCreateState(createDefaults ?? null, defaultCalendar?.id?.toString() || '')
      : event
        ? buildEditStateFromEvent(event)
        : buildCreateState(null, defaultCalendar?.id?.toString() || '')
  );
  const [scopeStep, setScopeStep] = useState<'edit' | 'delete' | null>(null);
  const [editScope, setEditScope] = useState<'this' | 'this_and_future' | null>(null);
  const [locationSearch, setLocationSearch] = useState('');

  // Poll lock status in view mode for shared events (Stream A: real-time lock awareness)
  // lockInfo is only set from the 423 error path; poll data (viewLockQuery.data) is used directly.
  const viewLockQuery = useQuery({
    queryKey: ['event-lock', event?.id],
    queryFn: async () => {
      const { data } = await api.get<EventLockInfo>(
        `/shared-calendars/events/${event!.id}/lock`
      );
      return data;
    },
    enabled: !!isSharedEvent && !!event && typeof event.id === 'number' && !isEditing && !isCreating,
    refetchInterval: 5_000,
    refetchIntervalInBackground: true,
    refetchOnMount: 'always',
  });

  // Clear 423-error lockInfo when poll confirms lock is gone
  useEffect(() => {
    if (viewLockQuery.data && !viewLockQuery.data.locked) {
      setLockInfo(null);
    }
  }, [viewLockQuery.data]);

  // Derived: authoritative lock state — poll data wins, 423 error lockInfo as fallback
  const activeLockInfo: EventLockInfo | null =
    (viewLockQuery.data?.locked ? viewLockQuery.data : null) ??
    (lockInfo?.locked ? lockInfo : null);

  const isRecurring = !!(event?.is_recurring || event?.parent_event_id);

  // Permission helpers
  const canEdit = !isSharedEvent || myPermission === 'owner' || myPermission === 'create_modify' || myPermission === 'full_access';
  const canDelete = !isSharedEvent || myPermission === 'owner' || myPermission === 'full_access';

  // Reset state when event changes
  useEffect(() => {
    setIsEditing(false);
    setScopeStep(null);
    setEditScope(null);
    setLocationSearch('');
    setLockInfo(null);
    if (event) setEditState(buildEditStateFromEvent(event));
  }, [event?.id]);

  // Enter edit mode when creating
  useEffect(() => {
    if (isCreating) {
      setIsEditing(true);
      setEditState(buildCreateState(createDefaults ?? null, defaultCalendar?.id?.toString() || ''));
      setLocationSearch('');
    }
  }, [isCreating, createDefaults]);

  // Initialize location search text from existing location
  useEffect(() => {
    if (isEditing && !isCreating && event?.location_id) {
      const loc = locations.find((l) => l.id === event.location_id);
      if (loc) setLocationSearch(loc.name);
    }
  }, [isEditing, isCreating, event?.location_id, locations]);

  const invalidateAll = useCallback(() => {
    queryClient.invalidateQueries({ queryKey: ['calendar-events'] });
    queryClient.invalidateQueries({ queryKey: ['dashboard'] });
    queryClient.invalidateQueries({ queryKey: ['upcoming'] });
  }, [queryClient]);

  // --- Mutations ---

  const saveMutation = useMutation({
    mutationFn: async (data: EditState) => {
      const rule = buildRecurrencePayload(data);
      let endDt = data.end_datetime;
      if (data.all_day && endDt) endDt = adjustAllDayEndForSave(endDt);

      const payload: Record<string, unknown> = {
        title: data.title,
        description: data.description || null,
        start_datetime: data.start_datetime,
        end_datetime: endDt,
        all_day: data.all_day,
        location_id: data.location_id ? parseInt(data.location_id) : null,
        calendar_id: data.calendar_id ? parseInt(data.calendar_id) : null,
        is_starred: data.is_starred,
        recurrence_rule: rule,
      };

      if (event && !isCreating) {
        if (editScope) payload.edit_scope = editScope;
        return api.put(`/events/${event.id}`, payload);
      } else {
        return api.post('/events', payload);
      }
    },
    onSuccess: () => {
      if (isSharedEvent) releaseLock();
      invalidateAll();
      toast.success(isCreating ? 'Event created' : 'Event updated');
      if (isCreating) {
        onClose();
        onSaved?.();
      } else {
        setIsEditing(false);
        setEditScope(null);
      }
    },
    onError: (error) => {
      toast.error(getErrorMessage(error, isCreating ? 'Failed to create event' : 'Failed to update event'));
    },
  });

  const deleteMutation = useMutation({
    mutationFn: async () => {
      const scope = editScope ? `?scope=${editScope}` : '';
      await api.delete(`/events/${event!.id}${scope}`);
    },
    onSuccess: () => {
      invalidateAll();
      toast.success('Event deleted');
      onClose();
      onDeleted?.();
    },
    onError: (error) => {
      toast.error(getErrorMessage(error, 'Failed to delete event'));
    },
  });

  const executeDelete = useCallback(() => deleteMutation.mutate(), [deleteMutation]);
  const { confirming: confirmingDelete, handleClick: handleDeleteClick } = useConfirmAction(executeDelete);

  // --- Handlers ---

  const handleEditStart = async () => {
    // For shared events, acquire lock first
    if (isSharedEvent && event && typeof event.id === 'number') {
      try {
        await acquireLock();
        setLockInfo(null);
      } catch (err: unknown) {
        if (axios.isAxiosError(err) && err.response?.status === 423) {
          const data = err.response.data as { locked_by_name?: string; expires_at?: string; is_permanent?: boolean } | undefined;
          setLockInfo({
            locked: true,
            locked_by_name: data?.locked_by_name || 'another user',
            expires_at: data?.expires_at || null,
            is_permanent: data?.is_permanent || false,
          });
          return;
        }
        toast.error('Failed to acquire edit lock');
        return;
      }
    }

    if (isRecurring) {
      setScopeStep('edit');
    } else {
      if (event) setEditState(buildEditStateFromEvent(event));
      setIsEditing(true);
    }
  };

  const handleScopeSelect = (scope: 'this' | 'this_and_future') => {
    setEditScope(scope);
    if (scopeStep === 'edit') {
      if (event) setEditState(buildEditStateFromEvent(event));
      setIsEditing(true);
      setScopeStep(null);
    } else if (scopeStep === 'delete') {
      // Delete with scope — execute immediately
      setScopeStep(null);
      const scopeParam = `?scope=${scope}`;
      api.delete(`/events/${event!.id}${scopeParam}`).then(() => {
        invalidateAll();
        toast.success('Event(s) deleted');
        onClose();
        onDeleted?.();
      }).catch((error) => {
        toast.error(getErrorMessage(error, 'Failed to delete event'));
      });
    }
  };

  const handleEditCancel = () => {
    if (isSharedEvent) releaseLock();
    setIsEditing(false);
    setEditScope(null);
    setLocationSearch('');
    if (isCreating) {
      onClose();
    } else if (event) {
      setEditState(buildEditStateFromEvent(event));
    }
  };

  const handleEditSave = () => {
    saveMutation.mutate(editState);
  };

  const handleDeleteStart = () => {
    if (isRecurring) {
      setScopeStep('delete');
    } else {
      handleDeleteClick();
    }
  };

  // --- Render helpers ---

  const updateField = <K extends keyof EditState>(key: K, value: EditState[K]) => {
    setEditState((s) => ({ ...s, [key]: value }));
  };

  // Empty state
  if (!event && !isCreating) {
    return (
      <div className="flex flex-col items-center justify-center h-full text-muted-foreground">
        <Calendar className="h-8 w-8 mb-3 opacity-40" />
        <p className="text-sm">Select an event to view details</p>
      </div>
    );
  }

  // View mode data
  const startDate = event ? parseISO(event.start_datetime) : null;
  const endDate = event?.end_datetime ? parseISO(event.end_datetime) : null;
  const startStr = startDate
    ? event!.all_day
      ? format(startDate, 'EEEE, MMMM d, yyyy')
      : format(startDate, 'EEEE, MMMM d, yyyy · h:mm a')
    : '';
  const endStr = endDate
    ? event!.all_day
      ? format(endDate, 'EEEE, MMMM d, yyyy')
      : format(endDate, 'h:mm a')
    : null;

  const panelTitle = isCreating
    ? createDefaults?.templateName
      ? `New Event from ${createDefaults.templateName}`
      : 'New Event'
    : event?.title || '';

  return (
    <div className="flex flex-col h-full bg-card border-l border-border overflow-hidden">
      {/* Header */}
      <div className="px-5 py-4 border-b border-border shrink-0">
        <div className="flex items-start justify-between gap-3">
          {isEditing ? (
            <div className="flex-1 min-w-0">
              {isCreating ? (
                <h3 className="font-heading text-lg font-semibold">{panelTitle}</h3>
              ) : (
                <Input
                  value={editState.title}
                  onChange={(e) => updateField('title', e.target.value)}
                  className="h-8 text-base font-semibold"
                  placeholder="Event title"
                  autoFocus
                />
              )}
            </div>
          ) : scopeStep ? (
            <h3 className="font-heading text-sm font-semibold">
              {scopeStep === 'edit' ? 'Edit Recurring Event' : 'Delete Recurring Event'}
            </h3>
          ) : (
            <div className="flex items-center gap-3 min-w-0 flex-1">
              <div
                className="w-3 h-3 rounded-full shrink-0"
                style={{ backgroundColor: event?.calendar_color || 'hsl(var(--accent-color))' }}
              />
              <div className="min-w-0">
                <h3 className="font-heading text-lg font-semibold truncate">{event?.title}</h3>
                <span className="text-xs text-muted-foreground">{event?.calendar_name}</span>
              </div>
            </div>
          )}

          <div className="flex items-center gap-1 shrink-0">
            {scopeStep ? (
              <Button
                variant="ghost"
                size="icon"
                className="h-7 w-7"
                onClick={() => setScopeStep(null)}
                title="Cancel"
              >
                <X className="h-3.5 w-3.5" />
              </Button>
            ) : (isEditing || isCreating) ? (
              <>
                <Button
                  variant="ghost"
                  size="icon"
                  className="h-7 w-7 text-green-400 hover:text-green-300"
                  onClick={handleEditSave}
                  disabled={saveMutation.isPending}
                  title="Save"
                >
                  <Save className="h-3.5 w-3.5" />
                </Button>
                <Button
                  variant="ghost"
                  size="icon"
                  className="h-7 w-7"
                  onClick={handleEditCancel}
                  title="Cancel"
                >
                  <X className="h-3.5 w-3.5" />
                </Button>
              </>
            ) : (
              <>
                {!event?.is_virtual && (
                  <>
                    {/* Edit button — only for own events or shared with edit permission */}
                    {canEdit && !isInvitedEvent && (
                      <Button
                        variant="ghost"
                        size="icon"
                        className="h-7 w-7"
                        onClick={handleEditStart}
                        disabled={isAcquiringLock || !!activeLockInfo}
                        title={activeLockInfo ? `Locked by ${activeLockInfo.locked_by_name || 'another user'}` : 'Edit event'}
                      >
                        {isAcquiringLock ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Pencil className="h-3.5 w-3.5" />}
                      </Button>
                    )}
                    {/* Leave button for invited events */}
                    {isInvitedEvent && myInvitationId && (
                      <Button
                        variant="ghost"
                        size="icon"
                        className="h-7 w-7 text-muted-foreground hover:text-destructive"
                        onClick={() => setShowLeaveDialog(true)}
                        title="Leave event"
                      >
                        <LogOut className="h-3.5 w-3.5" />
                      </Button>
                    )}
                    {/* Delete button for own events */}
                    {canDelete && !isInvitedEvent && (
                      confirmingDelete ? (
                        <Button
                          variant="ghost"
                          onClick={handleDeleteStart}
                          disabled={deleteMutation.isPending}
                          className="h-7 px-2 bg-destructive/20 text-destructive text-[11px] font-medium"
                          title="Confirm delete"
                        >
                          Sure?
                        </Button>
                      ) : (
                        <Button
                          variant="ghost"
                          size="icon"
                          className="h-7 w-7 text-muted-foreground hover:text-destructive"
                          onClick={handleDeleteStart}
                          disabled={deleteMutation.isPending}
                          title="Delete event"
                        >
                          <Trash2 className="h-3.5 w-3.5" />
                        </Button>
                      )
                    )}
                  </>
                )}
                <Button
                  variant="ghost"
                  size="icon"
                  className="h-7 w-7"
                  onClick={onClose}
                  title="Close panel"
                >
                  <X className="h-3.5 w-3.5" />
                </Button>
              </>
            )}
          </div>
        </div>
      </div>

      {/* Body */}
      <div className="flex-1 overflow-y-auto px-5 py-4 space-y-3">
        {/* Lock banner — shown when activeLockInfo reports a lock (poll-authoritative) */}
        {activeLockInfo && (
          <EventLockBanner
            lockedByName={activeLockInfo.locked_by_name || 'another user'}
            expiresAt={activeLockInfo.expires_at}
            isPermanent={activeLockInfo.is_permanent}
          />
        )}

        {scopeStep ? (
          /* Scope selection step */
          <div className="space-y-3">
            <p className="text-sm text-muted-foreground">
              This is a recurring event. How would you like to proceed?
            </p>
            <div className="flex flex-col gap-2">
              <Button
                variant="outline"
                className="w-full justify-center"
                onClick={() => handleScopeSelect('this')}
              >
                This event only
              </Button>
              <Button
                variant="outline"
                className="w-full justify-center"
                onClick={() => handleScopeSelect('this_and_future')}
              >
                This and all future events
              </Button>
              <Button
                variant="ghost"
                className="w-full justify-center"
                onClick={() => setScopeStep(null)}
              >
                Cancel
              </Button>
            </div>
          </div>
        ) : (isEditing || isCreating) ? (
          /* Edit / Create mode */
          <div className="space-y-4">
            {/* Title (only shown in body for create mode; edit mode has it in header) */}
            {isCreating && (
              <div className="space-y-1">
                <Label htmlFor="panel-title" required>Title</Label>
                <Input
                  id="panel-title"
                  value={editState.title}
                  onChange={(e) => updateField('title', e.target.value)}
                  placeholder="Event title"
                  required
                  autoFocus
                />
              </div>
            )}

            <div className="space-y-1">
              <Label htmlFor="panel-desc">Description</Label>
              <Textarea
                id="panel-desc"
                value={editState.description}
                onChange={(e) => updateField('description', e.target.value)}
                placeholder="Add a description..."
                rows={3}
                className="text-sm resize-none"
              />
            </div>

            <div className="flex items-center gap-2">
              <Checkbox
                id="panel-allday"
                checked={editState.all_day}
                onChange={(e) => {
                  const checked = (e.target as HTMLInputElement).checked;
                  updateField('all_day', checked);
                  updateField('start_datetime', formatForInput(editState.start_datetime, checked, '09:00'));
                  updateField('end_datetime', formatForInput(editState.end_datetime, checked, '10:00'));
                }}
              />
              <Label htmlFor="panel-allday">All day event</Label>
            </div>

            <div className="grid grid-cols-2 gap-3">
              <div className="space-y-1">
                <Label htmlFor="panel-start" required>Start</Label>
                <DatePicker
                  variant="input"
                  id="panel-start"
                  mode={editState.all_day ? 'date' : 'datetime'}
                  value={editState.start_datetime}
                  onChange={(v) => updateField('start_datetime', v)}
                  className="text-xs"
                  required
                />
              </div>
              <div className="space-y-1">
                <Label htmlFor="panel-end">End</Label>
                <DatePicker
                  variant="input"
                  id="panel-end"
                  mode={editState.all_day ? 'date' : 'datetime'}
                  value={editState.end_datetime}
                  onChange={(v) => updateField('end_datetime', v)}
                  className="text-xs"
                />
              </div>
            </div>

            <div className="grid grid-cols-2 gap-3">
              <div className="space-y-1">
                <Label htmlFor="panel-calendar">Calendar</Label>
                <Select
                  id="panel-calendar"
                  value={editState.calendar_id}
                  onChange={(e) => updateField('calendar_id', e.target.value)}
                  className="text-xs"
                >
                  {selectableCalendars.map((cal) => (
                    <option key={cal.id} value={cal.id}>{cal.name}</option>
                  ))}
                </Select>
              </div>
              <div className="space-y-1">
                <Label htmlFor="panel-location">Location</Label>
                <LocationPicker
                  id="panel-location"
                  value={locationSearch}
                  onChange={(val) => {
                    setLocationSearch(val);
                    if (!val) updateField('location_id', '');
                  }}
                  onSelect={async (result) => {
                    if (result.source === 'local' && result.location_id) {
                      updateField('location_id', result.location_id.toString());
                    } else if (result.source === 'nominatim') {
                      try {
                        const { data: newLoc } = await api.post('/locations', {
                          name: result.name,
                          address: result.address,
                          category: 'other',
                        });
                        queryClient.invalidateQueries({ queryKey: ['locations'] });
                        updateField('location_id', newLoc.id.toString());
                        toast.success(`Location "${result.name}" created`);
                      } catch {
                        toast.error('Failed to create location');
                      }
                    }
                  }}
                  placeholder="Search location..."
                />
              </div>
            </div>

            {/* Recurrence */}
            <div className="space-y-1">
              <Label htmlFor="panel-recurrence">Recurrence</Label>
              <Select
                id="panel-recurrence"
                value={editState.recurrence_type}
                onChange={(e) => updateField('recurrence_type', e.target.value)}
                className="text-xs"
              >
                <option value="">None</option>
                <option value="every_n_days">Every X days</option>
                <option value="weekly">Weekly</option>
                <option value="monthly_nth_weekday">Monthly (nth weekday)</option>
                <option value="monthly_date">Monthly (date)</option>
              </Select>
            </div>

            {editState.recurrence_type === 'every_n_days' && (
              <div className="space-y-1">
                <Label htmlFor="panel-interval">Every how many days?</Label>
                <Input
                  id="panel-interval"
                  type="number"
                  min={1}
                  max={365}
                  value={editState.recurrence_interval}
                  onChange={(e) => updateField('recurrence_interval', parseInt(e.target.value) || 1)}
                  className="text-xs"
                />
              </div>
            )}

            {editState.recurrence_type === 'weekly' && (
              <p className="text-xs text-muted-foreground">
                Repeats every week on the same day as the start date.
              </p>
            )}

            {editState.recurrence_type === 'monthly_nth_weekday' && (
              <div className="grid grid-cols-2 gap-3">
                <div className="space-y-1">
                  <Label htmlFor="panel-week">Week of month</Label>
                  <Select
                    id="panel-week"
                    value={editState.recurrence_week.toString()}
                    onChange={(e) => updateField('recurrence_week', parseInt(e.target.value))}
                    className="text-xs"
                  >
                    <option value="1">1st</option>
                    <option value="2">2nd</option>
                    <option value="3">3rd</option>
                    <option value="4">4th</option>
                  </Select>
                </div>
                <div className="space-y-1">
                  <Label htmlFor="panel-weekday">Day of week</Label>
                  <Select
                    id="panel-weekday"
                    value={editState.recurrence_weekday.toString()}
                    onChange={(e) => updateField('recurrence_weekday', parseInt(e.target.value))}
                    className="text-xs"
                  >
                    {WEEKDAYS.map((name, i) => (
                      <option key={i} value={i}>{name}</option>
                    ))}
                  </Select>
                </div>
              </div>
            )}

            {editState.recurrence_type === 'monthly_date' && (
              <div className="space-y-1">
                <Label htmlFor="panel-day">Day of month</Label>
                <Input
                  id="panel-day"
                  type="number"
                  min={1}
                  max={31}
                  value={editState.recurrence_day}
                  onChange={(e) => updateField('recurrence_day', parseInt(e.target.value) || 1)}
                  className="text-xs"
                />
              </div>
            )}

            <div className="flex items-center gap-2">
              <Checkbox
                id="panel-starred"
                checked={editState.is_starred}
                onChange={(e) => updateField('is_starred', (e.target as HTMLInputElement).checked)}
              />
              <Label htmlFor="panel-starred">Star this event</Label>
            </div>

            {/* Save / Cancel buttons at bottom of form */}
            <div className="flex items-center justify-end gap-2 pt-2 border-t border-border">
              <Button variant="outline" size="sm" onClick={handleEditCancel}>
                Cancel
              </Button>
              <Button size="sm" onClick={handleEditSave} disabled={saveMutation.isPending}>
                {saveMutation.isPending ? 'Saving...' : isCreating ? 'Create' : 'Update'}
              </Button>
            </div>
          </div>
        ) : (
          /* View mode */
          <>
            {/* 2-column grid: Calendar, Starred, Start, End, Location, Recurrence */}
            <div className="grid grid-cols-2 gap-3">
              {/* Calendar */}
              <div className="space-y-1">
                <div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
                  <Calendar className="h-3 w-3" />
                  Calendar
                </div>
                <div className="flex items-center gap-2">
                  <div
                    className="w-2 h-2 rounded-full shrink-0"
                    style={{ backgroundColor: event?.calendar_color || 'hsl(var(--accent-color))' }}
                  />
                  <span className="text-sm">{event?.calendar_name}</span>
                </div>
              </div>

              {/* Starred */}
              <div className="space-y-1">
                <div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
                  <Star className="h-3 w-3" />
                  Starred
                </div>
                {event?.is_starred ? (
                  <p className="text-sm text-amber-200/90">Starred</p>
                ) : (
                  <p className="text-sm text-muted-foreground">—</p>
                )}
              </div>

              {/* Start */}
              <div className="space-y-1">
                <div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
                  <Clock className="h-3 w-3" />
                  Start
                </div>
                <CopyableField value={startStr} icon={Clock} label="Start time" />
              </div>

              {/* End */}
              <div className="space-y-1">
                <div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
                  <Clock className="h-3 w-3" />
                  End
                </div>
                {endStr ? (
                  <CopyableField value={endStr} icon={Clock} label="End time" />
                ) : (
                  <p className="text-sm text-muted-foreground">—</p>
                )}
              </div>

              {/* Location */}
              <div className="space-y-1">
                <div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
                  <MapPin className="h-3 w-3" />
                  Location
                </div>
                {locationName ? (
                  <CopyableField value={locationName} icon={MapPin} label="Location" />
                ) : (
                  <p className="text-sm text-muted-foreground">—</p>
                )}
              </div>

              {/* Recurrence */}
              <div className="space-y-1">
                <div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
                  <Repeat className="h-3 w-3" />
                  Recurrence
                </div>
                {isRecurring && event?.recurrence_rule ? (
                  <p className="text-sm">{formatRecurrenceRule(event.recurrence_rule)}</p>
                ) : isRecurring ? (
                  <p className="text-sm">Recurring event</p>
                ) : (
                  <p className="text-sm text-muted-foreground">—</p>
                )}
              </div>
            </div>

            {/* Description — full width */}
            {event?.description && (
              <div className="space-y-1">
                <div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
                  <AlignLeft className="h-3 w-3" />
                  Description
                </div>
                <p className="text-sm whitespace-pre-wrap">{event.description}</p>
              </div>
            )}

            {/* Invitee section — view mode */}
            {event && !event.is_virtual && (
              <>
                {/* RSVP buttons for invitees */}
                {isInvitedEvent && myInvitationId && (
                  <div className="space-y-1">
                    <div className="flex items-center gap-1.5 text-[11px] text-muted-foreground uppercase tracking-wider">
                      Your RSVP
                    </div>
                    <RsvpButtons
                      currentStatus={myInvitationStatus || 'pending'}
                      onRespond={(status) => {
                        if (event.parent_event_id && eventNumericId) {
                          overrideInvitation({ invitationId: myInvitationId, occurrenceId: eventNumericId, status });
                        } else {
                          respondInvitation({ invitationId: myInvitationId, status });
                        }
                      }}
                      isResponding={isResponding}
                    />
                  </div>
                )}

                {/* Invitee list */}
                {invitees.length > 0 && (
                  <InviteeList
                    invitees={invitees}
                    isRecurringChild={!!event.parent_event_id}
                  />
                )}

                {/* Invite search for event owner/editor */}
                {!isInvitedEvent && canEdit && (
                  <InviteSearch
                    connections={connections}
                    existingInviteeIds={new Set(invitees.map((i) => i.user_id))}
                    onInvite={(userIds) => invite(userIds)}
                    isInviting={isInviting}
                  />
                )}
              </>
            )}

            {/* Updated at */}
            {event && !event.is_virtual && (
              <div className="pt-2 border-t border-border">
                <span className="text-[11px] text-muted-foreground">
                  {formatUpdatedAt(event.updated_at)}
                </span>
              </div>
            )}

            {/* Leave event dialog */}
            {event && isInvitedEvent && myInvitationId && (
              <LeaveEventDialog
                open={showLeaveDialog}
                onClose={() => setShowLeaveDialog(false)}
                onConfirm={() => {
                  leaveInvitation(myInvitationId).then(() => {
                    setShowLeaveDialog(false);
                    onClose();
                  });
                }}
                eventTitle={event.title}
                isRecurring={!!(event.is_recurring || event.parent_event_id)}
                isLeaving={isLeaving}
              />
            )}
          </>
        )}
      </div>
    </div>
  );
}
