import { useQuery, useQueryClient } from '@tanstack/react-query'
import { useState } from 'react'
import { Link, useSearchParams } from 'react-router-dom'
import {
  CookingPot, CalendarDays, ShoppingCart, ChevronRight, ChevronLeft, Sparkles, Loader2,
  GripVertical, X
} from 'lucide-react'
import toast from 'react-hot-toast'
import { showToast, showApiError } from '../lib/toast'
import { isoMonday, parseIsoDate, shiftIsoDate, formatIsoDate } from '../lib/utils'
import {
  DragDropContext,
  Droppable,
  Draggable,
  type DropResult,
  type DroppableProvided,
  type DraggableProvided,
  type DraggableProvidedDragHandleProps,
  type DraggableStateSnapshot,
  type DroppableStateSnapshot,
} from '@hello-pangea/dnd'
import { mealPlannerApi } from '../api'
import type { MealPlan, MealPlanItem } from '../types'
import { Badge } from '../components/ui/Badge'
import { Card, CardBody, CardHeader } from '../components/ui/Card'
import { SkeletonCard, Skeleton } from '../components/ui/Skeleton'
import { EmptyState } from '../components/ui/EmptyState'

const DAY_NAMES = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
const FULL_DAY_NAMES = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
const MEAL_TYPES = ['breakfast', 'lunch', 'dinner'] as const

/* ------------------------------------------------------------------ */
/*  MealCard (draggable)                                               */
/* ------------------------------------------------------------------ */
function MealCard({ item, dragHandleProps, isDragging, onApprove: _onApprove, onDeny: _onDeny, onDelete }: {
  item: MealPlanItem
  dragHandleProps?: DraggableProvidedDragHandleProps | null
  isDragging?: boolean
  onApprove?: (itemId: string) => void
  onDeny?: (itemId: string) => void
  onDelete?: (itemId: string) => void
}) {
  const totalTime = item.recipe?.total_time_minutes ??
    (item.recipe?.prep_time_minutes || 0) + (item.recipe?.cook_time_minutes || 0)

  const statusVariant =
    item.approval_status === 'approved' ? 'success' :
    item.approval_status === 'denied' ? 'danger' :
    item.approval_status === 'swapped' ? 'warning' :
    'neutral'

  return (
    <div className={`relative group block bg-surface-0 rounded-xl border overflow-hidden hover:shadow-md hover:border-primary-200 transition-all duration-200 ${isDragging ? 'shadow-lg border-primary-400 ring-2 ring-primary-200' : 'border-surface-200'}`}>
      {/* Keep delete visible on touch devices where hover is unavailable. */}
      {onDelete && (
        <button
          onClick={(e) => { e.stopPropagation(); onDelete(item.id) }}
          className="absolute top-1 right-1 z-10 rounded-full bg-danger-100 p-1 text-danger-600 shadow-sm transition-colors hover:bg-danger-200 hover:text-danger-800 focus:outline-none focus:ring-2 focus:ring-danger-400 focus:ring-offset-1"
          aria-label="Delete meal"
          title="Delete meal"
        >
          <X className="w-4 h-4" />
        </button>
      )}
      <div className="flex gap-2 p-2">
        {/* drag handle */}
        <div
          {...dragHandleProps}
          className="flex-shrink-0 self-center cursor-grab active:cursor-grabbing text-surface-400 hover:text-surface-600"
          aria-label="Drag to move meal"
        >
          <GripVertical className="w-4 h-4" />
        </div>

        {item.recipe?.image_url ? (
          <img
            src={item.recipe.image_url}
            alt={item.recipe.name}
            className="w-10 h-10 md:w-14 md:h-14 object-cover rounded-lg flex-shrink-0"
          />
        ) : (
          <div className="w-10 h-10 md:w-14 md:h-14 rounded-lg bg-surface-100 flex items-center justify-center flex-shrink-0">
            <CookingPot className="w-5 h-5 md:w-6 md:h-6 text-surface-400" />
          </div>
        )}
        <div className="flex-1 min-w-0 pr-7">
          <Link to={`/meals/${item.id}`} className="block">
            <h4 className="font-semibold text-sm text-surface-900 leading-tight line-clamp-2 group-hover:text-primary-700 transition-colors">
              {item.recipe?.name || 'Unknown Recipe'}
            </h4>
          </Link>
          <p className="text-[11px] text-surface-500 mt-0.5">
            {totalTime > 0 && `${totalTime} min · `}
            {item.recipe?.servings} servings
          </p>
          <div className="flex items-center gap-1.5 mt-1">
            <Badge
              variant={statusVariant}
              className="text-[10px] px-1.5 py-0.5"
              aria-label={`Approval status: ${item.approval_status}`}
            >
              {item.approval_status}
            </Badge>
            {item.estimated_cost && (
              <span className="text-[11px] font-medium text-surface-600">
                ${item.estimated_cost.toFixed(2)}
              </span>
            )}
          </div>
        </div>
      </div>
    </div>
  )
}

  /* ------------------------------------------------------------------ */
  /*  MealSlot — droppable area for one day + meal_type                  */
  /* ------------------------------------------------------------------ */
  function MealSlot({
    dayIndex,
    mealType,
    item,
    onApprove,
    onDeny,
    onDelete,
    onGenerate,
  }: {
    dayIndex: number
    mealType: string
    item?: MealPlanItem
    onApprove?: (itemId: string) => void
    onDeny?: (itemId: string) => void
    onDelete?: (itemId: string) => void
    onGenerate?: (dayIndex: number, mealType: string) => void
  }) {
    const droppableId = `slot-${dayIndex}-${mealType}`

    return (
      <Droppable droppableId={droppableId}>
        {(provided: DroppableProvided, snapshot: DroppableStateSnapshot) => (
          <div
            ref={provided.innerRef}
            {...provided.droppableProps}
            className={`
              rounded-lg p-1 min-h-[20px] md:min-h-[80px] transition-colors
              ${snapshot.isDraggingOver ? 'bg-primary-50 ring-2 ring-primary-300' : 'bg-transparent'}
            `}
          >
            {item ? (
              <Draggable draggableId={`item-${item.id}`} index={0}>
                {(dragProvided: DraggableProvided, dragSnapshot: DraggableStateSnapshot) => (
                  <div
                    ref={dragProvided.innerRef}
                    {...dragProvided.draggableProps}
                    style={dragProvided.draggableProps.style}
                  >
                    <MealCard
                      item={item}
                      dragHandleProps={dragProvided.dragHandleProps}
                      isDragging={dragSnapshot.isDragging}
                      onApprove={onApprove}
                      onDeny={onDeny}
                      onDelete={onDelete}
                    />
                  </div>
                )}
              </Draggable>
            ) : (
              <div className="flex h-16 rounded-xl border-2 border-dashed border-surface-200 flex-col items-center justify-center gap-1">
                <span className="text-xs text-surface-300">Empty</span>
                {onGenerate && (
                  <button
                    onClick={() => onGenerate(dayIndex, mealType)}
                    className="text-[10px] px-2 py-0.5 rounded bg-primary-50 text-primary-700 hover:bg-primary-100 font-medium transition-colors min-h-11"
                  >
                    Generate
                  </button>
                )}
              </div>
            )}
            {provided.placeholder}
          </div>
        )}
      </Droppable>
    )
  }

  /* ------------------------------------------------------------------ */
  /*  DayColumn                                                           */
  /* ------------------------------------------------------------------ */
  function DayColumn({
    dayIndex,
    items,
    onApprove,
    onDeny,
    onDelete,
    onGenerate,
  }: {
    dayIndex: number
    items: MealPlanItem[]
    onApprove?: (itemId: string) => void
    onDeny?: (itemId: string) => void
    onDelete?: (itemId: string) => void
    onGenerate?: (dayIndex: number, mealType: string) => void
  }) {
    const today = new Date().getDay()
    const isToday = today === (dayIndex + 1) % 7

    return (
      <div className="flex flex-col gap-1">
        <div className={`px-2 py-1.5 rounded-lg ${isToday ? 'bg-primary-50 border border-primary-200' : 'bg-surface-100'}`}>
          <div className="flex items-center justify-between">
            <span className={`text-xs font-semibold ${isToday ? 'text-primary-700' : 'text-surface-700'}`}>
              {FULL_DAY_NAMES[dayIndex]}
            </span>
            {isToday && <Badge variant="primary" className="text-[10px]">Today</Badge>}
          </div>
          <span className="text-[10px] text-surface-500">{DAY_NAMES[dayIndex]}</span>
        </div>
        <div className="space-y-1">
          {MEAL_TYPES.map(mealType => {
            const item = items.find(i => i.meal_type === mealType)
            return (
              <div key={mealType}>
                <span className="text-[9px] font-medium text-surface-400 uppercase tracking-wider px-1 block">
                  {mealType}
                </span>
                <MealSlot
                  dayIndex={dayIndex}
                  mealType={mealType}
                  item={item}
                  onApprove={onApprove}
                  onDeny={onDeny}
                  onDelete={onDelete}
                  onGenerate={onGenerate}
                />
              </div>
            )
          })}
        </div>
      </div>
    )
  }

  function DashboardSkeleton() {
    return (
      <div className="space-y-6 animate-fade-in">
        <div className="flex justify-between items-center">
          <Skeleton className="h-8 w-48" />
          <div className="flex gap-2">
            <Skeleton className="h-7 w-24" />
            <Skeleton className="h-7 w-20" />
          </div>
        </div>
        <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 lg:grid-cols-7 gap-2">
          {Array.from({ length: 7 }).map((_, i) => (
            <div key={i} className="space-y-2">
              <Skeleton className="h-8 w-full" />
              <div className="hidden sm:block"><SkeletonCard /></div>
              <div className="hidden sm:block"><SkeletonCard /></div>
              <div className="hidden sm:block"><SkeletonCard /></div>
            </div>
          ))}
        </div>
        <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
          <SkeletonCard />
          <SkeletonCard />
        </div>
      </div>
    )
  }

/* ------------------------------------------------------------------ */
/*  VoteEmailButton                                                      */
/* ------------------------------------------------------------------ */
function VoteEmailButton() {
  const [sendingVoteEmail, setSendingVoteEmail] = useState(false)

  async function handleSend() {
    setSendingVoteEmail(true)
    try {
      const res = await mealPlannerApi.admin.triggerOrchestrate('email')
      const status = res.data?.status || res.data?.message || 'sent'
      toast.success(status)
    } catch (err) {
      showApiError(err, 'Failed to send vote emails')
    } finally {
      setSendingVoteEmail(false)
    }
  }

  return (
    <button
      onClick={handleSend}
      disabled={sendingVoteEmail}
      className="inline-flex items-center gap-1 text-sm font-medium text-primary-600 hover:text-primary-700 transition-colors text-left disabled:opacity-50 disabled:cursor-not-allowed"
    >
      {sendingVoteEmail ? <Loader2 className="w-4 h-4 animate-spin" /> : <ChevronRight className="w-4 h-4" />}
      {sendingVoteEmail ? 'Sending...' : 'Send Vote Email'}
    </button>
  )
}

/* ------------------------------------------------------------------ */
/*  Dashboard                                                           */
/* ------------------------------------------------------------------ */
export default function Dashboard() {
  const queryClient = useQueryClient()
  const [searchParams, setSearchParams] = useSearchParams()
  const weekParam = searchParams.get('week')
  const parsedWeek = weekParam ? parseIsoDate(weekParam) : null
  const weekStart = weekParam && parsedWeek
    ? weekParam
    : isoMonday()
  const isCurrentWeek = weekStart === isoMonday()
  const navigateWeek = (next: string) => {
    setSearchParams(next === isoMonday() ? {} : { week: next }, { replace: true })
  }
  const { data: mealPlan, isLoading } = useQuery<MealPlan | null>({
    queryKey: ['mealPlan', weekStart],
    queryFn: () => mealPlannerApi.meals.getPlanned(weekStart).then(r => r.data),
  })

  async function handleDrop(itemId: string, newDay: number, newType: string) {
    try {
      await mealPlannerApi.meals.moveItem(itemId, newDay, newType)
      toast.success('Meal moved')
      queryClient.invalidateQueries({ queryKey: ['mealPlan', weekStart] })
    } catch {
      // Error toast fires from the global MutationCache handler.
    }
  }

  function onDragEnd(result: DropResult) {
    if (!result.destination) return
    const { draggableId, destination } = result
    const itemId = draggableId.replace('item-', '')
    const [, dayStr, typeStr] = destination.droppableId.split('-')
    handleDrop(itemId, parseInt(dayStr, 10) + 1, typeStr)
  }

  async function handleApprove(itemId: string) {
    try {
      await mealPlannerApi.meals.approveItem(itemId)
      toast.success('Meal approved')
      queryClient.invalidateQueries({ queryKey: ['mealPlan', weekStart] })
    } catch {
      // Error toast fires from the global MutationCache handler.
    }
  }

  async function handleDeny(itemId: string) {
    try {
      await mealPlannerApi.meals.denyItem(itemId)
      toast.success('Meal denied')
      queryClient.invalidateQueries({ queryKey: ['mealPlan', weekStart] })
    } catch {
      // Error toast fires from the global MutationCache handler.
    }
  }

  async function handleDelete(itemId: string) {
    if (!mealPlan) return
    const item = mealPlan.items.find(i => i.id === itemId)
    if (!item) return
    try {
      await mealPlannerApi.meals.deleteItem(itemId)
      queryClient.invalidateQueries({ queryKey: ['mealPlan', weekStart] })
      showToast.undo(
        'Meal deleted',
        async () => {
          try {
            await mealPlannerApi.meals.generateItem(
              mealPlan.id,
              item.day_of_week,
              item.meal_type
            )
            queryClient.invalidateQueries({ queryKey: ['mealPlan', weekStart] })
            toast.success('Slot filled with a new meal')
          } catch (err) {
            showApiError(err, 'Failed to refill slot')
          }
        }
      )
    } catch {
      // Error toast fires from the global MutationCache handler.
    }
  }

  async function handleGenerate(dayIndex: number, mealType: string) {
    if (!mealPlan) return
    try {
      await mealPlannerApi.meals.generateItem(mealPlan.id, dayIndex + 1, mealType)
      toast.success('Meal generated')
      queryClient.invalidateQueries({ queryKey: ['mealPlan', weekStart] })
    } catch {
      // Error toast fires from the global MutationCache handler.
    }
  }

  if (isLoading) return <DashboardSkeleton />

  if (!mealPlan) {
    return (
      <div className="space-y-6">
        <div className="flex items-center gap-3">
          <CalendarDays className="w-6 h-6 text-primary-600" />
          <h1 className="text-2xl font-bold text-surface-900">This Week's Meal Plan</h1>
        </div>
        <EmptyState
          icon={Sparkles}
          title="No meal plan yet"
          description="Generate your first weekly meal plan to get started with smart shopping lists and vote emails."
          action={{ label: 'Generate Meal Plan', onClick: () => {} }}
        />
      </div>
    )
  }

  const itemsByDay = Array.from({ length: 7 }, (_, i) =>
    mealPlan.items.filter(item => item.day_of_week === i + 1)
  )

  const statusVariant =
    mealPlan.status === 'approved' ? 'success' :
    mealPlan.status === 'locked' ? 'primary' :
    mealPlan.status === 'pending_approval' ? 'warning' :
    'neutral'

  return (
    <div className="space-y-6">
      {/* Header */}
      <div className="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-4">
        <div className="flex items-center gap-3">
          <div className="w-10 h-10 rounded-xl bg-primary-50 flex items-center justify-center">
            <CalendarDays className="w-5 h-5 text-primary-600" />
          </div>
          <div>
            <h1 className="text-2xl font-bold text-surface-900">
              Week of {formatIsoDate(mealPlan.week_start_date)}
            </h1>
            <p className="text-sm text-surface-500">
              {mealPlan.items.length} meals planned · {mealPlan.items.filter(i => i.approval_status === 'approved').length} approved
            </p>
          </div>
        </div>
        <div className="flex items-center gap-2 flex-wrap">
          <div className="inline-flex items-center rounded-lg border border-surface-200 bg-white">
            <button
              onClick={() => navigateWeek(shiftIsoDate(weekStart, -7))}
              aria-label="Previous week"
              className="p-2 text-surface-600 hover:bg-surface-100 rounded-l-lg focus:outline-none focus:ring-2 focus:ring-primary-400"
            >
              <ChevronLeft className="w-4 h-4" />
            </button>
            <button
              onClick={() => navigateWeek(isoMonday())}
              aria-label="Jump to current week"
              title="Jump to current week"
              className={`px-3 py-2 text-sm font-medium border-x border-surface-200 focus:outline-none focus:ring-2 focus:ring-primary-400 ${isCurrentWeek ? 'text-primary-700 bg-primary-50' : 'text-surface-600 hover:bg-surface-100'}`}
            >
              {isCurrentWeek ? 'This week' : 'Current'}
            </button>
            <button
              onClick={() => navigateWeek(shiftIsoDate(weekStart, 7))}
              aria-label="Next week"
              className="p-2 text-surface-600 hover:bg-surface-100 rounded-r-lg focus:outline-none focus:ring-2 focus:ring-primary-400"
            >
              <ChevronRight className="w-4 h-4" />
            </button>
          </div>
          <Badge
            variant={statusVariant}
            aria-label={`Plan status: ${mealPlan.status.replace(/_/g, ' ')}`}
          >
            {mealPlan.status.replace(/_/g, ' ')}
          </Badge>
          {mealPlan.total_estimated_cost !== undefined && (
            <div className="flex items-center gap-1.5 px-3 py-1.5 bg-surface-100 rounded-lg">
              <span className="text-sm font-semibold text-surface-900">
                ${mealPlan.total_estimated_cost.toFixed(2)}
              </span>
              <span className="text-xs text-surface-500">total</span>
            </div>
          )}
        </div>
      </div>

      {/* Weekly Grid — all 7 days visible */}
      <Card>
        <CardHeader>
          <h2 className="text-lg font-semibold text-surface-900">Weekly Overview</h2>
        </CardHeader>
        <CardBody>
          <DragDropContext onDragEnd={onDragEnd}>
            <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 lg:grid-cols-7 gap-2">
              {itemsByDay.map((items, index) => (
              <DayColumn
                key={index}
                dayIndex={index}
                items={items}
                onApprove={handleApprove}
                onDeny={handleDeny}
                onDelete={handleDelete}
                onGenerate={handleGenerate}
              />
              ))}
            </div>
          </DragDropContext>
        </CardBody>
      </Card>

      {/* Quick Actions */}
      <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
        <Card className="hover:shadow-md transition-shadow">
          <CardBody>
            <div className="flex items-start gap-4">
              <div className="w-10 h-10 rounded-xl bg-success-50 flex items-center justify-center flex-shrink-0">
                <ShoppingCart className="w-5 h-5 text-success-600" />
              </div>
              <div className="flex-1">
                <h3 className="text-lg font-semibold text-surface-900">Shopping List</h3>
                <p className="text-sm text-surface-500 mt-1">
                  View your aisle-organized shopping list with sale tracking.
                </p>
                <Link
                  to="/shopping-list"
                  className="inline-flex items-center gap-1 mt-3 text-sm font-medium text-primary-600 hover:text-primary-700 transition-colors"
                >
                  View shopping list <ChevronRight className="w-4 h-4" />
                </Link>
              </div>
            </div>
          </CardBody>
        </Card>

        <Card className="hover:shadow-md transition-shadow">
          <CardBody>
            <div className="flex items-start gap-4">
              <div className="w-10 h-10 rounded-xl bg-warning-50 flex items-center justify-center flex-shrink-0">
                <Sparkles className="w-5 h-5 text-warning-600" />
              </div>
              <div className="flex-1">
                <h3 className="text-lg font-semibold text-surface-900">Quick Actions</h3>
                <div className="flex flex-col gap-2 mt-2">
                  <Link
                    to="/pantry"
                    className="inline-flex items-center gap-1 text-sm font-medium text-primary-600 hover:text-primary-700 transition-colors"
                  >
                    Manage Pantry <ChevronRight className="w-4 h-4" />
                  </Link>
                  <VoteEmailButton />
                </div>
              </div>
            </div>
          </CardBody>
        </Card>
      </div>
    </div>
  )
}
