import { useState, useEffect, useCallback, type MutableRefObject } from 'react';
import {
  Calendar,
  Card,
  Typography,
  Space,
  Tag,
  Button,
  Progress,
  Empty,
  Spin,
  Grid,
  Tooltip,
} from 'antd';
import {
  CalendarOutlined,
  ClockCircleOutlined,
  EnvironmentOutlined,
  TeamOutlined,
  DownloadOutlined,
  LinkOutlined,
  CloseOutlined,
  ClearOutlined,
  VideoCameraOutlined,
} from '@ant-design/icons';
import axios from 'axios';
import dayjs, { Dayjs } from 'dayjs';
import utc from 'dayjs/plugin/utc';
import EventSubmissionForm from './EventSubmissionForm';
import type { UnifiedCalendarItem, UnifiedCalendarResponse } from '@/types/api';

dayjs.extend(utc);

const { Text } = Typography;

interface UnifiedCalendarProps {
  onShiftSignup?: (item: UnifiedCalendarItem) => void;
  gancioUrl?: string;
  onEventSubmitted?: () => void;
  /** Ref that receives a function to open the panel with an empty date (for "Submit Event" button) */
  onAddEvent?: MutableRefObject<(() => void) | null>;
  /** User is authenticated and non-TEMP */
  canCreateMeeting?: boolean;
  /** Site setting: enableMeet */
  meetEnabled?: boolean;
}

/** Generate a .ics file and trigger download */
function downloadIcs(item: UnifiedCalendarItem) {
  const startDt = dayjs(`${item.date}T${item.startTime}`);
  const endDt = dayjs(`${item.date}T${item.endTime}`);

  const fmt = (d: Dayjs) => d.utc().format('YYYYMMDDTHHmmss') + 'Z';

  const ics = [
    'BEGIN:VCALENDAR',
    'VERSION:2.0',
    'PRODID:-//Changemaker Lite//Calendar//EN',
    'BEGIN:VEVENT',
    `DTSTART:${fmt(startDt)}`,
    `DTEND:${fmt(endDt)}`,
    `SUMMARY:${item.title.replace(/[,;\\]/g, ' ')}`,
    `LOCATION:${(item.location || '').replace(/[,;\\]/g, ' ')}`,
    `UID:${item.id}@changemaker`,
    'END:VEVENT',
    'END:VCALENDAR',
  ].join('\r\n');

  const blob = new Blob([ics], { type: 'text/calendar;charset=utf-8' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = `${item.title.replace(/[^a-zA-Z0-9]/g, '_').slice(0, 40)}.ics`;
  a.click();
  URL.revokeObjectURL(url);
}

export default function UnifiedCalendar({ onShiftSignup, gancioUrl, onEventSubmitted, onAddEvent, canCreateMeeting, meetEnabled }: UnifiedCalendarProps) {
  const screens = Grid.useBreakpoint();
  const isMobile = !screens.md;

  const [calendarData, setCalendarData] = useState<UnifiedCalendarResponse | null>(null);
  const [loading, setLoading] = useState(true);
  const [openDates, setOpenDates] = useState<string[]>([]);
  const [currentMonth, setCurrentMonth] = useState(dayjs());

  // Expose a function for the parent "Submit Event" button to open the panel with tomorrow's date
  useEffect(() => {
    if (onAddEvent) {
      onAddEvent.current = () => {
        const tomorrow = dayjs().add(1, 'day').format('YYYY-MM-DD');
        setOpenDates(prev =>
          prev.includes(tomorrow) ? prev : [...prev, tomorrow].sort(),
        );
      };
    }
    return () => { if (onAddEvent) onAddEvent.current = null; };
  }, [onAddEvent]);

  const fetchCalendar = useCallback(async (month: Dayjs) => {
    setLoading(true);
    const startDate = month.startOf('month').subtract(7, 'day').format('YYYY-MM-DD');
    const endDate = month.endOf('month').add(7, 'day').format('YYYY-MM-DD');
    try {
      const { data } = await axios.get<UnifiedCalendarResponse>('/api/events/calendar', {
        params: { startDate, endDate },
      });
      setCalendarData(data);
    } catch {
      setCalendarData({ dates: {} });
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    fetchCalendar(currentMonth);
  }, [currentMonth, fetchCalendar]);

  const getDateItems = (dateKey: string): UnifiedCalendarItem[] => {
    return calendarData?.dates[dateKey]?.items || [];
  };

  // Toggle a date in the open list
  const handleSelect = (date: Dayjs) => {
    const key = date.format('YYYY-MM-DD');
    setOpenDates(prev =>
      prev.includes(key)
        ? prev.filter(d => d !== key)
        : [...prev, key].sort(),
    );
  };

  const removeDate = (dateKey: string) => {
    setOpenDates(prev => prev.filter(d => d !== dateKey));
  };

  const handlePanelChange = (date: Dayjs) => {
    setCurrentMonth(date);
  };

  const MAX_CELL_ITEMS = 3;

  // Cell renderer showing colorful mini-cards
  const cellRender = (date: Dayjs) => {
    const dateKey = date.format('YYYY-MM-DD');
    const items = getDateItems(dateKey);
    if (items.length === 0) return null;

    const visible = items.slice(0, MAX_CELL_ITEMS);
    const overflow = items.length - MAX_CELL_ITEMS;

    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 3, padding: '0 2px' }}>
        {visible.map(item => {
          const isPoll = item.type === 'poll';
          const isShift = item.type === 'shift';
          const isTicketed = item.type === 'ticketed_event';
          const bg = isTicketed ? 'rgba(114, 46, 209, 0.2)' : isPoll ? 'rgba(250, 140, 22, 0.2)' : isShift ? 'rgba(24, 144, 255, 0.2)' : 'rgba(82, 196, 26, 0.2)';
          const border = isTicketed ? 'rgba(114, 46, 209, 0.5)' : isPoll ? 'rgba(250, 140, 22, 0.5)' : isShift ? 'rgba(24, 144, 255, 0.5)' : 'rgba(82, 196, 26, 0.5)';
          const accent = isTicketed ? '#722ed1' : isPoll ? '#fa8c16' : isShift ? '#1890ff' : '#52c41a';
          return (
            <div
              key={item.id}
              style={{
                background: bg,
                border: `1px solid ${border}`,
                borderLeft: `3px solid ${accent}`,
                borderRadius: 4,
                padding: '2px 5px',
                fontSize: 11,
                lineHeight: '15px',
                overflow: 'hidden',
                whiteSpace: 'nowrap',
                textOverflow: 'ellipsis',
                color: 'rgba(255,255,255,0.85)',
              }}
            >
              <span style={{ color: 'rgba(255,255,255,0.5)', marginRight: 3, fontSize: 10 }}>
                {item.startTime}
              </span>
              {(item.tags?.includes('video-meeting') || item.eventFormat === 'ONLINE' || item.eventFormat === 'HYBRID') && (
                <VideoCameraOutlined style={{ fontSize: 9, marginRight: 3, color: 'rgba(255,255,255,0.5)' }} />
              )}
              {item.title}
            </div>
          );
        })}
        {overflow > 0 && (
          <div style={{ fontSize: 10, color: 'rgba(255,255,255,0.45)', textAlign: 'center' }}>
            +{overflow} more
          </div>
        )}
      </div>
    );
  };

  const renderItemCard = (item: UnifiedCalendarItem) => {
    const isShift = item.type === 'shift';
    const isPoll = item.type === 'poll';
    const isTicketed = item.type === 'ticketed_event';
    const spotsLeft = isShift && item.maxVolunteers
      ? item.maxVolunteers - (item.currentVolunteers || 0)
      : null;
    const isFull = spotsLeft !== null && spotsLeft <= 0;
    const pct = isShift && item.maxVolunteers && item.maxVolunteers > 0
      ? Math.round(((item.currentVolunteers || 0) / item.maxVolunteers) * 100)
      : 0;
    const borderColor = isTicketed ? '#722ed1' : isPoll ? '#fa8c16' : isShift ? '#1890ff' : '#52c41a';
    const tagColor = isTicketed ? 'purple' : isPoll ? 'orange' : isShift ? 'blue' : 'green';
    const tagLabel = isTicketed ? 'Ticketed' : isPoll ? 'Poll' : isShift ? 'Shift' : 'Event';

    return (
      <Card
        key={item.id}
        size="small"
        style={{
          borderLeft: `4px solid ${borderColor}`,
          marginBottom: 8,
        }}
      >
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 8, marginBottom: 4 }}>
          <Text strong style={{ color: '#fff', fontSize: 14 }}>
            {item.title}
            {(item.tags?.includes('video-meeting') || item.eventFormat === 'ONLINE' || item.eventFormat === 'HYBRID') && (
              <Tooltip title={item.eventFormat === 'HYBRID' ? 'Hybrid (Online + In-Person)' : 'Online Event'}>
                <VideoCameraOutlined style={{ marginLeft: 6, fontSize: 13, color: '#722ed1' }} />
              </Tooltip>
            )}
          </Text>
          <Tag color={tagColor} style={{ margin: 0, fontSize: 11 }}>
            {tagLabel}
          </Tag>
        </div>

        <Space size={16} wrap style={{ marginBottom: 8 }}>
          <Text style={{ color: 'rgba(255,255,255,0.65)', fontSize: 13 }}>
            <ClockCircleOutlined style={{ marginRight: 4 }} />
            {item.startTime} — {item.endTime}
          </Text>
          {item.location && (
            <Text style={{ color: 'rgba(255,255,255,0.65)', fontSize: 13 }}>
              <EnvironmentOutlined style={{ marginRight: 4 }} />
              {item.location}
            </Text>
          )}
        </Space>

        {item.tags.length > 0 && (
          <div style={{ marginBottom: 8 }}>
            {item.tags.map(tag => (
              <Tag key={tag} style={{ margin: '0 4px 4px 0', fontSize: 11 }}>{tag}</Tag>
            ))}
          </div>
        )}

        {/* Ticketed event: capacity bar */}
        {isTicketed && item.maxAttendees != null && (
          <div style={{ marginBottom: 8 }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 2 }}>
              <Text type="secondary" style={{ fontSize: 12 }}>
                <TeamOutlined style={{ marginRight: 4 }} />
                Attendees
              </Text>
              <Text type="secondary" style={{ fontSize: 12 }}>
                {item.currentAttendees || 0}/{item.maxAttendees}
              </Text>
            </div>
            <Progress
              percent={Math.round(((item.currentAttendees || 0) / item.maxAttendees) * 100)}
              size="small"
              status={item.isSoldOut ? 'exception' : 'active'}
              showInfo={false}
            />
          </div>
        )}

        {/* Shift-specific: capacity bar */}
        {isShift && item.maxVolunteers != null && (
          <div style={{ marginBottom: 8 }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 2 }}>
              <Text type="secondary" style={{ fontSize: 12 }}>
                <TeamOutlined style={{ marginRight: 4 }} />
                Volunteers
              </Text>
              <Text type="secondary" style={{ fontSize: 12 }}>
                {item.currentVolunteers || 0}/{item.maxVolunteers}
              </Text>
            </div>
            <Progress percent={pct} size="small" status={isFull ? 'exception' : 'active'} showInfo={false} />
          </div>
        )}

        <Space size={8} wrap>
          <Tooltip title="Add to Calendar">
            <Button
              type="text"
              size="small"
              icon={<DownloadOutlined />}
              onClick={() => downloadIcs(item)}
            >
              .ics
            </Button>
          </Tooltip>

          {isShift && !isFull && item.shiftId && (
            <Button
              type="primary"
              size="small"
              icon={<TeamOutlined />}
              onClick={() => onShiftSignup?.(item)}
            >
              Sign Up
            </Button>
          )}

          {!isShift && !isPoll && item.gancioUrl && (
            <Button
              type="link"
              size="small"
              icon={<LinkOutlined />}
              href={item.gancioUrl}
              target="_blank"
              rel="noopener noreferrer"
            >
              View
            </Button>
          )}

          {isPoll && item.pollSlug && (
            <Button
              type="primary"
              size="small"
              icon={<CalendarOutlined />}
              href={`/poll/${item.pollSlug}`}
              target="_blank"
              rel="noopener noreferrer"
            >
              Vote ({item.pollVoteCount ?? 0})
            </Button>
          )}

          {isTicketed && item.eventSlug && (
            <Button
              type="primary"
              size="small"
              href={`/event/${item.eventSlug}`}
            >
              {item.isSoldOut ? 'Sold Out' : 'Get Tickets'}
            </Button>
          )}
        </Space>
      </Card>
    );
  };

  const handleEventSubmitted = () => {
    fetchCalendar(currentMonth);
    onEventSubmitted?.();
  };

  // Render a date section in the side panel
  const renderDateSection = (dateKey: string) => {
    const items = getDateItems(dateKey);
    const isPast = dateKey < dayjs().format('YYYY-MM-DD');
    return (
      <div key={dateKey} style={{ marginBottom: 20 }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
          <Text strong style={{ color: '#fff', fontSize: 14 }}>
            <CalendarOutlined style={{ marginRight: 6 }} />
            {dayjs(dateKey).format('dddd, MMMM D')}
          </Text>
          <Button
            type="text"
            size="small"
            icon={<CloseOutlined />}
            onClick={() => removeDate(dateKey)}
            style={{ color: 'rgba(255,255,255,0.45)' }}
          />
        </div>
        {items.length > 0 && items.map(renderItemCard)}
        {items.length === 0 && !isPast ? (
          <EventSubmissionForm
            initialDate={dateKey}
            gancioUrl={gancioUrl}
            onSuccess={handleEventSubmitted}
            canCreateMeeting={canCreateMeeting}
            meetEnabled={meetEnabled}
          />
        ) : items.length === 0 && isPast ? (
          <Text type="secondary" style={{ fontSize: 13, display: 'block', padding: '8px 0' }}>
            Nothing was scheduled
          </Text>
        ) : null}
      </div>
    );
  };

  // Mobile: date-grouped list fallback
  if (isMobile) {
    if (loading) {
      return (
        <div style={{ textAlign: 'center', padding: 40 }}>
          <Spin size="large" />
        </div>
      );
    }

    const sortedDates = Object.keys(calendarData?.dates || {}).sort();
    const upcomingDates = sortedDates.filter(d => d >= dayjs().format('YYYY-MM-DD'));

    if (upcomingDates.length === 0) {
      return <Empty description="No upcoming events or shifts" style={{ padding: 40 }} />;
    }

    return (
      <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
        {upcomingDates.map(dateKey => {
          const items = getDateItems(dateKey);
          return (
            <div key={dateKey}>
              <Text strong style={{ color: '#fff', fontSize: 14, display: 'block', marginBottom: 8 }}>
                <CalendarOutlined style={{ marginRight: 6 }} />
                {dayjs(dateKey).format('dddd, MMMM D')}
              </Text>
              {items.map(renderItemCard)}
            </div>
          );
        })}
      </div>
    );
  }

  const panelVisible = openDates.length > 0;

  // Desktop: Calendar + inline side panel
  return (
    <div style={{ display: 'flex', gap: 16, minHeight: 500 }}>
      <div style={{ flex: 1, minWidth: 0 }}>
        {loading && (
          <div style={{ textAlign: 'center', padding: 20 }}>
            <Spin />
          </div>
        )}
        <Calendar
          fullscreen
          cellRender={(date) => cellRender(date)}
          onSelect={handleSelect}
          onPanelChange={handlePanelChange}
        />
      </div>

      {/* Inline side panel — pushes calendar over, accumulates selected dates */}
      {panelVisible && (
        <div style={{ width: 380, flexShrink: 0 }}>
          <Card
            title={
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
                <span style={{ color: '#fff' }}>
                  <CalendarOutlined style={{ marginRight: 8 }} />
                  {openDates.length === 1 ? dayjs(openDates[0]).format('ddd, MMM D') : `${openDates.length} Dates`}
                </span>
                <Button
                  type="text"
                  size="small"
                  icon={<ClearOutlined />}
                  onClick={() => setOpenDates([])}
                  style={{ color: 'rgba(255,255,255,0.45)' }}
                >
                  Clear
                </Button>
              </div>
            }
            styles={{ body: { maxHeight: 'calc(100vh - 340px)', overflowY: 'auto', padding: '12px 16px' } }}
          >
            {openDates.map(renderDateSection)}
          </Card>
        </div>
      )}
    </div>
  );
}
