import { useState, useEffect, useCallback, useMemo } from 'react'
import Header                 from './components/Header'
import FailedBanner           from './components/FailedBanner'
import Calendar               from './components/Calendar'
import RightPanel             from './components/RightPanel'
import SettingsModal          from './components/SettingsModal'
import TestWindowDetailsPanel from './components/TestWindowDetailsPanel'
import { api, groupScheduleItems } from './api'

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
function getMondayOfWeek(date) {
  const d = new Date(date)
  const day = d.getDay()
  d.setDate(d.getDate() + (day === 0 ? -6 : 1 - day))
  d.setHours(0, 0, 0, 0)
  return d
}

function parseLocalDate(value) {
  if (!value) return null

  const [year, month, day] = value.split('-').map(Number)
  if (!year || !month || !day) return null

  const parsed = new Date(year, month - 1, day)
  parsed.setHours(0, 0, 0, 0)
  return Number.isNaN(parsed.getTime()) ? null : parsed
}

function toKey(d) { return d.toISOString().slice(0, 10) }

function addDays(date, n) {
  const d = new Date(date)
  d.setDate(d.getDate() + n)
  return d
}

function parseHolidayDates(raw = '') {
  return new Set(
    String(raw)
      .split(',')
      .map((token) => token.trim())
      .filter(Boolean),
  )
}

function isOffDay(date, holidaySet) {
  const weekday = date.getDay()
  if (weekday === 0 || weekday === 6) return true
  return holidaySet.has(toKey(date))
}

function getWeekendStartDatesForWeek(weekStart, holidaySet) {
  const dates = []
  for (let offset = 0; offset < 7; offset += 1) {
    const current = addDays(weekStart, offset)
    const nextDay = addDays(current, 1)
    if (!isOffDay(current, holidaySet) && isOffDay(nextDay, holidaySet)) {
      dates.push(toKey(current))
    }
  }
  return dates
}

function getTonightWindowKeys() {
  const now = new Date()
  const hour = now.getHours()
  const today = new Date(now)
  today.setHours(0, 0, 0, 0)

  if (hour < 1) {
    return {
      shift3Date: toKey(addDays(today, -1)),
      shift1Date: toKey(today),
    }
  }

  return {
    shift3Date: toKey(today),
    shift1Date: toKey(addDays(today, 1)),
  }
}

function toTonightConfigRows(scheduleData) {
  const { shift3Date, shift1Date } = getTonightWindowKeys()
  const tonightTests = [
    ...((scheduleData[shift3Date]?.shift3) ?? []),
    ...((scheduleData[shift1Date]?.shift1) ?? []),
  ]

  const bySta = new Map()

  for (const test of tonightTests) {
    const config = test.config ?? {}
    for (const entry of Object.values(config)) {
      const staRaw = entry?.sta
      const testPoint = entry?.test_point
      if (!staRaw || !testPoint) continue

      for (const staPart of String(staRaw).split(',')) {
        const sta = staPart.trim().toUpperCase()
        if (!sta) continue

        if (!bySta.has(sta)) {
          bySta.set(sta, { sta, points: new Set() })
        }
        bySta.get(sta).points.add(testPoint)
      }
    }
  }

  return Array.from(bySta.values())
    .map((row) => ({
      sta: row.sta,
      testPoints: Array.from(row.points).sort(),
    }))
    .sort((a, b) => a.sta.localeCompare(b.sta))
}

const SHIFT_KEYS = ['shift1', 'shift2', 'shift3']
const SHIFT_INDEX_BY_KEY = {
  shift1: 1,
  shift2: 2,
  shift3: 3,
}

function createEmptyScheduleDay() {
  return { shift1: [], shift2: [], shift3: [] }
}

function getShiftTests(scheduleData, dateKey, shiftKey) {
  return scheduleData[dateKey]?.[shiftKey] ?? []
}

function isOnOrAfterScheduleStart(dateKey, shiftKey, scheduleStartShift) {
  if (!scheduleStartShift?.date || !scheduleStartShift?.shiftIndex) return false

  if (dateKey > scheduleStartShift.date) return true
  if (dateKey < scheduleStartShift.date) return false

  const currentShiftIndex = SHIFT_INDEX_BY_KEY[shiftKey] ?? 99
  return currentShiftIndex >= scheduleStartShift.shiftIndex
}

function collectSnapshotShiftKeys(currentScheduleData = {}, previousScheduleData = {}, scheduleStartShift = null) {
  const snapshotShiftKeys = new Set()
  const dateKeys = new Set([
    ...Object.keys(currentScheduleData),
    ...Object.keys(previousScheduleData),
  ])

  for (const dateKey of dateKeys) {
    for (const shiftKey of SHIFT_KEYS) {
      if (isOnOrAfterScheduleStart(dateKey, shiftKey, scheduleStartShift)) {
        continue
      }

      const currentTests = getShiftTests(currentScheduleData, dateKey, shiftKey)
      const previousTests = getShiftTests(previousScheduleData, dateKey, shiftKey)

      // Show historical snapshot only when this shift disappeared in the latest schedule.
      if (currentTests.length === 0 && previousTests.length > 0) {
        snapshotShiftKeys.add(`${dateKey}::${shiftKey}`)
      }
    }
  }

  return snapshotShiftKeys
}

function markHistoricalSnapshot(tests = []) {
  return tests.map((test) => ({
    ...test,
    isPreviousVersionSnapshot: true,
  }))
}

function buildCalendarScheduleData(currentScheduleData = {}, previousScheduleData = {}, snapshotShiftKeys = new Set()) {
  const calendarScheduleData = {}
  const dateKeys = new Set([
    ...Object.keys(currentScheduleData),
    ...Object.keys(previousScheduleData),
  ])

  for (const dateKey of dateKeys) {
    const mergedDay = createEmptyScheduleDay()

    for (const shiftKey of SHIFT_KEYS) {
      const shiftSnapshotKey = `${dateKey}::${shiftKey}`
      mergedDay[shiftKey] = snapshotShiftKeys.has(shiftSnapshotKey)
        ? markHistoricalSnapshot(getShiftTests(previousScheduleData, dateKey, shiftKey))
        : getShiftTests(currentScheduleData, dateKey, shiftKey)
    }

    calendarScheduleData[dateKey] = mergedDay
  }

  return calendarScheduleData
}

const DEFAULT_SETTINGS = {
  targetDir:         '',
  p2pCoeCsvPath:      '',
  p3pCsvPath:         '',
  refResultDir:       '',
  dutResultDir:       '',
  smbUsername:        '',
  smbPassword:        '',
  smbDomain:          '',
  dutP2pRuntimeMinutes: '',
  dutCoeRuntimeMinutes: '',
  dutP3pRuntimeMinutes: '',
  refP2pRuntimeMinutes: '',
  refCoeRuntimeMinutes: '',
  refP3pRuntimeMinutes: '',
  testExclusion:      '',
  holidays:           '',
}

function sanitizeSettings(saved = {}) {
  const {
    p2pRuntimeMinutes,
    coeRuntimeMinutes,
    p3pRuntimeMinutes,
    ...rest
  } = saved

  delete rest.startDateOverride

  return {
    ...DEFAULT_SETTINGS,
    dutP2pRuntimeMinutes: rest.dutP2pRuntimeMinutes ?? p2pRuntimeMinutes ?? '',
    dutCoeRuntimeMinutes: rest.dutCoeRuntimeMinutes ?? coeRuntimeMinutes ?? '',
    dutP3pRuntimeMinutes: rest.dutP3pRuntimeMinutes ?? p3pRuntimeMinutes ?? '',
    refP2pRuntimeMinutes: rest.refP2pRuntimeMinutes ?? p2pRuntimeMinutes ?? '',
    refCoeRuntimeMinutes: rest.refCoeRuntimeMinutes ?? coeRuntimeMinutes ?? '',
    refP3pRuntimeMinutes: rest.refP3pRuntimeMinutes ?? p3pRuntimeMinutes ?? '',
    ...rest,
  }
}

// ---------------------------------------------------------------------------

export default function App() {
  const [isAuthenticated, setIsAuthenticated] = useState(false)
  const [isAuthBootstrapping, setIsAuthBootstrapping] = useState(true)
  const [userRole, setUserRole] = useState(null)
  const [authUsername, setAuthUsername] = useState('')
  const [username, setUsername] = useState('')
  const [password, setPassword] = useState('')
  const [loginError, setLoginError] = useState(null)
  const [isLoggingIn, setIsLoggingIn] = useState(false)

  const [settingsOpen,   setSettingsOpen]   = useState(false)
  const [settings,       setSettings]       = useState(DEFAULT_SETTINGS)
  const [daytimeTestingToday, setDaytimeTestingToday] = useState(false)
  const [daytimeTestingHours, setDaytimeTestingHours] = useState('8')
  const [daytimeTestingDevice, setDaytimeTestingDevice] = useState('CGW453')
  const [dualDeviceWeekendWeekSelections, setDualDeviceWeekendWeekSelections] = useState({})
  const [topPriorityDut, setTopPriorityDut] = useState('')
  const [topPriorityRef, setTopPriorityRef] = useState('')
  const [lowestPriority, setLowestPriority] = useState('')
  const [startDateOverride, setStartDateOverride] = useState('')
  const [failedTests,       setFailedTests]       = useState([])
  const [scheduleData,      setScheduleData]      = useState({})
  const [previousScheduleData, setPreviousScheduleData] = useState({})
  const [scheduleStartShift, setScheduleStartShift] = useState(null)
  const [scheduleWindows,   setScheduleWindows]   = useState([])
  const [selectedWindowId,  setSelectedWindowId]  = useState(null)
  const [completionDate,    setCompletionDate]    = useState(null)
  const [weekStart,         setWeekStart]         = useState(() => getMondayOfWeek(new Date()))
  const [loading,           setLoading]           = useState(false)
  const [error,             setError]             = useState(null)

  const isAdmin = userRole === 'admin'
  const isViewer = userRole === 'viewer'

  const tonightConfigRows = useMemo(() => toTonightConfigRows(scheduleData), [scheduleData])
  const snapshotShiftKeys = useMemo(
    () => collectSnapshotShiftKeys(scheduleData, previousScheduleData, scheduleStartShift),
    [scheduleData, previousScheduleData, scheduleStartShift],
  )
  const calendarScheduleData = useMemo(
    () => buildCalendarScheduleData(scheduleData, previousScheduleData, snapshotShiftKeys),
    [scheduleData, previousScheduleData, snapshotShiftKeys],
  )
  const windowLookup = useMemo(() => {
    const lookup = new Map()

    for (const windowDetails of scheduleWindows) {
      for (const segment of windowDetails.segments ?? []) {
        lookup.set(`${segment.date}::shift${segment.shift_index}`, windowDetails)
      }
    }

    return lookup
  }, [scheduleWindows])
  const selectedWindow = useMemo(
    () => scheduleWindows.find((windowDetails) => windowDetails.window_id === selectedWindowId) ?? null,
    [scheduleWindows, selectedWindowId],
  )
  const holidaySet = useMemo(() => parseHolidayDates(settings.holidays), [settings.holidays])
  const activeWeekKey = useMemo(() => toKey(weekStart), [weekStart])
  const dualDeviceWeekendWeekEnabled = Boolean(dualDeviceWeekendWeekSelections[activeWeekKey])
  const dualDeviceWindowStartDates = useMemo(() => {
    if (!dualDeviceWeekendWeekEnabled) return []
    return getWeekendStartDatesForWeek(weekStart, holidaySet)
  }, [dualDeviceWeekendWeekEnabled, weekStart, holidaySet])
  const daytimeDateKey = useMemo(
    () => (daytimeTestingToday ? toKey(new Date()) : null),
    [daytimeTestingToday],
  )

  const clearAuthSession = useCallback(() => {
    sessionStorage.removeItem('auth_token')
    sessionStorage.removeItem('auth_role')
    sessionStorage.removeItem('auth_username')
    setIsAuthenticated(false)
    setUserRole(null)
    setAuthUsername('')
    setSettingsOpen(false)
    setFailedTests([])
  }, [])

  const handleApiError = useCallback((requestError) => {
    if (requestError?.status === 401) {
      clearAuthSession()
      setError('Your session has expired. Please sign in again.')
      return true
    }
    return false
  }, [clearAuthSession])

  const fetchSchedule = useCallback(async (start) => {
    try {
      const data = await api.getScheduleWeek(toKey(start))
      let previousVersionScheduleData = {}

      if ((data.schedule_version ?? 0) > 1) {
        try {
          const previousData = await api.getScheduleWeek(toKey(start), data.schedule_version - 1)
          previousVersionScheduleData = groupScheduleItems(previousData.items)
        } catch (previousError) {
          console.warn('Failed to fetch previous schedule version:', previousError)
        }
      }

      setScheduleData(groupScheduleItems(data.items))
      setPreviousScheduleData(previousVersionScheduleData)
      if (data.schedule_start_date && data.schedule_start_shift_index) {
        setScheduleStartShift({
          date: data.schedule_start_date,
          shiftIndex: data.schedule_start_shift_index,
        })
      } else {
        setScheduleStartShift(null)
      }
      setScheduleWindows(data.windows ?? [])
      setCompletionDate(data.completion_date ?? null)
    } catch (e) {
      if (handleApiError(e)) return
      console.error('Failed to fetch schedule:', e)
    }
  }, [handleApiError])

  const fetchRerunTests = useCallback(async () => {
    try {
      const data = await api.getRerunTests()
      setFailedTests(data.tests ?? [])
    } catch (e) {
      if (handleApiError(e)) return
      console.error('Failed to fetch rerun tests:', e)
    }
  }, [handleApiError])

  useEffect(() => {
    async function restoreSession() {
      const token = sessionStorage.getItem('auth_token')
      const role = sessionStorage.getItem('auth_role')
      const storedUsername = sessionStorage.getItem('auth_username') ?? ''
      if (!token || !role) {
        setIsAuthBootstrapping(false)
        return
      }

      try {
        const user = await api.me()
        const resolvedRole = user.role ?? role
        const resolvedUsername = user.username ?? storedUsername
        sessionStorage.setItem('auth_role', resolvedRole)
        sessionStorage.setItem('auth_username', resolvedUsername)
        setUserRole(resolvedRole)
        setAuthUsername(resolvedUsername)
        setIsAuthenticated(true)
      } catch (_restoreError) {
        clearAuthSession()
      } finally {
        setIsAuthBootstrapping(false)
      }
    }

    restoreSession()
  }, [clearAuthSession])

  useEffect(() => {
    if (!isAuthenticated) return

    async function init() {
      try {
        const holidayData = await api.getHolidays()
        if (isAdmin) {
          const saved = await api.getSettings()
          setSettings(() => ({
            ...sanitizeSettings(saved),
            holidays: (holidayData.dates ?? []).join(', '),
          }))
        } else {
          setSettings(() => ({
            ...DEFAULT_SETTINGS,
            holidays: (holidayData.dates ?? []).join(', '),
          }))
        }
      } catch (e) {
        if (handleApiError(e)) return
        console.warn('Backend not reachable on load:', e.message)
      }
      await fetchSchedule(getMondayOfWeek(new Date()))
      await fetchRerunTests()
    }

    init()
  }, [isAuthenticated, isAdmin, fetchSchedule, fetchRerunTests, handleApiError])

  useEffect(() => {
    if (!isAuthenticated) return
    fetchSchedule(weekStart)
  }, [isAuthenticated, weekStart, fetchSchedule])

  useEffect(() => {
    if (!isAuthenticated) return

    const timer = setInterval(() => {
      fetchSchedule(weekStart)
      fetchRerunTests()
    }, 5000)

    return () => clearInterval(timer)
  }, [isAuthenticated, weekStart, fetchSchedule, fetchRerunTests])

  async function handleLogin(event) {
    event.preventDefault()
    setIsLoggingIn(true)
    setLoginError(null)
    try {
      const response = await api.login(username.trim(), password)
      sessionStorage.setItem('auth_token', response.access_token)
      sessionStorage.setItem('auth_role', response.role)
      sessionStorage.setItem('auth_username', response.username)
      setUserRole(response.role)
      setAuthUsername(response.username)
      setIsAuthenticated(true)
      setUsername('')
      setPassword('')
      setError(null)
    } catch (e) {
      setLoginError(e.message)
    } finally {
      setIsLoggingIn(false)
    }
  }

  function handleLogout() {
    clearAuthSession()
  }

  async function handleSaveSettings(newSettings) {
    setLoading(true)
    setError(null)
    try {
      const sanitizedSettings = sanitizeSettings(newSettings)

      await api.saveSettings(sanitizedSettings)

      const holidayDates = (sanitizedSettings.holidays ?? '')
        .split(',').map(s => s.trim()).filter(Boolean)
      await api.saveHolidays(holidayDates)

      const csvPaths = [
        sanitizedSettings.p2pCoeCsvPath?.trim(),
        sanitizedSettings.p3pCsvPath?.trim(),
      ].filter(Boolean)

      if (csvPaths.length > 0) {
        await api.loadCsv(csvPaths, sanitizedSettings.targetDir?.trim() ?? '')
      }

      setSettings(sanitizedSettings)
    } catch (e) {
      if (handleApiError(e)) return
      setError(e.message)
    } finally {
      setLoading(false)
    }
  }

  async function handleRestartAndClearData() {
    setLoading(true)
    setError(null)
    try {
      await api.restartAndClearData()

      setSettings(DEFAULT_SETTINGS)
      setTopPriorityDut('')
      setTopPriorityRef('')
      setLowestPriority('')
      setStartDateOverride('')
      setDaytimeTestingToday(false)
      setDaytimeTestingHours('8')
      setDaytimeTestingDevice('CGW453')
      setFailedTests([])
      setScheduleData({})
      setPreviousScheduleData({})
      setScheduleStartShift(null)
      setScheduleWindows([])
      setSelectedWindowId(null)
      setCompletionDate(null)

      await fetchSchedule(weekStart)
      await fetchRerunTests()
    } catch (e) {
      if (handleApiError(e)) return
      setError(e.message)
      throw e
    } finally {
      setLoading(false)
    }
  }

  async function handleRemakeSchedule() {
    setLoading(true)
    setError(null)
    try {
      const parsedDaytimeHours = Number.parseInt(String(daytimeTestingHours).trim(), 10)
      const safeDaytimeHours = Number.isFinite(parsedDaytimeHours)
        ? Math.max(0, Math.min(8, parsedDaytimeHours))
        : 8
      const effectiveStartDate = startDateOverride.trim()
      const result = await api.compileSchedule({
        start_date: effectiveStartDate || null,
        daytime_testing_today: daytimeTestingToday,
        daytime_testing_hours: safeDaytimeHours,
        daytime_testing_device: daytimeTestingDevice,
        dual_device_weekend_start_dates: dualDeviceWindowStartDates,
        top_priority_tests_dut: topPriorityDut.split(',').map(s => s.trim()).filter(Boolean),
        top_priority_tests_ref: topPriorityRef.split(',').map(s => s.trim()).filter(Boolean),
        lowest_priority_tests: lowestPriority.split(',').map(s => s.trim()).filter(Boolean),
        rule: settings.testExclusion ?? '',
      })
      setCompletionDate(result.completion_date ?? null)

      if (effectiveStartDate) {
        const overrideDate = parseLocalDate(effectiveStartDate)
        if (overrideDate) {
          const overrideWeekStart = getMondayOfWeek(overrideDate)
          setWeekStart(overrideWeekStart)
          await fetchSchedule(overrideWeekStart)
        } else {
          await fetchSchedule(weekStart)
        }
      } else {
        await fetchSchedule(weekStart)
      }

      setStartDateOverride('')
    } catch (e) {
      if (handleApiError(e)) return
      setError(e.message)
    } finally {
      setLoading(false)
    }
  }

  function handleRerunDecision(rerunDuringDay) {
    const appendUnique = (currentValue, incomingValues) => {
      const existing = currentValue.split(',').map(s => s.trim()).filter(Boolean)
      const merged = [...new Set([...existing, ...incomingValues])]
      return merged.join(', ')
    }

    const dutIncoming = failedTests
      .filter(test => test.device === 'CGW453')
      .map(test => test.test_id)
    const refIncoming = failedTests
      .filter(test => test.device === 'CGW452')
      .map(test => test.test_id)

    if (dutIncoming.length > 0) {
      setTopPriorityDut(prev => appendUnique(prev, dutIncoming))
    }
    if (refIncoming.length > 0) {
      setTopPriorityRef(prev => appendUnique(prev, refIncoming))
    }

    if (rerunDuringDay) {
      setDaytimeTestingToday(true)
      if (dutIncoming.length > 0 && refIncoming.length === 0) {
        setDaytimeTestingDevice('CGW453')
      } else if (refIncoming.length > 0 && dutIncoming.length === 0) {
        setDaytimeTestingDevice('CGW452')
      }
    }

    setFailedTests([])
  }

  useEffect(() => {
    if (selectedWindowId && !selectedWindow) {
      setSelectedWindowId(null)
    }
  }, [selectedWindow, selectedWindowId])

  function handleWindowSelect(windowDetails) {
    setSelectedWindowId(windowDetails?.window_id ?? null)
  }

  function handleCloseWindowDetails() {
    setSelectedWindowId(null)
  }

  if (isAuthBootstrapping) {
    return (
      <div className="min-h-screen bg-slate-950 text-slate-100 flex items-center justify-center px-4">
        <p className="text-sm text-slate-400">Restoring session...</p>
      </div>
    )
  }

  if (!isAuthenticated) {
    return (
      <div className="min-h-screen bg-slate-950 text-slate-100 flex items-center justify-center px-4">
        <form
          onSubmit={handleLogin}
          className="w-full max-w-md bg-slate-900 border border-slate-800 rounded-xl p-6 space-y-4"
        >
          <div>
            <h1 className="text-xl font-semibold tracking-tight">Sign in</h1>
          </div>

          {loginError && (
            <div className="bg-red-950/50 border border-red-700 rounded-lg px-3 py-2 text-red-300 text-sm">
              {loginError}
            </div>
          )}

          <label className="block text-sm text-slate-300">
            Username
            <input
              value={username}
              onChange={(event) => setUsername(event.target.value)}
              className="mt-1 w-full rounded-lg border border-slate-700 bg-slate-950 px-3 py-2 text-slate-100 focus:outline-none focus:ring-2 focus:ring-cyan-600"
              autoComplete="username"
              required
            />
          </label>

          <label className="block text-sm text-slate-300">
            Password
            <input
              type="password"
              value={password}
              onChange={(event) => setPassword(event.target.value)}
              className="mt-1 w-full rounded-lg border border-slate-700 bg-slate-950 px-3 py-2 text-slate-100 focus:outline-none focus:ring-2 focus:ring-cyan-600"
              autoComplete="current-password"
              required
            />
          </label>

          <button
            type="submit"
            disabled={isLoggingIn}
            className="w-full rounded-lg bg-cyan-700 hover:bg-cyan-600 disabled:opacity-60 px-4 py-2 text-sm font-medium transition-colors"
          >
            {isLoggingIn ? 'Signing in...' : 'Sign in'}
          </button>
        </form>
      </div>
    )
  }

  return (
    <div className="flex flex-col min-h-screen bg-gray-950 text-gray-100">
      <Header
        onOpenSettings={() => {
          if (isAdmin) setSettingsOpen(true)
        }}
        showSettings={isAdmin}
        username={authUsername}
        onLogout={handleLogout}
      />

      {error && (
        <div className="px-6 py-2 bg-orange-900/60 border-b border-orange-700 text-orange-200 text-sm flex items-center justify-between">
          <span>{error}</span>
          <button className="ml-3 text-orange-400 hover:text-white" onClick={() => setError(null)}>✕</button>
        </div>
      )}

      <FailedBanner
        rerunTests={failedTests}
        onDecision={handleRerunDecision}
        onClose={() => setFailedTests([])}
      />

      <main className="relative flex flex-1 gap-4 p-4 overflow-hidden">
        <div className="flex-1 min-w-0 flex flex-col">
          <Calendar
            scheduleData={calendarScheduleData}
            daytimeDateKey={daytimeDateKey}
            weekStart={weekStart}
            onWeekChange={setWeekStart}
            isViewer={isViewer}
            dualDeviceWeekendWeekEnabled={dualDeviceWeekendWeekEnabled}
            onDualDeviceWeekendWeekEnabledChange={(enabled) => {
              setDualDeviceWeekendWeekSelections((prev) => ({
                ...prev,
                [activeWeekKey]: enabled,
              }))
            }}
            windowLookup={windowLookup}
            snapshotShiftKeys={snapshotShiftKeys}
            onWindowSelect={handleWindowSelect}
          />
        </div>

        <RightPanel
          completionDate={completionDate}
          daytimeTestingToday={daytimeTestingToday}
          onDaytimeTestingTodayChange={setDaytimeTestingToday}
          daytimeTestingHours={daytimeTestingHours}
          onDaytimeTestingHoursChange={setDaytimeTestingHours}
          daytimeTestingDevice={daytimeTestingDevice}
          onDaytimeTestingDeviceChange={setDaytimeTestingDevice}
          startDateOverride={startDateOverride}
          onStartDateOverrideChange={setStartDateOverride}
          topPriorityDut={topPriorityDut}
          onTopPriorityDutChange={setTopPriorityDut}
          topPriorityRef={topPriorityRef}
          onTopPriorityRefChange={setTopPriorityRef}
          lowestPriority={lowestPriority}
          onLowestPriorityChange={setLowestPriority}
          onRemakeSchedule={handleRemakeSchedule}
          loading={loading}
          tonightConfigRows={tonightConfigRows}
          isViewer={isViewer}
        />

        <TestWindowDetailsPanel
          isOpen={Boolean(selectedWindow)}
          windowDetails={selectedWindow}
          onClose={handleCloseWindowDetails}
          isViewer={isViewer}
        />
      </main>

      {isAdmin ? (
        <SettingsModal
          isOpen={settingsOpen}
          onClose={() => setSettingsOpen(false)}
          settings={settings}
          onSave={handleSaveSettings}
          onRestart={handleRestartAndClearData}
        />
      ) : null}
    </div>
  )
}
