import React, { useState, useMemo, useRef, useEffect } from 'react';
import {
    DndContext,
    DragEndEvent,
    useSensor,
    useSensors,
    PointerSensor,
    DragOverlay
} from '@dnd-kit/core';
import {
    addMinutes,
    startOfDay,
    endOfDay,
    startOfWeek,
    endOfWeek,
    startOfMonth,
    endOfMonth,
    eachDayOfInterval,
    format,
    isSameDay
} from 'date-fns';
import { ChevronLeft, ChevronRight, ZoomIn, ZoomOut, Filter, Calendar as CalendarIcon, Undo, Redo, Clock, GripVertical } from 'lucide-react';
import clsx from 'clsx';
import TimelineRow from '../Timeline/TimelineRow';
import CurrentTimeIndicator from '../Timeline/CurrentTimeIndicator';
import Sidebar from './Sidebar';
import { Event, Resource, PendingAppointment } from '../../types';
import { calculateLayout } from '../../lib/layoutAlgorithm';
import { DEFAULT_PIXELS_PER_HOUR, SNAP_MINUTES } from '../../lib/timelineUtils';

import { useQuery } from '@tanstack/react-query';
import { adaptResources, adaptEvents, adaptPending } from '../../lib/uiAdapter';
import apiClient from '../../api/client';

type ViewMode = 'day' | 'week' | 'month';

export const Timeline: React.FC = () => {
    // Data Fetching
    const { data: resources = [] } = useQuery({
        queryKey: ['resources'],
        queryFn: async () => {
            const response = await apiClient.get('/resources/');
            return adaptResources(response.data);
        }
    });

    const { data: backendAppointments = [] } = useQuery({ // Renamed to backendAppointments to avoid conflict with localEvents
        queryKey: ['appointments'],
        queryFn: async () => {
            const response = await apiClient.get('/appointments/');
            return response.data; // Still return raw data, adapt in useEffect
        }
    });

    // State
    const [localEvents, setLocalEvents] = useState<Event[]>([]);
    const [localPending, setLocalPending] = useState<PendingAppointment[]>([]);

    // Sync remote data to local state (for optimistic UI updates later)
    useEffect(() => {
        if (backendAppointments.length > 0) {
            setLocalEvents(adaptEvents(backendAppointments));
            setLocalPending(adaptPending(backendAppointments));
        }
    }, [backendAppointments]);

    const [viewMode, setViewMode] = useState<ViewMode>('day');
    const [currentDate, setCurrentDate] = useState(new Date());
    const [pixelsPerHour, setPixelsPerHour] = useState(DEFAULT_PIXELS_PER_HOUR);
    const [activeDragItem, setActiveDragItem] = useState<any>(null);

    const timelineScrollRef = useRef<HTMLDivElement>(null);
    const sidebarScrollRef = useRef<HTMLDivElement>(null);
    const hasScrolledRef = useRef(false);

    // Sensors for drag detection
    const sensors = useSensors(
        useSensor(PointerSensor, {
            activationConstraint: {
                distance: 5,
            },
        })
    );

    // Calculate view range
    const { startTime, endTime, days } = useMemo(() => {
        let start, end;

        if (viewMode === 'day') {
            start = startOfDay(currentDate);
            end = endOfDay(currentDate);
        } else if (viewMode === 'week') {
            start = startOfWeek(currentDate, { weekStartsOn: 1 });
            end = endOfWeek(currentDate, { weekStartsOn: 1 });
        } else {
            start = startOfMonth(currentDate);
            end = endOfMonth(currentDate);
        }

        const days = eachDayOfInterval({ start, end });
        return { startTime: start, endTime: end, days };
    }, [viewMode, currentDate]);

    // Calculate Layouts for Sidebar Sync
    const resourceLayouts = useMemo<ResourceLayout[]>(() => {
        return resources.map(resource => {
            const resourceEvents = localEvents.filter(e => e.resourceId === resource.id);
            const eventsWithLanes = calculateLayout(resourceEvents);
            const maxLane = Math.max(0, ...eventsWithLanes.map(e => e.laneIndex || 0));
            const height = (maxLane + 1) * 40 + 20; // 40 is eventHeight, 20 is padding

            return {
                resourceId: resource.id,
                resourceName: resource.name,
                height,
                laneCount: maxLane + 1
            };
        });
    }, [resources, localEvents]);

    // Scroll Sync Logic
    const handleTimelineScroll = () => {
        if (timelineScrollRef.current && sidebarScrollRef.current) {
            sidebarScrollRef.current.scrollTop = timelineScrollRef.current.scrollTop;
        }
    };

    // Date Range Label
    const getDateRangeLabel = () => {
        if (viewMode === 'day') {
            return format(currentDate, 'EEEE, MMMM d, yyyy');
        } else if (viewMode === 'week') {
            const start = startOfWeek(currentDate, { weekStartsOn: 1 });
            const end = endOfWeek(currentDate, { weekStartsOn: 1 });
            return `${format(start, 'MMM d')} - ${format(end, 'MMM d, yyyy')}`;
        } else {
            return format(currentDate, 'MMMM yyyy');
        }
    };

    // Auto-scroll
    useEffect(() => {
        if (timelineScrollRef.current && !hasScrolledRef.current) {
            const indicator = document.getElementById('current-time-indicator');
            if (indicator) {
                indicator.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' });
                hasScrolledRef.current = true;
            }
        }
    }, [startTime, viewMode]);

    useEffect(() => {
        hasScrolledRef.current = false;
    }, [viewMode]);

    const handleDragStart = (event: any) => {
        setActiveDragItem(event.active.data.current);
    };

    // Handle Drag End
    const handleDragEnd = (event: DragEndEvent) => {
        const { active, delta, over } = event;
        setActiveDragItem(null);
        if (!active) return;

        let newResourceId: number | undefined;
        if (over && over.id.toString().startsWith('resource-')) {
            newResourceId = Number(over.id.toString().replace('resource-', ''));
        }

        // Handle Pending Event Drop
        if (active.data.current?.type === 'pending') {
            if (newResourceId) {
                const pendingId = Number(active.id.toString().replace('pending-', ''));
                const pendingItem = localPending.find(p => p.id === pendingId);

                if (pendingItem) {
                    const dropRect = active.rect.current.translated;
                    const containerRect = timelineScrollRef.current?.getBoundingClientRect();

                    if (dropRect && containerRect) {
                        // Calculate relative X position in the timeline content
                        const relativeX = dropRect.left - containerRect.left + (timelineScrollRef.current?.scrollLeft || 0);

                        const pixelsPerMinute = pixelsPerHour / 60;
                        const minutesFromStart = Math.max(0, relativeX / pixelsPerMinute);
                        const snappedMinutes = Math.round(minutesFromStart / SNAP_MINUTES) * SNAP_MINUTES;

                        const newStart = addMinutes(startTime, snappedMinutes);
                        const newEnd = addMinutes(newStart, pendingItem.durationMinutes);

                        const newEvent: Event = {
                            id: Date.now(),
                            resourceId: newResourceId,
                            title: pendingItem.customerName,
                            start: newStart,
                            end: newEnd,
                            status: 'CONFIRMED'
                        };

                        setLocalEvents(prev => [...prev, newEvent]);
                        setLocalPending(prev => prev.filter(p => p.id !== pendingId));
                    }
                }
            }
            return;
        }

        // Handle Existing Event Drag
        const eventId = Number(active.id.toString().replace('event-', ''));
        setLocalEvents(prev => prev.map(e => {
            if (e.id === eventId) {
                const minutesShift = Math.round(delta.x / (pixelsPerHour / 60));
                const snappedShift = Math.round(minutesShift / SNAP_MINUTES) * SNAP_MINUTES;

                const updates: Partial<Event> = {};

                if (snappedShift !== 0) {
                    updates.start = addMinutes(e.start, snappedShift);
                    updates.end = addMinutes(e.end, snappedShift);
                }

                if (newResourceId !== undefined && newResourceId !== e.resourceId) {
                    updates.resourceId = newResourceId;
                }

                return { ...e, ...updates };
            }
            return e;
        }));
    };

    const handleResizeStart = (_e: React.MouseEvent, direction: 'left' | 'right', id: number) => {
        console.log('Resize started', direction, id);
    };

    const handleZoomIn = () => setPixelsPerHour(prev => Math.min(prev + 20, 300));
    const handleZoomOut = () => setPixelsPerHour(prev => Math.max(prev - 20, 40));

    return (
        <div className="flex flex-col h-full overflow-hidden select-none bg-white dark:bg-gray-900 transition-colors duration-200">
            {/* Header Bar */}
            <div className="flex items-center justify-between px-6 py-4 bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 shadow-sm shrink-0 z-10 transition-colors duration-200">
                <div className="flex items-center gap-4">
                    {/* Date Navigation */}
                    <div className="flex items-center gap-2">
                        <button
                            onClick={() => setCurrentDate(d => addMinutes(d, viewMode === 'day' ? -1440 : -10080))}
                            className="p-1.5 text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors"
                            title="Previous"
                        >
                            <ChevronLeft size={20} />
                        </button>
                        <div className="flex items-center gap-2 px-3 py-1.5 bg-gray-100 dark:bg-gray-700 rounded-md text-gray-700 dark:text-gray-200 font-medium transition-colors duration-200 w-[320px] justify-center">
                            <CalendarIcon size={16} />
                            <span className="text-center">{getDateRangeLabel()}</span>
                        </div>
                        <button
                            onClick={() => setCurrentDate(d => addMinutes(d, viewMode === 'day' ? 1440 : 10080))}
                            className="p-1.5 text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors"
                            title="Next"
                        >
                            <ChevronRight size={20} />
                        </button>
                    </div>

                    {/* View Mode Switcher */}
                    <div className="flex items-center gap-1 border-l border-gray-300 dark:border-gray-600 pl-4">
                        {(['day', 'week', 'month'] as const).map((mode) => (
                            <button
                                key={mode}
                                onClick={() => setViewMode(mode)}
                                className={clsx(
                                    "px-3 py-1.5 text-sm font-medium rounded transition-colors capitalize",
                                    viewMode === mode
                                        ? "bg-blue-500 text-white"
                                        : "text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700"
                                )}
                            >
                                {mode}
                            </button>
                        ))}
                    </div>

                    {/* Zoom Controls */}
                    <div className="flex items-center gap-2">
                        <button
                            className="p-1.5 text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors"
                            onClick={handleZoomOut}
                        >
                            <ZoomOut size={16} />
                        </button>
                        <span className="text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wide">Zoom</span>
                        <button
                            className="p-1.5 text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors"
                            onClick={handleZoomIn}
                        >
                            <ZoomIn size={16} />
                        </button>
                    </div>

                    {/* Undo/Redo */}
                    <div className="flex items-center gap-1 border-l border-gray-300 dark:border-gray-600 pl-4">
                        <button className="p-2 text-gray-300 dark:text-gray-600 cursor-not-allowed rounded" disabled>
                            <Undo size={18} />
                        </button>
                        <button className="p-2 text-gray-300 dark:text-gray-600 cursor-not-allowed rounded" disabled>
                            <Redo size={18} />
                        </button>
                    </div>
                </div>

                <div className="flex items-center gap-3">
                    <button className="flex items-center gap-2 px-4 py-2 text-sm font-medium text-white bg-blue-600 rounded-lg hover:bg-blue-700 transition-colors shadow-sm">
                        + New Appointment
                    </button>
                    <button className="p-2 text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg border border-gray-200 dark:border-gray-600 transition-colors">
                        <Filter size={18} />
                    </button>
                </div>
            </div>

            {/* Main Layout */}
            <div className="flex flex-1 overflow-hidden">
                <DndContext sensors={sensors} onDragStart={handleDragStart} onDragEnd={handleDragEnd}>
                    {/* Sidebar (Resources + Pending) */}
                    <Sidebar
                        resourceLayouts={resourceLayouts}
                        pendingAppointments={localPending}
                        scrollRef={sidebarScrollRef}
                    />

                    {/* Timeline Grid */}
                    <div className="flex-1 flex flex-col overflow-hidden bg-white dark:bg-gray-900 relative transition-colors duration-200">
                        <div
                            ref={timelineScrollRef}
                            onScroll={handleTimelineScroll}
                            className="flex-1 overflow-auto timeline-scroll"
                        >
                            <div className="min-w-max relative min-h-full">
                                {/* Current Time Indicator */}
                                <div className="absolute inset-y-0 left-0 right-0 pointer-events-none z-40">
                                    <CurrentTimeIndicator startTime={startTime} hourWidth={pixelsPerHour} />
                                </div>

                                {/* Header Row */}
                                <div className="sticky top-0 z-10 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 transition-colors duration-200">
                                    <div className="flex" style={{ height: 48 }}>
                                        {viewMode === 'day' ? (
                                            Array.from({ length: 24 }).map((_, i) => (
                                                <div
                                                    key={i}
                                                    className="flex-shrink-0 border-r border-gray-100 dark:border-gray-700/50 p-2 text-sm text-gray-500 font-medium box-border"
                                                    style={{ width: pixelsPerHour }}
                                                >
                                                    {format(new Date().setHours(i, 0, 0, 0), 'h a')}
                                                </div>
                                            ))
                                        ) : viewMode === 'week' ? (
                                            days.map((day, i) => (
                                                <div
                                                    key={i}
                                                    className="flex-shrink-0 border-r border-gray-300 dark:border-gray-600"
                                                    style={{ width: pixelsPerHour * 24 }}
                                                >
                                                    <div className={clsx(
                                                        "p-2 text-sm font-bold text-center border-b border-gray-100 dark:border-gray-700",
                                                        isSameDay(day, new Date()) ? "bg-blue-50 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400" : "bg-gray-50 dark:bg-gray-800 text-gray-700 dark:text-gray-300"
                                                    )}>
                                                        {format(day, 'EEEE, MMM d')}
                                                    </div>
                                                    <div className="flex">
                                                        {Array.from({ length: 24 }).map((_, h) => (
                                                            <div
                                                                key={h}
                                                                className="flex-shrink-0 border-r border-gray-100 dark:border-gray-700/50 p-1 text-xs text-gray-400 text-center"
                                                                style={{ width: pixelsPerHour }}
                                                            >
                                                                {h % 6 === 0 ? format(new Date().setHours(h, 0, 0, 0), 'h a') : ''}
                                                            </div>
                                                        ))}
                                                    </div>
                                                </div>
                                            ))
                                        ) : (
                                            days.map((day, i) => (
                                                <div
                                                    key={i}
                                                    className={clsx(
                                                        "flex-shrink-0 border-r border-gray-100 dark:border-gray-700/50 p-2 text-sm font-medium text-center",
                                                        isSameDay(day, new Date()) ? "bg-blue-50 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400" : "text-gray-500"
                                                    )}
                                                    style={{ width: 100 }}
                                                >
                                                    {format(day, 'd')}
                                                </div>
                                            ))
                                        )}
                                    </div>
                                </div>

                                {/* Resource Rows (Grid Only) */}
                                {resourceLayouts.map(layout => (
                                    <TimelineRow
                                        key={layout.resourceId}
                                        resourceId={layout.resourceId}
                                        events={localEvents.filter(e => e.resourceId === layout.resourceId)}
                                        startTime={startTime}
                                        endTime={endTime}
                                        hourWidth={pixelsPerHour}
                                        eventHeight={40}
                                        height={layout.height}
                                        onResizeStart={handleResizeStart}
                                    />
                                ))}
                            </div>
                        </div>
                    </div>

                    {/* Drag Overlay for Visual Feedback */}
                    <DragOverlay>
                        {activeDragItem ? (
                            <div className="p-3 bg-white dark:bg-gray-700 border border-l-4 border-gray-200 dark:border-gray-600 border-l-orange-400 dark:border-l-orange-500 rounded shadow-lg opacity-80 w-64">
                                <div className="flex items-start justify-between">
                                    <div>
                                        <p className="font-semibold text-sm text-gray-900 dark:text-white">{activeDragItem.title}</p>
                                    </div>
                                    <GripVertical size={14} className="text-gray-400" />
                                </div>
                                <div className="mt-2 flex items-center gap-1 text-xs text-gray-400 dark:text-gray-500">
                                    <Clock size={10} />
                                    <span>{activeDragItem.duration} min</span>
                                </div>
                            </div>
                        ) : null}
                    </DragOverlay>
                </DndContext>
            </div>
        </div>
    );
};

export default Timeline;
