import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils';
import { ChevronLeft, ChevronRight, Dumbbell, Plus, UserX, Users } from 'lucide-react';
import { useEffect, useRef } from 'react';
import { useBooking } from '../booking-provider';
import type { BookingCourtSchedule, BookingTimelineSegment } from '../booking.types';
import { timeToMinutes } from '../lib/booking-time';
import { BookingStatusLegend } from './booking-status-legend';

const courtInfoWidth = 220;
const hourWidth = 104;

export function BookingTimeline() {
  const {
    schedules,
    timelineHours,
    visibleTimeRange,
    currentTime,
    isLoading,
    isError,
    errorMessage,
  } = useBooking();

  const scrollRef = useRef<HTMLDivElement>(null);
  const prevCurrentTimeRef = useRef<string | null>(null);

  const rangeStart = timeToMinutes(visibleTimeRange.start);
  const rangeEnd = timeToMinutes(visibleTimeRange.end);
  const totalMinutes = rangeEnd - rangeStart;
  const gridWidth = Math.max((timelineHours.length - 1) * hourWidth, 760);
  const timelineMarks = timelineHours.map((hour) => ({
    hour,
    left: ((timeToMinutes(hour) - rangeStart) / totalMinutes) * 100,
  }));

  useEffect(() => {
    if (!currentTime || !scrollRef.current) return;
    if (currentTime === prevCurrentTimeRef.current) return;
    prevCurrentTimeRef.current = currentTime;

    const container = scrollRef.current;
    const indicatorLeft =
      courtInfoWidth + ((timeToMinutes(currentTime) - rangeStart) / totalMinutes) * gridWidth;
    const targetScroll = indicatorLeft - container.clientWidth / 2;
    const clampedScroll = Math.max(
      0,
      Math.min(targetScroll, container.scrollWidth - container.clientWidth)
    );

    requestAnimationFrame(() => {
      container.scrollTo({ left: clampedScroll, behavior: 'smooth' });
    });
  }, [currentTime, rangeStart, totalMinutes, gridWidth]);

  return (
    <section className="overflow-hidden rounded-lg border bg-card/85 shadow-sm">
      <div className="flex items-center justify-between gap-4 border-b px-4 py-4">
        <BookingStatusLegend />
        <div className="hidden items-center gap-2 md:flex">
          <Button type="button" size="icon-sm" variant="ghost">
            <ChevronLeft className="size-4" />
          </Button>
          <Button type="button" size="icon-sm" variant="ghost">
            <ChevronRight className="size-4" />
          </Button>
        </div>
      </div>

      {isLoading && (
        <div className="px-4 py-10 text-sm text-muted-foreground">Cargando reservas...</div>
      )}

      {isError && !isLoading && (
        <div className="px-4 py-10 text-sm text-destructive">{errorMessage}</div>
      )}

      {!isLoading && !isError && schedules.length === 0 && (
        <div className="px-4 py-10 text-sm text-muted-foreground">
          No hay canchas para los filtros seleccionados.
        </div>
      )}

      {!isLoading && !isError && schedules.length > 0 && (
        <div ref={scrollRef} className="booking-scrollbar overflow-x-auto overflow-y-hidden">
          <div className="relative min-w-full" style={{ width: courtInfoWidth + gridWidth }}>
            <TimelineHeader
              timelineMarks={timelineMarks}
              courtInfoWidth={courtInfoWidth}
              gridWidth={gridWidth}
            />

            <div className="divide-y">
              {schedules.map((schedule) => (
                <BookingCourtRow
                  key={schedule.court.id}
                  schedule={schedule}
                  courtInfoWidth={courtInfoWidth}
                  gridWidth={gridWidth}
                  rangeStart={rangeStart}
                  totalMinutes={totalMinutes}
                  timelineMarks={timelineMarks}
                />
              ))}
            </div>

            {currentTime && (
              <CurrentTimeIndicator
                time={currentTime}
                courtInfoWidth={courtInfoWidth}
                gridWidth={gridWidth}
                rangeStart={rangeStart}
                totalMinutes={totalMinutes}
              />
            )}
          </div>
        </div>
      )}
    </section>
  );
}

interface TimelineHeaderProps {
  timelineMarks: Array<{ hour: string; left: number }>;
  courtInfoWidth: number;
  gridWidth: number;
}

function TimelineHeader({ timelineMarks, courtInfoWidth, gridWidth }: TimelineHeaderProps) {
  return (
    <div
      className="sticky top-0 z-20 grid border-b bg-card/95 z-auto"
      style={{ gridTemplateColumns: `${courtInfoWidth}px ${gridWidth}px` }}
    >
      <div className="sticky left-0 z-30 border-r bg-card/95 px-4 py-3 shadow-[8px_0_18px_-18px_oklch(0_0_0/0.45)]" />
      <div className="relative h-12">
        {timelineMarks.map((mark) => (
          <div
            key={mark.hour}
            className="absolute top-0 flex h-full items-center border-l px-3 text-sm text-muted-foreground first:border-l-0"
            style={{ left: `${mark.left}%` }}
          >
            {mark.hour}
          </div>
        ))}
      </div>
    </div>
  );
}

interface BookingCourtRowProps {
  schedule: BookingCourtSchedule;
  courtInfoWidth: number;
  gridWidth: number;
  rangeStart: number;
  totalMinutes: number;
  timelineMarks: Array<{ hour: string; left: number }>;
}

function BookingCourtRow({
  schedule,
  courtInfoWidth,
  gridWidth,
  rangeStart,
  totalMinutes,
  timelineMarks,
}: BookingCourtRowProps) {
  return (
    <div
      className="grid min-h-[96px]"
      style={{ gridTemplateColumns: `${courtInfoWidth}px ${gridWidth}px` }}
    >
      <BookingCourtInfo schedule={schedule} />
      <div className="relative bg-background/20 py-4">
        <div className="absolute inset-y-0 left-0 right-0 opacity-70">
          {timelineMarks.map((mark) => (
            <span
              key={mark.hour}
              className="absolute top-0 h-full border-l first:border-l-0"
              style={{ left: `${mark.left}%` }}
            />
          ))}
        </div>

        <div className="relative h-16">
          {schedule.segments.map((segment) => (
            <BookingSlotBlock
              key={segment.id}
              segment={segment}
              schedule={schedule}
              rangeStart={rangeStart}
              totalMinutes={totalMinutes}
            />
          ))}
        </div>
      </div>
    </div>
  );
}

function BookingCourtInfo({ schedule }: { schedule: BookingCourtSchedule }) {
  return (
    <div className="sticky left-0 z-10 flex items-center gap-3 border-r bg-card/95 px-4 py-4 shadow-[8px_0_18px_-18px_oklch(0_0_0/0.45)]">
      <div className="flex size-12 shrink-0 items-center justify-center rounded-lg border border-primary/40 bg-primary/15 text-primary">
        <Dumbbell className="size-6" />
      </div>
      <div className="min-w-0">
        <h2 className="truncate text-base font-semibold">{schedule.court.name}</h2>
        <p className="truncate text-sm text-muted-foreground">{schedule.court.sport.name}</p>
        <div className="mt-1 flex items-center gap-3 text-xs text-muted-foreground">
          <span className="inline-flex items-center gap-1">
            <span className="size-2 rounded-full bg-primary" />
            {schedule.metrics.free}
          </span>
          <span className="inline-flex items-center gap-1">
            <span className="size-2 rounded-full bg-reserved" />
            {schedule.metrics.reserved}
          </span>
          <span className="inline-flex items-center gap-1">
            <span className="size-2 rounded-full bg-maintenance" />
            {schedule.metrics.maintenance}
          </span>
        </div>
      </div>
    </div>
  );
}

interface BookingSlotBlockProps {
  segment: BookingTimelineSegment;
  schedule: BookingCourtSchedule;
  rangeStart: number;
  totalMinutes: number;
}

function BookingSlotBlock({ segment, schedule, rangeStart, totalMinutes }: BookingSlotBlockProps) {
  const { openCreateBooking, updateBookingStatus, openBookingTools } = useBooking();
  const left = ((segment.startMinutes - rangeStart) / totalMinutes) * 100;
  const width = ((segment.endMinutes - segment.startMinutes) / totalMinutes) * 100;
  const isFree = segment.status === 'free';

  return (
    <button
      type="button"
      className={cn(
        'absolute top-0 flex h-16 min-w-0 flex-col justify-center overflow-hidden rounded-md border px-2 text-left text-xs shadow-sm transition-all hover:-translate-y-0.5 hover:shadow-md focus-visible:ring-2 focus-visible:ring-ring',
        segment.status === 'free' &&
          'border-primary/70 bg-primary/20 text-primary hover:bg-primary/25',
        segment.status === 'reserved' &&
          'border-reserved/70 bg-reserved/80 text-reserved-foreground',
        segment.status === 'maintenance' &&
          'border-maintenance/80 bg-maintenance/75 text-maintenance-foreground',
        segment.booking?.status === 'COMPLETED' &&
          'border-reserved/70 bg-reserved/25 dark:text-reserved-foreground text-gray-600 line-through',
        segment.booking?.status === 'NOSHOW' &&
          'border-amber-500/60 bg-amber-500/50 text-amber-950 dark:text-amber-200'
      )}
      style={{
        left: `calc(${left}% + 4px)`,
        width: `calc(${width}% - 8px)`,
      }}
      onClick={(event) => {
        if (isFree) {
          openCreateBooking({
            courtId: schedule.court.id,
            startTime: segment.startTime,
            sportId: schedule.court.sportId,
          });
        } else if (segment.booking?.status === 'NOSHOW') {
          return;
        } else {
          if (event.shiftKey && segment.booking?.status === 'CONFIRMED') {
            updateBookingStatus(segment.booking.id, 'COMPLETED');
          } else {
            openBookingTools(segment);
          }
        }
      }}
      title={
        segment.booking
          ? `${segment.booking.customerName} · ${segment.startTime} - ${segment.endTime}`
          : `${segment.startTime} - ${segment.endTime}`
      }
    >
      {isFree ? (
        <span className="flex items-center justify-center gap-1 text-sm font-medium">
          <Plus className="size-4" />
          <span className="hidden sm:inline">Reservar</span>
        </span>
      ) : (
        <>
          <div className="flex items-center justify-between">
            <span className="truncate text-sm font-medium">
              {segment.startTime} - {segment.endTime}
            </span>
            {segment.booking?.status === 'NOSHOW' && (
              <span title="No Show - El cliente no se presentó">
                <UserX className="size-3 shrink-0" />
              </span>
            )}
          </div>
          <span className="mt-1 flex items-center gap-1 truncate opacity-90">
            <Users className="size-3" />
            {segment.booking?.customerName ?? 'Mantenimiento'}
          </span>
        </>
      )}
    </button>
  );
}

interface CurrentTimeIndicatorProps {
  time: string;
  courtInfoWidth: number;
  gridWidth: number;
  rangeStart: number;
  totalMinutes: number;
}

function CurrentTimeIndicator({
  time,
  courtInfoWidth,
  gridWidth,
  rangeStart,
  totalMinutes,
}: CurrentTimeIndicatorProps) {
  const left = courtInfoWidth + ((timeToMinutes(time) - rangeStart) / totalMinutes) * gridWidth;

  return (
    <div className="pointer-events-none absolute bottom-0 top-12 z-[5]" style={{ left }}>
      <div className="absolute left-0 top-0 -translate-x-1/2 -translate-y-1/2 rounded-md bg-primary px-2 py-1 text-xs font-medium text-primary-foreground shadow-sm">
        {time}
      </div>
      <div className="absolute bottom-0 left-0 top-0 w-px bg-primary" />
    </div>
  );
}
