import { useState, useEffect, useRef, useCallback } from 'react';
import { format, addDays, startOfWeek, parseISO, differenceInDays, isSameDay } from 'date-fns';
import { ja } from 'date-fns/locale';
import { api } from '../api.js';
import { isInspectionExpirySoon, formatDateRange, formatReservationTooltip } from '../utils/carUtils.js';
import ReservationModal from './ReservationModal.jsx';
import styles from './ScheduleView.module.css';

const CELL_WIDTH = 52; // px per day column
const ROW_HEIGHT = 64; // px per car row
const LABEL_WIDTH = 140; // px for car name column
const HEADER_HEIGHT = 72; // px for the date header row
const DAYS_SHOWN = 21; // number of days to show

// Detect touch-primary device to disable mouse-only drag & drop
const isTouchDevice = typeof window !== 'undefined' &&
  ('ontouchstart' in window || navigator.maxTouchPoints > 0);

// Palette for reservation colors (cycle through them by car index)
const COLORS = [
  { bg: '#dbeafe', border: '#3b82f6', text: '#1e3a8a' },
  { bg: '#dcfce7', border: '#22c55e', text: '#14532d' },
  { bg: '#fef9c3', border: '#eab308', text: '#713f12' },
  { bg: '#fce7f3', border: '#ec4899', text: '#831843' },
  { bg: '#ede9fe', border: '#8b5cf6', text: '#3b0764' },
  { bg: '#ffedd5', border: '#f97316', text: '#7c2d12' },
  { bg: '#e0f2fe', border: '#0ea5e9', text: '#0c4a6e' },
  { bg: '#f0fdf4', border: '#16a34a', text: '#14532d' },
];

function getColor(index) {
  return COLORS[index % COLORS.length];
}

function dateToStr(date) {
  return format(date, 'yyyy-MM-dd');
}

export default function ScheduleView({ reloadKey = 0 }) {
  const [cars, setCars] = useState([]);
  const [reservations, setReservations] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  // The first date shown in the grid
  const [viewStart, setViewStart] = useState(() =>
    startOfWeek(new Date(), { weekStartsOn: 1 })
  );

  // Drag-to-create state
  const [creating, setCreating] = useState(null);
  // { carId, startDateStr, endDateStr }

  // Drag-to-move state
  const [moving, setMoving] = useState(null);
  // { reservation, grabDayOffset, currentCarId, currentStartDate }

  // Modal state
  const [modal, setModal] = useState(null);
  // null | { mode: 'create', prefill: {...} } | { mode: 'edit', reservation: {...} }

  // Context menu state (right-click on reservation)
  const [contextMenu, setContextMenu] = useState(null);
  // null | { x, y, reservation }

  const gridRef = useRef(null);
  const movingRef = useRef(null); // keeps latest moving state for event handlers

  // Generate the array of dates shown
  const dates = Array.from({ length: DAYS_SHOWN }, (_, i) => addDays(viewStart, i));

  // --- Data loading ---
  const loadData = useCallback(async () => {
    try {
      setLoading(true);
      const [carsData, resData] = await Promise.all([api.getCars(), api.getReservations()]);
      setCars(carsData);
      setReservations(resData);
      setError(null);
    } catch (e) {
      setError(e.message);
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    loadData();
  }, [loadData, reloadKey]);

  // --- Navigation ---
  const prevWeek = () => setViewStart((d) => addDays(d, -7));
  const nextWeek = () => setViewStart((d) => addDays(d, 7));
  const goToday = () => setViewStart(startOfWeek(new Date(), { weekStartsOn: 1 }));

  // --- Grid position helpers ---
  // Given a mouse clientX within the grid scroll area, get the day index (0-based)
  const getColFromX = useCallback((clientX) => {
    if (!gridRef.current) return -1;
    const rect = gridRef.current.getBoundingClientRect();
    const scrollLeft = gridRef.current.scrollLeft;
    const x = clientX - rect.left + scrollLeft - LABEL_WIDTH;
    if (x < 0) return -1;
    return Math.floor(x / CELL_WIDTH);
  }, []);

  const getRowFromY = useCallback((clientY) => {
    if (!gridRef.current) return -1;
    const rect = gridRef.current.getBoundingClientRect();
    const scrollTop = gridRef.current.scrollTop;
    const y = clientY - rect.top + scrollTop - HEADER_HEIGHT;
    if (y < 0) return -1;
    return Math.floor(y / ROW_HEIGHT);
  }, []);

  // --- Cell drag to create ---
  const handleCellMouseDown = (e, carId, dateStr) => {
    if (isTouchDevice) return; // drag-to-create is mouse-only
    if (e.button !== 0) return;
    e.preventDefault();
    setCreating({ carId, startDateStr: dateStr, endDateStr: dateStr });
  };

  // --- Cell tap to create (touch devices) ---
  const handleCellClick = useCallback((e, carId) => {
    if (!isTouchDevice) return;
    const col = getColFromX(e.clientX);
    if (col >= 0 && col < DAYS_SHOWN) {
      const dateStr = dateToStr(dates[col]);
      setModal({
        mode: 'create',
        prefill: { car_id: carId, start_date: dateStr, end_date: dateStr },
      });
    }
  }, [dates, getColFromX]);

  const handleGridMouseMove = useCallback((e) => {
    if (creating) {
      const col = getColFromX(e.clientX);
      if (col >= 0 && col < DAYS_SHOWN) {
        const hoveredDate = dateToStr(dates[col]);
        setCreating((prev) => {
          if (!prev) return null;
          // Ensure start <= end
          const s = prev.startDateStr;
          const h = hoveredDate;
          return {
            ...prev,
            endDateStr: h >= s ? h : s,
            startDateStr: h < s ? h : prev.startDateStr,
          };
        });
      }
    }

    if (moving) {
      const col = getColFromX(e.clientX);
      const row = getRowFromY(e.clientY);
      movingRef.current = { ...movingRef.current };

      if (col >= 0 && col < DAYS_SHOWN) {
        const newStartCol = Math.max(0, col - moving.grabDayOffset);
        const duration = differenceInDays(
          parseISO(moving.reservation.end_date),
          parseISO(moving.reservation.start_date)
        );
        const clampedStartCol = Math.min(newStartCol, DAYS_SHOWN - 1 - duration);
        const newStartDate = dateToStr(dates[Math.max(0, clampedStartCol)]);
        const newEndDate = dateToStr(addDays(dates[Math.max(0, clampedStartCol)], duration));

        let newCarId = moving.currentCarId;
        if (row >= 0 && row < cars.length) {
          newCarId = cars[row].id;
        }

        setMoving((prev) => prev ? {
          ...prev,
          currentCarId: newCarId,
          currentStartDate: newStartDate,
          currentEndDate: newEndDate,
          col: clampedStartCol,
          row: row >= 0 && row < cars.length ? row : prev.row,
        } : null);
      }
    }
  }, [creating, moving, dates, cars, getColFromX, getRowFromY]);

  const handleGridMouseUp = useCallback(async (e) => {
    if (creating) {
      const { carId, startDateStr, endDateStr } = creating;
      setCreating(null);
      // Open modal to confirm/fill details
      setModal({
        mode: 'create',
        prefill: {
          car_id: carId,
          start_date: startDateStr,
          end_date: endDateStr,
        },
      });
    }

    if (moving) {
      const { reservation, currentCarId, currentStartDate, currentEndDate } = moving;
      setMoving(null);
      movingRef.current = null;

      const duration = differenceInDays(
        parseISO(reservation.end_date),
        parseISO(reservation.start_date)
      );
      const newEndDate = currentEndDate ||
        dateToStr(addDays(parseISO(currentStartDate), duration));

      // Only update if something changed
      if (
        currentCarId !== reservation.car_id ||
        currentStartDate !== reservation.start_date
      ) {
        try {
          await api.updateReservation(reservation.id, {
            car_id: currentCarId,
            start_date: currentStartDate,
            end_date: newEndDate,
            customer_name: reservation.customer_name,
            notes: reservation.notes,
            start_period: reservation.start_period,
            end_period: reservation.end_period,
          });
          await loadData();
        } catch (err) {
          setError(`予約の移動に失敗しました: ${err.message}`);
          await loadData();
        }
      }
    }
  }, [creating, moving, loadData]);

  useEffect(() => {
    window.addEventListener('mousemove', handleGridMouseMove);
    window.addEventListener('mouseup', handleGridMouseUp);
    return () => {
      window.removeEventListener('mousemove', handleGridMouseMove);
      window.removeEventListener('mouseup', handleGridMouseUp);
    };
  }, [handleGridMouseMove, handleGridMouseUp]);

  // Close context menu on any click or Escape
  useEffect(() => {
    if (!contextMenu) return;
    const close = () => setContextMenu(null);
    const onKey = (e) => { if (e.key === 'Escape') close(); };
    window.addEventListener('click', close);
    window.addEventListener('keydown', onKey);
    return () => {
      window.removeEventListener('click', close);
      window.removeEventListener('keydown', onKey);
    };
  }, [contextMenu]);

  // --- Reservation drag to move ---
  const handleReservationMouseDown = (e, reservation) => {
    e.stopPropagation();
    if (isTouchDevice) return; // drag-to-move is mouse-only
    if (e.button !== 0) return;
    e.preventDefault();

    const col = getColFromX(e.clientX);
    const startCol = Math.max(0, dates.findIndex((d) => dateToStr(d) === reservation.start_date));
    const grabOffset = col >= 0 ? col - startCol : 0;
    const carRow = cars.findIndex((c) => c.id === reservation.car_id);

    setMoving({
      reservation,
      grabDayOffset: Math.max(0, grabOffset),
      currentCarId: reservation.car_id,
      currentStartDate: reservation.start_date,
      currentEndDate: reservation.end_date,
      col: startCol,
      row: carRow,
    });
  };

  // --- Modal save/delete handlers ---
  const handleModalSave = async (data) => {
    try {
      if (modal.mode === 'edit') {
        await api.updateReservation(modal.reservation.id, data);
      } else {
        await api.createReservation(data);
      }
      setModal(null);
      await loadData();
    } catch (e) {
      setError(`予約の保存に失敗しました: ${e.message}`);
    }
  };

  const handleModalDelete = async (id) => {
    try {
      await api.deleteReservation(id);
      setModal(null);
      await loadData();
    } catch (e) {
      setError(`予約の削除に失敗しました: ${e.message}`);
    }
  };

  // --- Rendering ---
  // Build a map of reservations visible in the date range
  const viewStartStr = dateToStr(viewStart);
  const viewEndStr = dateToStr(dates[dates.length - 1]);

  const visibleReservations = reservations.filter(
    (r) => r.end_date >= viewStartStr && r.start_date <= viewEndStr
  );

  // For each reservation, calculate its left/width in the grid
  function getReservationLayout(r) {
    const rStart = r.start_date < viewStartStr ? viewStartStr : r.start_date;
    const rEnd = r.end_date > viewEndStr ? viewEndStr : r.end_date;
    const startCol = differenceInDays(parseISO(rStart), viewStart);
    const endCol = differenceInDays(parseISO(rEnd), viewStart);
    const left = startCol * CELL_WIDTH;
    const width = (endCol - startCol + 1) * CELL_WIDTH;
    return { left, width, startCol, endCol };
  }

  // Create ghost for currently moving reservation
  const movingGhost = moving ? (() => {
    const duration = differenceInDays(
      parseISO(moving.reservation.end_date),
      parseISO(moving.reservation.start_date)
    );
    const col = moving.col ?? 0;
    const left = col * CELL_WIDTH;
    const width = (duration + 1) * CELL_WIDTH;
    return { col, left, width, row: moving.row };
  })() : null;

  // Today column
  const todayStr = dateToStr(new Date());

  const carColorMap = {};
  cars.forEach((car, i) => { carColorMap[car.id] = getColor(i); });

  return (
    <div className={styles.container}>
      {/* Toolbar */}
      <div className={styles.toolbar}>
        <div className={styles.navGroup}>
          <button className={styles.toolBtn} onClick={prevWeek}>‹ 前週</button>
          <button className={styles.toolBtn} onClick={goToday}>今日</button>
          <button className={styles.toolBtn} onClick={nextWeek}>次週 ›</button>
        </div>
        <div className={styles.dateRange}>
          {format(viewStart, 'yyyy年M月d日', { locale: ja })} 〜{' '}
          {format(dates[dates.length - 1], 'yyyy年M月d日', { locale: ja })}
        </div>
        <button
          className={styles.addBtn}
          onClick={() =>
            setModal({
              mode: 'create',
              prefill: {
                car_id: cars[0]?.id,
                start_date: todayStr,
                end_date: todayStr,
              },
            })
          }
        >
          + 予約を追加
        </button>
      </div>

      {error && <div className={styles.error}>エラー: {error}</div>}

      {/* Grid */}
      <div
        className={styles.gridWrapper}
        ref={gridRef}
        onMouseLeave={() => {
          // don't cancel on leave — handled by global events
        }}
      >
        {loading && (
          <div
            className={styles.loadingOverlay}
            style={{ height: HEADER_HEIGHT }}
          >
            読み込み中...
          </div>
        )}
        <div
          className={styles.grid}
          style={{ width: LABEL_WIDTH + DAYS_SHOWN * CELL_WIDTH }}
        >
          {/* Header row */}
          <div className={styles.headerRow} style={{ height: HEADER_HEIGHT }}>
            {/* Corner cell */}
            <div
              className={styles.cornerCell}
              style={{ width: LABEL_WIDTH, height: HEADER_HEIGHT }}
            />
            {/* Date headers */}
            {dates.map((date) => {
              const ds = dateToStr(date);
              const isToday = ds === todayStr;
              const dow = format(date, 'E', { locale: ja });
              const isWeekend = dow === '土' || dow === '日';
              return (
                <div
                  key={ds}
                  className={`${styles.dateHeader} ${isToday ? styles.todayHeader : ''} ${isWeekend ? styles.weekendHeader : ''}`}
                  style={{ width: CELL_WIDTH, height: HEADER_HEIGHT }}
                >
                  <span className={styles.dateDay}>{format(date, 'd')}</span>
                  <span className={`${styles.dateDow} ${isWeekend ? styles.weekendDow : ''}`}>{dow}</span>
                </div>
              );
            })}
          </div>

          {/* Car rows */}
          {cars.map((car, carIdx) => {
            const color = carColorMap[car.id];
            const carReservations = visibleReservations.filter((r) => {
              if (moving && r.id === moving.reservation.id) return false; // hide while moving
              return r.car_id === car.id;
            });

            // Creating highlight for this row
            const isCreatingRow = creating && creating.carId === car.id;
            let creatingLeft = 0, creatingWidth = 0;
            if (isCreatingRow) {
              const startCol = differenceInDays(parseISO(creating.startDateStr), viewStart);
              const endCol = differenceInDays(parseISO(creating.endDateStr), viewStart);
              creatingLeft = Math.max(0, startCol) * CELL_WIDTH;
              creatingWidth = (Math.min(endCol, DAYS_SHOWN - 1) - Math.max(0, startCol) + 1) * CELL_WIDTH;
            }

            // Ghost reservation for this row
            const showGhost = moving && moving.row === carIdx && movingGhost;

            return (
              <div key={car.id} className={styles.carRow} style={{ height: ROW_HEIGHT }}>
                {/* Car label */}
                <div
                  className={styles.carLabel}
                  style={{ width: LABEL_WIDTH, height: ROW_HEIGHT }}
                  title={car.description || car.name}
                >
                  <span className={styles.carDot} style={{ background: color.border }} />
                  <span className={styles.carLabelContent}>
                    <span className={styles.carName}>{car.name}</span>
                    <span className={styles.carBadges}>
                      {car.has_etc ? <span className={styles.badgeEtc}>ETC</span> : null}
                      {car.tire_type === 'スタッドレス' ? <span className={styles.badgeStudless}>スタッドレス</span> : null}
                    </span>
                    {isInspectionExpirySoon(car.inspection_expiry) ? (
                      <span
                        className={`${styles.badgeWarn} ${styles.badgeWarnWide}`}
                        title={`車検満了日: ${car.inspection_expiry}（まもなく期限切れ）`}
                      >
                        ⚠️ 車検
                      </span>
                    ) : null}
                  </span>
                </div>

                {/* Day cells */}
                <div
                  className={styles.cellArea}
                  style={{ width: DAYS_SHOWN * CELL_WIDTH, height: ROW_HEIGHT }}
                  onClick={(e) => handleCellClick(e, car.id)}
                >
                  {dates.map((date) => {
                    const ds = dateToStr(date);
                    const isToday = ds === todayStr;
                    const dow = format(date, 'E', { locale: ja });
                    const isWeekend = dow === '土' || dow === '日';
                    return (
                      <div
                        key={ds}
                        className={`${styles.cell} ${isToday ? styles.todayCell : ''} ${isWeekend ? styles.weekendCell : ''} ${isTouchDevice ? styles.cellTouch : ''}`}
                        style={{ width: CELL_WIDTH, height: ROW_HEIGHT }}
                        onMouseDown={(e) => handleCellMouseDown(e, car.id, ds)}
                      />
                    );
                  })}

                  {/* Creating highlight */}
                  {isCreatingRow && creatingWidth > 0 && (
                    <div
                      className={styles.creatingHighlight}
                      style={{
                        left: creatingLeft,
                        width: creatingWidth,
                        top: 4,
                        height: ROW_HEIGHT - 8,
                      }}
                    />
                  )}

                  {/* Ghost while moving */}
                  {showGhost && (
                    <div
                      className={styles.reservationBlock}
                      style={{
                        left: movingGhost.left,
                        width: movingGhost.width,
                        top: 5,
                        height: ROW_HEIGHT - 10,
                        background: color.bg,
                        borderColor: color.border,
                        color: color.text,
                        opacity: 0.6,
                        cursor: 'grabbing',
                      }}
                    >
                      <span className={styles.blockText}>
                        {moving.reservation.customer_name || '予約'}
                      </span>
                    </div>
                  )}

                  {/* Reservation blocks */}
                  {carReservations.map((r) => {
                    const { left, width } = getReservationLayout(r);
                    return (
                      <div
                        key={r.id}
                        className={styles.reservationBlock}
                        style={{
                          left,
                          width: width - 4,
                          top: 5,
                          height: ROW_HEIGHT - 10,
                          background: color.bg,
                          borderColor: color.border,
                          color: color.text,
                          cursor: isTouchDevice ? 'pointer' : 'grab',
                        }}
                        onMouseDown={(e) => handleReservationMouseDown(e, r)}
                        onClick={(e) => {
                          if (!moving) {
                            e.stopPropagation();
                            setModal({ mode: 'edit', reservation: r });
                          }
                        }}
                        onContextMenu={(e) => {
                          e.preventDefault();
                          e.stopPropagation();
                          setContextMenu({ x: e.clientX, y: e.clientY, reservation: r });
                        }}
                        title={formatReservationTooltip(r)}
                      >
                        <span className={styles.blockText}>
                          {r.customer_name || '予約'}
                        </span>
                        {width > 80 && (
                          <span className={styles.blockDates}>
                            {formatDateRange(r.start_date, r.start_period, r.end_date, r.end_period)}
                          </span>
                        )}
                      </div>
                    );
                  })}
                </div>
              </div>
            );
          })}

          {cars.length === 0 && !loading && (
            <div className={styles.noCars}>
              代車が登録されていません。「代車管理」から追加してください。
            </div>
          )}
        </div>
      </div>

      {/* Reservation Modal */}
      {modal && (
        <ReservationModal
          cars={cars}
          reservation={modal.mode === 'edit' ? modal.reservation : modal.prefill}
          onSave={handleModalSave}
          onDelete={handleModalDelete}
          onClose={() => setModal(null)}
        />
      )}

      {/* Right-click context menu */}
      {contextMenu && (
        <div
          className={styles.contextMenu}
          style={{ left: contextMenu.x, top: contextMenu.y }}
          onClick={(e) => e.stopPropagation()}
        >
          <button
            className={styles.contextMenuItem}
            onClick={() => {
              setModal({ mode: 'edit', reservation: contextMenu.reservation });
              setContextMenu(null);
            }}
          >
            ✏️ 編集
          </button>
          <button
            className={`${styles.contextMenuItem} ${styles.contextMenuItemDelete}`}
            onClick={async () => {
              setContextMenu(null);
              await handleModalDelete(contextMenu.reservation.id);
            }}
          >
            🗑️ 削除
          </button>
        </div>
      )}
    </div>
  );
}
