import { useState, useEffect, useMemo, useCallback } from 'react';
import {
  Calendar, ChevronLeft, ChevronRight, Clock,
  ToggleLeft, ToggleRight,
} from 'lucide-react';
import {
  startOfWeek, endOfWeek, subWeeks, addWeeks, addDays, format,
  isToday, parseISO, differenceInMinutes, isAfter,
} from 'date-fns';
import { cn } from '../../utils/helpers';
import { useAuthStore } from '../../store/useAuthStore';
import { usePractitionerStore } from '../store/usePractitionerStore';
import type { APIHospitalVisit } from '../../services/medical';

/* ═══════════════════════════════════════════════════════════════════════
   CONSTANTS
   ═══════════════════════════════════════════════════════════════════════ */

const START_HOUR = 8;
const END_HOUR = 19;
const SLOT_HEIGHT = 52;
const SLOTS = (END_HOUR - START_HOUR) * 2;
const GRID_HEIGHT = SLOTS * SLOT_HEIGHT;

const HOURS = Array.from({ length: END_HOUR - START_HOUR + 1 }, (_, i) => START_HOUR + i);
const HALF_HOURS = Array.from({ length: SLOTS }, (_, i) => {
  const h = START_HOUR + Math.floor(i / 2);
  const m = (i % 2) * 30;
  return `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;
});

const TYPE_COLORS: Record<string, { bg: string; border: string; text: string }> = {
  Examination:  { bg: 'bg-primary/10',    border: 'border-primary/30',    text: 'text-primary' },
  Control:      { bg: 'bg-emerald-50',    border: 'border-emerald-200',   text: 'text-emerald-700' },
  Consultation: { bg: 'bg-violet-50',     border: 'border-violet-200',    text: 'text-violet-700' },
  'Follow-up':  { bg: 'bg-amber-50',      border: 'border-amber-200',     text: 'text-amber-700' },
};

const DEFAULT_COLOR = { bg: 'bg-sky-50', border: 'border-sky-200', text: 'text-sky-700' };

/* ═══════════════════════════════════════════════════════════════════════
   HELPERS
   ═══════════════════════════════════════════════════════════════════════ */

function initials(name: string) {
  return name.split(' ').map(n => n[0]).join('').slice(0, 2).toUpperCase();
}

function storageKey(id: string) { return `hipograf_availability_${id}`; }

function loadAvailability(id: string): Set<string> {
  try {
    const raw = localStorage.getItem(storageKey(id));
    return raw ? new Set(JSON.parse(raw)) : new Set();
  } catch { return new Set(); }
}

function saveAvailability(id: string, set: Set<string>) {
  localStorage.setItem(storageKey(id), JSON.stringify([...set]));
}

function slotKey(day: Date, time: string) {
  return `${format(day, 'yyyy-MM-dd')}_${time}`;
}

function visitPosition(visit: APIHospitalVisit) {
  const d = parseISO(visit.visitDate);
  const h = d.getHours();
  const m = d.getMinutes();
  if (h < START_HOUR || h >= END_HOUR) return null;

  const slotIndex = (h - START_HOUR) * 2 + Math.floor(m / 30);
  const minuteOffset = m % 30;
  const top = slotIndex * SLOT_HEIGHT + (minuteOffset / 30) * SLOT_HEIGHT;

  let durationMin = 30;
  if (visit.dischargeDate) {
    durationMin = Math.max(15, differenceInMinutes(parseISO(visit.dischargeDate), d));
  }
  const height = Math.max(SLOT_HEIGHT * 0.8, (durationMin / 30) * SLOT_HEIGHT);

  return { top, height };
}

function visitType(visit: APIHospitalVisit): string {
  return visit.department || 'Examination';
}

function patientName(visit: APIHospitalVisit, patients: { _id: string; dispName: string }[]): string {
  const p = patients.find(pt => pt._id === visit.patientId);
  return p?.dispName || 'Patient';
}

function isFuture(visit: APIHospitalVisit) {
  try { return isAfter(parseISO(visit.visitDate), new Date()); } catch { return false; }
}


/* ═══════════════════════════════════════════════════════════════════════
   COMPONENT
   ═══════════════════════════════════════════════════════════════════════ */

export default function SchedulePage() {
  const practitioner = useAuthStore(s => s.user);
  const { patients, appointments, appointmentsLoading, loadAppointments } = usePractitionerStore();

  const [weekStart, setWeekStart] = useState(() => startOfWeek(new Date(), { weekStartsOn: 1 }));
  const [availabilityMode, setAvailabilityMode] = useState(false);
  const [availability, setAvailability] = useState<Set<string>>(() =>
    loadAvailability(practitioner?._id || ''),
  );

  const weekEnd = useMemo(() => endOfWeek(weekStart, { weekStartsOn: 1 }), [weekStart]);
  const days = useMemo(() => Array.from({ length: 7 }, (_, i) => addDays(weekStart, i)), [weekStart]);

  // Load appointments for visible week
  useEffect(() => {
    loadAppointments(weekStart.toISOString(), weekEnd.toISOString());
  }, [weekStart, weekEnd, loadAppointments]);

  const appointmentsByDay = useMemo(() => {
    const map = new Map<string, APIHospitalVisit[]>();
    days.forEach(d => map.set(format(d, 'yyyy-MM-dd'), []));
    appointments.forEach(v => {
      try {
        const key = format(parseISO(v.visitDate), 'yyyy-MM-dd');
        map.get(key)?.push(v);
      } catch { /* skip malformed */ }
    });
    return map;
  }, [appointments, days]);

  const toggleAvailability = useCallback((day: Date, time: string) => {
    if (!practitioner) return;
    const key = slotKey(day, time);
    setAvailability(prev => {
      const next = new Set(prev);
      if (next.has(key)) next.delete(key); else next.add(key);
      saveAvailability(practitioner._id, next);
      return next;
    });
  }, [practitioner]);

  const goToday = () => setWeekStart(startOfWeek(new Date(), { weekStartsOn: 1 }));
  const goPrev = () => setWeekStart(w => subWeeks(w, 1));
  const goNext = () => setWeekStart(w => addWeeks(w, 1));

  const weekLabel = `${format(weekStart, 'MMM d')} – ${format(weekEnd, 'MMM d, yyyy')}`;

  return (
    <div className="space-y-5 animate-fade-in">
      {/* ── Header ───────────────────────────────────────────────── */}
      <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
        <div className="flex items-center gap-3">
          <div className="w-10 h-10 rounded-xl bg-primary/10 flex items-center justify-center">
            <Calendar className="w-5 h-5 text-primary" />
          </div>
          <div>
            <h1 className="text-[17px] font-bold text-gray-900 tracking-tight">Weekly Schedule</h1>
            <p className="text-[12px] text-gray-500">Your appointments and availability</p>
          </div>
        </div>

        {/* Availability toggle */}
        <button
          onClick={() => setAvailabilityMode(!availabilityMode)}
          className={cn(
            'flex items-center gap-2 px-3 py-2 rounded-xl text-[12px] font-medium border transition-all',
            availabilityMode
              ? 'bg-emerald-50 text-emerald-700 border-emerald-200'
              : 'bg-white text-gray-600 border-gray-200 hover:bg-gray-50',
          )}
        >
          {availabilityMode
            ? <ToggleRight className="w-4 h-4" />
            : <ToggleLeft className="w-4 h-4" />
          }
          {availabilityMode ? 'Editing Availability' : 'Manage Availability'}
        </button>
      </div>

      {/* ── Week Navigation ──────────────────────────────────────── */}
      <div className="bg-white rounded-2xl border border-gray-200 shadow-card">
        <div className="flex items-center justify-between px-5 py-3.5 border-b border-gray-100">
          <div className="flex items-center gap-2">
            <button onClick={goPrev} className="btn-icon w-8 h-8">
              <ChevronLeft className="w-4 h-4" />
            </button>
            <button onClick={goNext} className="btn-icon w-8 h-8">
              <ChevronRight className="w-4 h-4" />
            </button>
            <button
              onClick={goToday}
              className="px-3 py-1.5 rounded-lg text-[12px] font-medium text-gray-600 border border-gray-200 hover:bg-gray-50 transition-colors"
            >
              Today
            </button>
          </div>

          <h2 className="text-[14px] font-semibold text-gray-900 tracking-tight">{weekLabel}</h2>

          <div className="flex items-center gap-3">
            {Object.entries(TYPE_COLORS).map(([type, c]) => (
              <div key={type} className="flex items-center gap-1.5">
                <div className={cn('w-2.5 h-2.5 rounded-full', c.bg, 'border', c.border)} />
                <span className="text-[11px] text-gray-500">{type}</span>
              </div>
            ))}
          </div>
        </div>

        {/* ── Calendar Grid ──────────────────────────────────────── */}
        <div className="flex overflow-x-auto">
          {/* Time labels column */}
          <div className="flex-none w-[60px] border-r border-gray-100">
            <div className="h-[56px] border-b border-gray-100" />
            <div className="relative" style={{ height: GRID_HEIGHT }}>
              {HOURS.map(h => (
                <div
                  key={h}
                  className="absolute left-0 right-0 flex items-start justify-end pr-3 -mt-[7px]"
                  style={{ top: (h - START_HOUR) * 2 * SLOT_HEIGHT }}
                >
                  <span className="text-[11px] font-medium text-gray-400 tabular-nums">
                    {String(h).padStart(2, '0')}:00
                  </span>
                </div>
              ))}
            </div>
          </div>

          {/* Day columns */}
          {days.map((day, dayIdx) => {
            const dayKey = format(day, 'yyyy-MM-dd');
            const dayVisits = appointmentsByDay.get(dayKey) || [];
            const today = isToday(day);

            return (
              <div
                key={dayKey}
                className={cn(
                  'flex-1 min-w-[130px]',
                  dayIdx < 6 && 'border-r border-gray-100',
                )}
              >
                {/* Day header */}
                <div
                  className={cn(
                    'h-[56px] flex flex-col items-center justify-center border-b border-gray-100',
                    today && 'bg-primary/[0.03]',
                  )}
                >
                  <span className="text-[11px] font-semibold text-gray-400 uppercase tracking-wider">
                    {format(day, 'EEE')}
                  </span>
                  <span
                    className={cn(
                      'text-[15px] font-bold mt-0.5 tabular-nums',
                      today ? 'text-primary' : 'text-gray-900',
                    )}
                  >
                    {format(day, 'd')}
                  </span>
                </div>

                {/* Time slots */}
                <div className="relative" style={{ height: GRID_HEIGHT }}>
                  {HALF_HOURS.map((time, slotIdx) => {
                    const key = slotKey(day, time);
                    const isAvailable = availability.has(key);
                    const isHour = slotIdx % 2 === 0;

                    return (
                      <div
                        key={time}
                        onClick={() => {
                          if (availabilityMode) toggleAvailability(day, time);
                        }}
                        className={cn(
                          'absolute left-0 right-0 transition-colors duration-150',
                          isHour ? 'border-t border-gray-100' : 'border-t border-gray-50',
                          availabilityMode && 'cursor-pointer',
                          isAvailable && !availabilityMode && 'bg-emerald-50/40',
                          isAvailable && availabilityMode && 'bg-emerald-100/60',
                          !isAvailable && availabilityMode && 'hover:bg-emerald-50/50',
                          today && !isAvailable && !availabilityMode && 'bg-primary/[0.015]',
                        )}
                        style={{
                          top: slotIdx * SLOT_HEIGHT,
                          height: SLOT_HEIGHT,
                        }}
                      >
                        {availabilityMode && isAvailable && (
                          <div className="absolute inset-0 flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity">
                            <span className="text-[10px] font-medium text-emerald-600">Available</span>
                          </div>
                        )}
                      </div>
                    );
                  })}

                  {/* Current time indicator */}
                  {today && (() => {
                    const now = new Date();
                    const h = now.getHours();
                    const m = now.getMinutes();
                    if (h < START_HOUR || h >= END_HOUR) return null;
                    const top = ((h - START_HOUR) * 60 + m) / 30 * SLOT_HEIGHT;
                    return (
                      <div
                        className="absolute left-0 right-0 z-20 pointer-events-none"
                        style={{ top }}
                      >
                        <div className="flex items-center">
                          <div className="w-2.5 h-2.5 rounded-full bg-accent -ml-[5px]" />
                          <div className="flex-1 h-[2px] bg-accent" />
                        </div>
                      </div>
                    );
                  })()}

                  {/* Appointment blocks */}
                  {dayVisits.map(visit => {
                    const pos = visitPosition(visit);
                    if (!pos) return null;
                    const type = visitType(visit);
                    const colors = TYPE_COLORS[type] || DEFAULT_COLOR;
                    const name = patientName(visit, patients);
                    const time = format(parseISO(visit.visitDate), 'HH:mm');
                    const upcoming = isFuture(visit);

                    return (
                      <div
                        key={visit._id}
                        className={cn(
                          'absolute left-1 right-1 z-10 rounded-lg border px-2 py-1.5 overflow-hidden transition-shadow hover:shadow-md',
                          colors.bg, colors.border,
                          !upcoming && 'opacity-60',
                        )}
                        style={{ top: pos.top, height: pos.height }}
                      >
                        <div className="flex items-start gap-1.5 h-full">
                          <div className={cn(
                            'w-5 h-5 rounded-full flex-none flex items-center justify-center text-[8px] font-bold mt-0.5',
                            colors.bg, colors.text,
                            'border', colors.border,
                          )}>
                            {initials(name)}
                          </div>
                          <div className="min-w-0 flex-1">
                            <p className={cn('text-[11px] font-semibold truncate leading-tight', colors.text)}>
                              {name}
                            </p>
                            <p className="text-[10px] text-gray-500 flex items-center gap-1 mt-0.5">
                              <Clock className="w-2.5 h-2.5" />
                              {time}
                            </p>
                            {pos.height > SLOT_HEIGHT && (
                              <span className={cn(
                                'inline-block mt-1 px-1.5 py-0.5 rounded text-[9px] font-medium',
                                colors.bg, colors.text,
                              )}>
                                {type}
                              </span>
                            )}
                          </div>
                        </div>
                      </div>
                    );
                  })}
                </div>
              </div>
            );
          })}
        </div>

        {/* Loading overlay */}
        {appointmentsLoading && (
          <div className="flex items-center justify-center py-4 border-t border-gray-100">
            <div className="animate-spin h-5 w-5 border-2 border-primary border-t-transparent rounded-full" />
            <span className="ml-2 text-[12px] text-gray-500">Loading appointments...</span>
          </div>
        )}
      </div>

      {/* ── Legend / Help ─────────────────────────────────────────── */}
      {availabilityMode && (
        <div className="flex items-center gap-4 px-4 py-3 bg-emerald-50/50 rounded-xl border border-emerald-200/50 animate-fade-in">
          <div className="flex items-center gap-2">
            <div className="w-4 h-4 rounded bg-emerald-100/80 border border-emerald-200" />
            <span className="text-[12px] text-emerald-700">Click slots to mark as available</span>
          </div>
          <div className="flex items-center gap-2">
            <div className="w-4 h-4 rounded bg-white border border-gray-200" />
            <span className="text-[12px] text-gray-500">Unavailable</span>
          </div>
        </div>
      )}

      {/* ── Upcoming Today ───────────────────────────────────────── */}
      {(() => {
        const todayKey = format(new Date(), 'yyyy-MM-dd');
        const todayVisits = (appointmentsByDay.get(todayKey) || [])
          .filter(isFuture)
          .sort((a, b) => parseISO(a.visitDate).getTime() - parseISO(b.visitDate).getTime());

        if (!todayVisits.length) return null;

        return (
          <div className="bg-white rounded-2xl border border-gray-200 shadow-card p-5 animate-fade-in">
            <h3 className="text-[13px] font-bold text-gray-900 mb-3 flex items-center gap-2">
              <Clock className="w-4 h-4 text-primary" />
              Upcoming Today
            </h3>
            <div className="space-y-2">
              {todayVisits.map(visit => {
                const type = visitType(visit);
                const colors = TYPE_COLORS[type] || DEFAULT_COLOR;
                const name = patientName(visit, patients);
                return (
                  <div
                    key={visit._id}
                    className="flex items-center gap-3 px-3 py-2.5 rounded-xl bg-gray-50/50 border border-gray-100"
                  >
                    <div className="w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center text-primary text-[11px] font-bold">
                      {initials(name)}
                    </div>
                    <div className="flex-1 min-w-0">
                      <p className="text-[13px] font-medium text-gray-900 truncate">{name}</p>
                      <p className="text-[11px] text-gray-500">
                        {format(parseISO(visit.visitDate), 'HH:mm')} &middot; {visit.hospital}
                      </p>
                    </div>
                    <span className={cn(
                      'px-2 py-0.5 rounded-full text-[11px] font-medium border',
                      colors.bg, colors.text, colors.border,
                    )}>
                      {type}
                    </span>
                  </div>
                );
              })}
            </div>
          </div>
        );
      })()}
    </div>
  );
}
