'use client'

import { useEffect, useMemo, useState } from 'react'
import { loadBoardTimeline, type BoardTimelinePayload } from '@/app/intake/board/actions'
import {
  TIMELINE_WEEKS,
  TIMELINE_DAYS,
  addDays,
  aggregateDayStatus,
  buildDayCells,
  findFreeConsultantIdsForRange,
  formatISODate,
  parseISODate,
  rangesOverlap,
  startOfWeekUTC,
  STATUS_LABEL_DE,
  type AvailabilityStatus,
  type TimelineIntake,
} from '@/lib/intake/availability'
import AvailabilityEditModal from './availability-edit-modal'
import {
  FALLBACK_HEX,
  cssVarRefForPhase,
  phaseConfigKeyForIntakePriority,
  type IntakePriorityKey,
} from '@/lib/intake/phase-config'

type Props = { initialAnchor?: string }

type State =
  | { phase: 'loading' }
  | { phase: 'error'; error: string }
  | { phase: 'ready'; payload: BoardTimelinePayload }

const STATUS_BG: Record<AvailabilityStatus, string> = {
  free: 'bg-success/40',
  partial: 'bg-warning/50',
  full: 'bg-destructive/50',
  vacation: 'bg-muted-foreground/40',
  blocked: 'bg-foreground/50',
}

function priorityBarStyle(priority: IntakePriorityKey, opacity = 1): React.CSSProperties {
  const key = phaseConfigKeyForIntakePriority(priority)
  const fallback = FALLBACK_HEX[key] ?? 'var(--primary)'
  return { backgroundColor: cssVarRefForPhase(key, fallback), opacity }
}

const WEEKDAY_LABELS = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So']
const MONTH_LABELS = [
  'Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez',
]

export default function IntakeTimeline({ initialAnchor }: Props) {
  const [anchor, setAnchor] = useState<Date>(() => {
    const base = initialAnchor ? parseISODate(initialAnchor) : new Date()
    return startOfWeekUTC(base)
  })
  const [state, setState] = useState<State>({ phase: 'loading' })
  const [hoveredIntakeId, setHoveredIntakeId] = useState<string | null>(null)
  const [editDate, setEditDate] = useState<string | null>(null)
  const [refreshCounter, setRefreshCounter] = useState(0)

  const rangeStart = formatISODate(anchor)
  const rangeEnd = formatISODate(addDays(anchor, TIMELINE_DAYS - 1))

  useEffect(() => {
    let cancelled = false
    setState({ phase: 'loading' })
    ;(async () => {
      const result = await loadBoardTimeline(rangeStart, rangeEnd)
      if (cancelled) return
      if (!result.ok || !result.data) {
        setState({ phase: 'error', error: result.ok ? 'no_data' : result.error })
        return
      }
      setState({ phase: 'ready', payload: result.data })
    })()
    return () => {
      cancelled = true
    }
  }, [rangeStart, rangeEnd, refreshCounter])

  const dayCells = useMemo(() => buildDayCells(anchor, TIMELINE_DAYS), [anchor])

  if (state.phase === 'loading') {
    return <div className="p-6 text-sm text-muted-foreground">Lade Timeline…</div>
  }
  if (state.phase === 'error') {
    return (
      <div className="p-6 text-sm text-destructive">
        Fehler: {state.error}
      </div>
    )
  }

  const { consultants, availabilities, intakes, selfConsultantId } = state.payload

  const hoveredIntake = hoveredIntakeId
    ? intakes.find((i) => i.id === hoveredIntakeId) ?? null
    : null

  let highlightedConsultantIds = new Set<string>()
  if (hoveredIntake) {
    const ranges: Array<[string, string]> = []
    if (hoveredIntake.preferred_first_visit_start && hoveredIntake.preferred_first_visit_end) {
      ranges.push([
        hoveredIntake.preferred_first_visit_start,
        hoveredIntake.preferred_first_visit_end,
      ])
    }
    if (hoveredIntake.preferred_second_visit_start && hoveredIntake.preferred_second_visit_end) {
      ranges.push([
        hoveredIntake.preferred_second_visit_start,
        hoveredIntake.preferred_second_visit_end,
      ])
    }
    if (ranges.length > 0) {
      const ids = consultants.map((c) => c.id)
      const free = new Set<string>(ids)
      for (const [s, e] of ranges) {
        const freeForRange = new Set(
          findFreeConsultantIdsForRange(Array.from(free), availabilities, s, e),
        )
        for (const id of free) {
          if (!freeForRange.has(id)) free.delete(id)
        }
      }
      highlightedConsultantIds = free
    }
  }

  const existingForSelfInRange = selfConsultantId
    ? availabilities.filter((a) => a.consultant_id === selfConsultantId)
    : []

  function shiftWeeks(weeks: number) {
    setAnchor((prev) => addDays(prev, weeks * 7))
  }

  function onCellClick(consultantId: string, date: string) {
    if (consultantId !== selfConsultantId) return
    setEditDate(date)
  }

  function onSaved() {
    setEditDate(null)
    setRefreshCounter((c) => c + 1)
  }

  return (
    <div className="space-y-4">
      <header className="flex items-center justify-between flex-wrap gap-3">
        <div className="flex items-center gap-2">
          <button
            type="button"
            onClick={() => shiftWeeks(-2)}
            className="px-2 py-1 text-xs font-condensed bg-card border border-border rounded-sm hover:bg-muted"
            aria-label="2 Wochen zurück"
          >
            ‹‹
          </button>
          <button
            type="button"
            onClick={() => shiftWeeks(-1)}
            className="px-2 py-1 text-xs font-condensed bg-card border border-border rounded-sm hover:bg-muted"
            aria-label="1 Woche zurück"
          >
            ‹
          </button>
          <button
            type="button"
            onClick={() => setAnchor(startOfWeekUTC(new Date()))}
            className="px-3 py-1 text-xs font-condensed bg-card border border-border rounded-sm hover:bg-muted"
          >
            Heute
          </button>
          <button
            type="button"
            onClick={() => shiftWeeks(1)}
            className="px-2 py-1 text-xs font-condensed bg-card border border-border rounded-sm hover:bg-muted"
            aria-label="1 Woche vor"
          >
            ›
          </button>
          <button
            type="button"
            onClick={() => shiftWeeks(2)}
            className="px-2 py-1 text-xs font-condensed bg-card border border-border rounded-sm hover:bg-muted"
            aria-label="2 Wochen vor"
          >
            ››
          </button>
        </div>
        <div className="text-xs font-condensed text-muted-foreground">
          {TIMELINE_WEEKS} Wochen · {rangeStart} → {rangeEnd}
        </div>
        <Legend />
      </header>

      <div className="overflow-x-auto bg-card border border-border rounded-md">
        <table className="min-w-full text-xs border-collapse">
          <thead>
            <tr className="bg-muted/40">
              <th
                scope="col"
                className="sticky left-0 z-10 bg-muted/40 px-3 py-2 text-left font-condensed font-bold text-foreground border-b border-r border-border min-w-[180px]"
              >
                Berater · Aufträge
              </th>
              {dayCells.map((cell, idx) => {
                const showWeek = idx % 7 === 0
                const d = parseISODate(cell.date)
                const weekLabel = showWeek
                  ? `KW ${weekNumberISO(d)} · ${MONTH_LABELS[d.getUTCMonth()]} ${String(d.getUTCDate()).padStart(2, '0')}`
                  : ''
                return (
                  <th
                    key={cell.date}
                    scope="col"
                    className={`px-0 py-1 text-center font-condensed text-[10px] text-muted-foreground border-b border-border w-7 ${cell.weekday >= 5 ? 'bg-muted/20' : ''}`}
                    title={cell.date}
                  >
                    {showWeek ? (
                      <div className="leading-tight">
                        <div className="text-foreground font-bold whitespace-nowrap">{weekLabel}</div>
                        <div>{WEEKDAY_LABELS[cell.weekday]}</div>
                      </div>
                    ) : (
                      <div className="leading-tight">{WEEKDAY_LABELS[cell.weekday]}</div>
                    )}
                  </th>
                )
              })}
            </tr>
          </thead>
          <tbody>
            {intakes.length === 0 ? (
              <tr>
                <td colSpan={TIMELINE_DAYS + 1} className="px-3 py-3 text-muted-foreground italic text-center">
                  Keine offenen Aufträge mit Wunschzeitraum in diesem Range.
                </td>
              </tr>
            ) : (
              intakes.map((intake) => (
                <IntakeRow
                  key={intake.id}
                  intake={intake}
                  dayCells={dayCells}
                  rangeStart={rangeStart}
                  rangeEnd={rangeEnd}
                  isHovered={hoveredIntakeId === intake.id}
                  onHover={setHoveredIntakeId}
                />
              ))
            )}

            <tr className="bg-muted/20">
              <td
                colSpan={TIMELINE_DAYS + 1}
                className="sticky left-0 px-3 py-1 text-[10px] font-condensed text-muted-foreground uppercase tracking-wide border-y border-border"
              >
                Berater
              </td>
            </tr>

            {consultants.map((c) => (
              <ConsultantRow
                key={c.id}
                consultant={c}
                availabilities={availabilities}
                dayCells={dayCells}
                isHighlighted={hoveredIntake ? highlightedConsultantIds.has(c.id) : false}
                hasHover={!!hoveredIntake}
                onCellClick={onCellClick}
                isEditable={c.id === selfConsultantId}
              />
            ))}
          </tbody>
        </table>
      </div>

      {selfConsultantId ? (
        <p className="text-[11px] text-muted-foreground">
          Tipp: Klick in deine eigene Zeile öffnet den Verfügbarkeits-Editor für diesen Tag.
        </p>
      ) : (
        <p className="text-[11px] text-warning">
          Hinweis: Dein Account hat keinen Consultant-Record. Eigene Verfügbarkeit kann nicht gepflegt werden.
        </p>
      )}

      {editDate && selfConsultantId && (
        <AvailabilityEditModal
          initialDate={editDate}
          existing={existingForSelfInRange}
          onCancel={() => setEditDate(null)}
          onSaved={onSaved}
        />
      )}
    </div>
  )
}

type IntakeRowProps = {
  intake: TimelineIntake
  dayCells: ReturnType<typeof buildDayCells>
  rangeStart: string
  rangeEnd: string
  isHovered: boolean
  onHover: (id: string | null) => void
}

function IntakeRow({ intake, dayCells, rangeStart, rangeEnd, isHovered, onHover }: IntakeRowProps) {
  const bars: Array<{ start: string; end: string; label: string }> = []
  if (intake.preferred_first_visit_start && intake.preferred_first_visit_end) {
    bars.push({
      start: intake.preferred_first_visit_start,
      end: intake.preferred_first_visit_end,
      label: 'Erstbesuch',
    })
  }
  if (intake.preferred_second_visit_start && intake.preferred_second_visit_end) {
    bars.push({
      start: intake.preferred_second_visit_start,
      end: intake.preferred_second_visit_end,
      label: 'Zweitbesuch',
    })
  }

  return (
    <tr
      className={`group ${isHovered ? 'bg-primary/5' : ''}`}
      onMouseEnter={() => onHover(intake.id)}
      onMouseLeave={() => onHover(null)}
    >
      <th
        scope="row"
        className="sticky left-0 z-10 bg-card group-hover:bg-primary/5 px-3 py-1.5 text-left border-b border-r border-border min-w-[180px]"
      >
        <div className="flex flex-col">
          <span className="font-condensed font-bold text-[11px] text-foreground">
            {intake.intake_id}
          </span>
          <span className="text-[11px] text-muted-foreground truncate max-w-[160px]">
            {intake.supplier_name ?? '—'}
          </span>
        </div>
      </th>
      {dayCells.map((cell) => {
        const inFirstBar =
          intake.preferred_first_visit_start &&
          intake.preferred_first_visit_end &&
          cell.date >= intake.preferred_first_visit_start &&
          cell.date <= intake.preferred_first_visit_end
        const inSecondBar =
          intake.preferred_second_visit_start &&
          intake.preferred_second_visit_end &&
          cell.date >= intake.preferred_second_visit_start &&
          cell.date <= intake.preferred_second_visit_end

        const inRange = rangesOverlap(cell.date, cell.date, rangeStart, rangeEnd)
        if (!inRange) return <td key={cell.date} className="border-b border-border h-8" />

        return (
          <td
            key={cell.date}
            className={`border-b border-border h-8 relative ${cell.weekday >= 5 ? 'bg-muted/10' : ''}`}
          >
            {inFirstBar && (
              <div
                title={`Erstbesuch ${intake.preferred_first_visit_start} → ${intake.preferred_first_visit_end}`}
                className="absolute inset-x-0 top-1 h-2.5"
                style={priorityBarStyle(intake.priority)}
              />
            )}
            {inSecondBar && (
              <div
                title={`Zweitbesuch ${intake.preferred_second_visit_start} → ${intake.preferred_second_visit_end}`}
                className="absolute inset-x-0 bottom-1 h-2.5"
                style={priorityBarStyle(intake.priority, 0.6)}
              />
            )}
          </td>
        )
      })}
    </tr>
  )
}

type ConsultantRowProps = {
  consultant: { id: string; display_name: string; team_code: string; is_self: boolean }
  availabilities: import('@/lib/intake/availability').ConsultantAvailability[]
  dayCells: ReturnType<typeof buildDayCells>
  isHighlighted: boolean
  hasHover: boolean
  onCellClick: (consultantId: string, date: string) => void
  isEditable: boolean
}

function ConsultantRow({
  consultant,
  availabilities,
  dayCells,
  isHighlighted,
  hasHover,
  onCellClick,
  isEditable,
}: ConsultantRowProps) {
  const dimmed = hasHover && !isHighlighted
  return (
    <tr className={`${consultant.is_self ? 'bg-primary/5' : ''} ${dimmed ? 'opacity-40' : ''}`}>
      <th
        scope="row"
        className={`sticky left-0 z-10 px-3 py-1.5 text-left border-b border-r border-border min-w-[180px] ${consultant.is_self ? 'bg-primary/5' : 'bg-card'} ${isHighlighted ? 'ring-2 ring-primary ring-inset' : ''}`}
      >
        <div className="flex flex-col">
          <span className="font-condensed font-bold text-[11px] text-foreground">
            {consultant.is_self ? `Du · ${consultant.display_name}` : consultant.display_name}
          </span>
          {consultant.team_code && (
            <span className="text-[10px] text-muted-foreground">{consultant.team_code}</span>
          )}
        </div>
      </th>
      {dayCells.map((cell) => {
        const status = aggregateDayStatus(availabilities, consultant.id, cell.date)
        const bg = status ? STATUS_BG[status] : ''
        const title = status
          ? `${cell.date} · ${STATUS_LABEL_DE[status]}`
          : `${cell.date} · Frei (kein Eintrag)`
        return (
          <td
            key={cell.date}
            className={`border-b border-border h-7 ${bg} ${cell.weekday >= 5 && !status ? 'bg-muted/10' : ''} ${isEditable ? 'cursor-pointer hover:ring-2 hover:ring-primary hover:ring-inset' : ''}`}
            title={title}
            onClick={() => isEditable && onCellClick(consultant.id, cell.date)}
            aria-label={title}
          />
        )
      })}
    </tr>
  )
}

function Legend() {
  return (
    <div className="flex items-center gap-3 flex-wrap text-[10px] font-condensed text-muted-foreground">
      <LegendItem className="bg-success/40" label="Frei" />
      <LegendItem className="bg-warning/50" label="Teilbelegt" />
      <LegendItem className="bg-destructive/50" label="Voll" />
      <LegendItem className="bg-muted-foreground/40" label="Urlaub" />
      <LegendItem className="bg-foreground/50" label="Gesperrt" />
    </div>
  )
}

function LegendItem({ className, label }: { className: string; label: string }) {
  return (
    <span className="flex items-center gap-1">
      <span className={`w-3 h-3 inline-block ${className} border border-border`} />
      {label}
    </span>
  )
}

function weekNumberISO(d: Date): number {
  const target = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()))
  const dayNr = (target.getUTCDay() + 6) % 7
  target.setUTCDate(target.getUTCDate() - dayNr + 3)
  const firstThursday = new Date(Date.UTC(target.getUTCFullYear(), 0, 4))
  const diff = target.getTime() - firstThursday.getTime()
  return 1 + Math.round(diff / (7 * 24 * 3600 * 1000))
}
