/**
 * @license
 * SPDX-License-Identifier: Apache-2.0
 */

import React, { useState, useEffect, useRef, useCallback } from 'react';
import {
  User,
  Task,
  TaskInstance,
  Medication,
  MedicationInstance,
  Appointment,
  Presence,
  CarouselMessage,
  ActiveScreen,
  PendingUndoItem,
  AlertItem,
} from './types';
import {
  INITIAL_USERS,
  INITIAL_TASKS,
  INITIAL_MEDICATIONS,
  INITIAL_APPOINTMENTS,
  INITIAL_PRESENCES,
  INITIAL_CAROUSEL_MESSAGES,
} from './mockData';
import {
  loadStoredData,
  saveStoredData,
  STORAGE_KEYS,
  generateDailyInstances,
  getTodaysDuty,
  checkPlanningGaps,
  buildSortedAlerts,
} from './storage';
import { HeaderBar } from './components/HeaderBar';
import { DashboardView } from './components/DashboardView';
import { TasksView } from './components/TasksView';
import { MedsView } from './components/MedsView';
import { PresencesView } from './components/PresencesView';
import { AppointmentsView } from './components/AppointmentsView';
import { IdentificationModal } from './components/IdentificationModal';
import { SessionIndicator } from './components/SessionIndicator';
import { RotationView } from './components/RotationView';
import { AdminModal } from './components/AdminModal';
import { ExportOvhModal } from './components/ExportOvhModal';

export default function App() {
  // Theme: 'dark' (Kiosk OLED tablette murale) or 'light' (papier sobre Public Sans)
  const [theme, setTheme] = useState<'dark' | 'light'>(() =>
    loadStoredData<'dark' | 'light'>(STORAGE_KEYS.THEME, 'dark')
  );

  // Active Screen
  const [currentScreen, setCurrentScreen] = useState<ActiveScreen>('dashboard');

  // Core Data
  const [users, setUsers] = useState<User[]>(() =>
    loadStoredData(STORAGE_KEYS.USERS, INITIAL_USERS)
  );
  const [tasks, setTasks] = useState<Task[]>(() =>
    loadStoredData(STORAGE_KEYS.TASKS, INITIAL_TASKS)
  );
  const [medications, setMedications] = useState<Medication[]>(() =>
    loadStoredData(STORAGE_KEYS.MEDICATIONS, INITIAL_MEDICATIONS)
  );
  const [taskInstances, setTaskInstances] = useState<TaskInstance[]>(() =>
    loadStoredData(STORAGE_KEYS.TASK_INSTANCES, [])
  );
  const [medInstances, setMedInstances] = useState<MedicationInstance[]>(() =>
    loadStoredData(STORAGE_KEYS.MED_INSTANCES, [])
  );
  const [appointments, setAppointments] = useState<Appointment[]>(() =>
    loadStoredData(STORAGE_KEYS.APPOINTMENTS, INITIAL_APPOINTMENTS)
  );
  const [presences, setPresences] = useState<Presence[]>(() =>
    loadStoredData(STORAGE_KEYS.PRESENCES, INITIAL_PRESENCES)
  );
  const [carouselMessages, setCarouselMessages] = useState<CarouselMessage[]>(() =>
    loadStoredData(STORAGE_KEYS.CAROUSEL, INITIAL_CAROUSEL_MESSAGES)
  );

  // Active User Session (60-second window after identification)
  const [activeUser, setActiveUser] = useState<User | null>(null);
  const [sessionSeconds, setSessionSeconds] = useState<number>(60);
  const sessionTimerRef = useRef<NodeJS.Timeout | null>(null);

  // 5-second pending undo items (key: `task-${id}` or `med-${id}`)
  const [pendingUndos, setPendingUndos] = useState<Record<string, PendingUndoItem>>({});

  // Identification modal
  const [isIdModalOpen, setIsIdModalOpen] = useState<boolean>(false);
  const [pendingAction, setPendingAction] = useState<(() => void) | null>(null);
  const [pendingActionDesc, setPendingActionDesc] = useState<string>('');

  // Modals & Mode Veille
  const [isAdminOpen, setIsAdminOpen] = useState<boolean>(false);
  const [isExportOpen, setIsExportOpen] = useState<boolean>(false);
  const [isRotationActive, setIsRotationActive] = useState<boolean>(false);
  const [midnightAlertNotice, setMidnightAlertNotice] = useState<string | null>(null);

  // Inactivity timeout for ambient rotation (e.g. 75 seconds of no activity)
  const inactivityTimerRef = useRef<NodeJS.Timeout | null>(null);

  const resetInactivityTimer = useCallback(() => {
    if (inactivityTimerRef.current) clearTimeout(inactivityTimerRef.current);
    inactivityTimerRef.current = setTimeout(() => {
      // If idle, activate ambient rotation mode
      setIsRotationActive(true);
    }, 75000);
  }, []);

  // Initialize instances on load
  useEffect(() => {
    const { taskInstances: updatedTasks, medInstances: updatedMeds } = generateDailyInstances(
      tasks,
      medications,
      taskInstances,
      medInstances
    );
    setTaskInstances(updatedTasks);
    setMedInstances(updatedMeds);
    saveStoredData(STORAGE_KEYS.TASK_INSTANCES, updatedTasks);
    saveStoredData(STORAGE_KEYS.MED_INSTANCES, updatedMeds);
  }, []);

  // Save changes to storage
  useEffect(() => saveStoredData(STORAGE_KEYS.USERS, users), [users]);
  useEffect(() => saveStoredData(STORAGE_KEYS.TASKS, tasks), [tasks]);
  useEffect(() => saveStoredData(STORAGE_KEYS.MEDICATIONS, medications), [medications]);
  useEffect(() => saveStoredData(STORAGE_KEYS.TASK_INSTANCES, taskInstances), [taskInstances]);
  useEffect(() => saveStoredData(STORAGE_KEYS.MED_INSTANCES, medInstances), [medInstances]);
  useEffect(() => saveStoredData(STORAGE_KEYS.APPOINTMENTS, appointments), [appointments]);
  useEffect(() => saveStoredData(STORAGE_KEYS.PRESENCES, presences), [presences]);
  useEffect(() => saveStoredData(STORAGE_KEYS.CAROUSEL, carouselMessages), [carouselMessages]);
  useEffect(() => saveStoredData(STORAGE_KEYS.THEME, theme), [theme]);

  // Global activity listener for tablet kiosk
  useEffect(() => {
    const handleActivity = () => {
      resetInactivityTimer();
    };
    window.addEventListener('pointerdown', handleActivity);
    window.addEventListener('keydown', handleActivity);
    resetInactivityTimer();
    return () => {
      window.removeEventListener('pointerdown', handleActivity);
      window.removeEventListener('keydown', handleActivity);
      if (inactivityTimerRef.current) clearTimeout(inactivityTimerRef.current);
    };
  }, [resetInactivityTimer]);

  // Duty calculation
  const dutyInfo = getTodaysDuty(presences);
  const presumedDutyName = dutyInfo.dutyUser?.nom || 'Marie';

  // Planning gaps calculation
  const planningGaps = checkPlanningGaps(presences);

  // Decrement session timer every second
  useEffect(() => {
    if (activeUser) {
      if (sessionTimerRef.current) clearInterval(sessionTimerRef.current);
      sessionTimerRef.current = setInterval(() => {
        setSessionSeconds((prev) => {
          if (prev <= 1) {
            // Session expired
            setActiveUser(null);
            if (sessionTimerRef.current) clearInterval(sessionTimerRef.current);
            return 0;
          }
          return prev - 1;
        });
      }, 1000);
    } else {
      if (sessionTimerRef.current) clearInterval(sessionTimerRef.current);
    }
    return () => {
      if (sessionTimerRef.current) clearInterval(sessionTimerRef.current);
    };
  }, [activeUser]);

  // Session helpers
  const handleRenewSession = () => {
    setSessionSeconds(60);
  };

  const handleLogout = () => {
    setActiveUser(null);
    setSessionSeconds(0);
    if (sessionTimerRef.current) clearInterval(sessionTimerRef.current);
  };

  const executeWithSession = (action: () => void, description: string) => {
    if (activeUser) {
      // Renew 60s window on user action
      setSessionSeconds(60);
      action();
    } else {
      // Prompt identification
      setPendingAction(() => action);
      setPendingActionDesc(description);
      setIsIdModalOpen(true);
    }
  };

  const handleConfirmUser = (user: User) => {
    setActiveUser(user);
    setSessionSeconds(60);
    setIsIdModalOpen(false);
    if (pendingAction) {
      pendingAction();
      setPendingAction(null);
      setPendingActionDesc('');
    }
  };

  // 5-second undo management
  const handleMarkTaskDone = (task: TaskInstance) => {
    executeWithSession(() => {
      const key = `task-${task.id}`;
      const validatedBy = activeUser?.nom || presumedDutyName;

      setPendingUndos((prev) => ({
        ...prev,
        [key]: {
          id: key,
          type: 'tache',
          sourceId: task.id,
          title: task.nom,
          secondsRemaining: 5,
          validatedBy,
        },
      }));

      // Countdown interval
      const interval = setInterval(() => {
        setPendingUndos((current) => {
          const item = current[key];
          if (!item) {
            clearInterval(interval);
            return current;
          }
          if (item.secondsRemaining <= 1) {
            clearInterval(interval);
            // Definitively apply done in database
            const now = new Date().toLocaleTimeString('fr-FR', {
              hour: '2-digit',
              minute: '2-digit',
            });
            setTaskInstances((prevTasks) =>
              prevTasks.map((t) =>
                t.id === task.id
                  ? { ...t, fait: true, fait_par: validatedBy, fait_a: now }
                  : t
              )
            );
            const copy = { ...current };
            delete copy[key];
            return copy;
          }
          return {
            ...current,
            [key]: {
              ...item,
              secondsRemaining: item.secondsRemaining - 1,
            },
          };
        });
      }, 1000);
    }, task.nom);
  };

  const handleMarkMedDone = (med: MedicationInstance) => {
    executeWithSession(() => {
      const key = `med-${med.id}`;
      const validatedBy = activeUser?.nom || presumedDutyName;

      setPendingUndos((prev) => ({
        ...prev,
        [key]: {
          id: key,
          type: 'medicament',
          sourceId: med.id,
          title: med.nom,
          secondsRemaining: 5,
          validatedBy,
        },
      }));

      const interval = setInterval(() => {
        setPendingUndos((current) => {
          const item = current[key];
          if (!item) {
            clearInterval(interval);
            return current;
          }
          if (item.secondsRemaining <= 1) {
            clearInterval(interval);
            const now = new Date().toLocaleTimeString('fr-FR', {
              hour: '2-digit',
              minute: '2-digit',
            });
            setMedInstances((prevMeds) =>
              prevMeds.map((m) =>
                m.id === med.id
                  ? { ...m, fait: true, fait_par: validatedBy, fait_a: now }
                  : m
              )
            );
            const copy = { ...current };
            delete copy[key];
            return copy;
          }
          return {
            ...current,
            [key]: {
              ...item,
              secondsRemaining: item.secondsRemaining - 1,
            },
          };
        });
      }, 1000);
    }, `${med.nom} (${med.patient})`);
  };

  const handleCancelUndo = (key: string) => {
    setPendingUndos((prev) => {
      const copy = { ...prev };
      delete copy[key];
      return copy;
    });
  };

  // Build sorted alerts (excluding those currently in pending undo state)
  const ignoredKeys = new Set(Object.keys(pendingUndos));
  const alerts = buildSortedAlerts(taskInstances, medInstances, appointments, ignoredKeys);

  const handleSelectAlert = (alert: AlertItem) => {
    if (alert.type === 'medicament') {
      setCurrentScreen('medicaments');
    } else if (alert.type === 'tache') {
      setCurrentScreen('taches');
    } else {
      setCurrentScreen('rdv');
    }
  };

  // Presence helper
  const handleAddPresence = (newPresence: Omit<Presence, 'id'>) => {
    const nextId = presences.length > 0 ? Math.max(...presences.map((p) => p.id)) + 1 : 1;
    setPresences((prev) => [...prev, { id: nextId, ...newPresence }]);
  };

  const handleDeletePresence = (id: number) => {
    setPresences((prev) => prev.filter((p) => p.id !== id));
  };

  // Task & Med Admin helpers
  const handleAddTask = (newTask: Omit<Task, 'id'>) => {
    const nextId = tasks.length > 0 ? Math.max(...tasks.map((t) => t.id)) + 1 : 1;
    const taskObj: Task = { id: nextId, ...newTask };
    const updatedTasks = [...tasks, taskObj];
    setTasks(updatedTasks);

    // Auto-generate for today
    const { taskInstances: updatedInsts } = generateDailyInstances(
      updatedTasks,
      medications,
      taskInstances,
      medInstances
    );
    setTaskInstances(updatedInsts);
  };

  const handleDeleteTask = (id: number) => {
    setTasks((prev) => prev.filter((t) => t.id !== id));
    setTaskInstances((prev) => prev.filter((ti) => ti.tache_id !== id));
  };

  const handleAddMedication = (newMed: Omit<Medication, 'id'>) => {
    const nextId = medications.length > 0 ? Math.max(...medications.map((m) => m.id)) + 1 : 1;
    const medObj: Medication = { id: nextId, ...newMed };
    const updatedMeds = [...medications, medObj];
    setMedications(updatedMeds);

    const { medInstances: updatedInsts } = generateDailyInstances(
      tasks,
      updatedMeds,
      taskInstances,
      medInstances
    );
    setMedInstances(updatedInsts);
  };

  const handleDeleteMedication = (id: number) => {
    setMedications((prev) => prev.filter((m) => m.id !== id));
    setMedInstances((prev) => prev.filter((mi) => mi.medicament_id !== id));
  };

  const handleAddAppointment = (newRdv: Omit<Appointment, 'id'>) => {
    const nextId = appointments.length > 0 ? Math.max(...appointments.map((a) => a.id)) + 1 : 1;
    setAppointments((prev) => [...prev, { id: nextId, ...newRdv }]);
  };

  const handleDeleteAppointment = (id: number) => {
    setAppointments((prev) => prev.filter((a) => a.id !== id));
  };

  // Midnight Simulation
  const handleSimulateMidnight = () => {
    const { taskInstances: newTasks, medInstances: newMeds } = generateDailyInstances(
      tasks,
      medications,
      taskInstances,
      medInstances
    );
    setTaskInstances(newTasks);
    setMedInstances(newMeds);

    const gaps = checkPlanningGaps(presences);
    if (gaps.length > 0) {
      setMidnightAlertNotice(
        `Simulation réussie : Instances du jour générées. ⚠️ Trou de planning détecté sur ${gaps
          .map((g) => g.dayName)
          .join(', ')}. Email automatique simulé via mail() PHP envoyé à l’admin !`
      );
    } else {
      setMidnightAlertNotice(
        `Simulation réussie : Instances du jour générées. Planning J+1 et J+2 entièrement couvert.`
      );
    }
    setTimeout(() => setMidnightAlertNotice(null), 8000);
  };

  const handleResetData = () => {
    setUsers(INITIAL_USERS);
    setTasks(INITIAL_TASKS);
    setMedications(INITIAL_MEDICATIONS);
    setAppointments(INITIAL_APPOINTMENTS);
    setPresences(INITIAL_PRESENCES);
    setCarouselMessages(INITIAL_CAROUSEL_MESSAGES);
    const { taskInstances: resetTasks, medInstances: resetMeds } = generateDailyInstances(
      INITIAL_TASKS,
      INITIAL_MEDICATIONS,
      [],
      []
    );
    setTaskInstances(resetTasks);
    setMedInstances(resetMeds);
    setPendingUndos({});
    setActiveUser(null);
  };

  return (
    <div className={`min-h-screen transition-colors duration-300 theme-${theme}`}>
      <div className="max-w-[640px] mx-auto min-h-screen p-3.5 sm:p-5 flex flex-col justify-between">
        <div className="flex flex-col">
          {/* Header Bar */}
          <HeaderBar
            currentScreen={currentScreen}
            onNavigate={setCurrentScreen}
            activeUser={activeUser}
            onLogout={handleLogout}
            onOpenAdmin={() => setIsAdminOpen(true)}
            onOpenExport={() => setIsExportOpen(true)}
            onStartRotation={() => setIsRotationActive(true)}
            theme={theme}
            onToggleTheme={() => setTheme((t) => (t === 'dark' ? 'light' : 'dark'))}
            planningGapCount={planningGaps.length}
          />

          {/* Simulated Email / Cron Notification */}
          {midnightAlertNotice && (
            <div className="mb-3 p-3.5 rounded-xl bg-amber-950/80 border border-amber-600 text-amber-200 text-xs flex items-center justify-between animate-in fade-in duration-300">
              <span>{midnightAlertNotice}</span>
              <button
                onClick={() => setMidnightAlertNotice(null)}
                className="font-bold text-amber-400 ml-2"
              >
                ✕
              </button>
            </div>
          )}

          {/* Active Screen Rendering */}
          <main className="flex-1">
            {currentScreen === 'dashboard' && (
              <DashboardView
                dutyInfo={dutyInfo}
                alerts={alerts}
                appointments={appointments}
                taskInstances={taskInstances}
                carouselMessages={carouselMessages.map((m) => m.texte)}
                onNavigate={setCurrentScreen}
                onSelectAlert={handleSelectAlert}
              />
            )}

            {currentScreen === 'taches' && (
              <TasksView
                tasks={taskInstances}
                pendingUndos={pendingUndos}
                onBack={() => setCurrentScreen('dashboard')}
                onMarkDone={handleMarkTaskDone}
                onCancelUndo={handleCancelUndo}
              />
            )}

            {currentScreen === 'medicaments' && (
              <MedsView
                meds={medInstances}
                pendingUndos={pendingUndos}
                onBack={() => setCurrentScreen('dashboard')}
                onMarkDone={handleMarkMedDone}
                onCancelUndo={handleCancelUndo}
              />
            )}

            {currentScreen === 'presence' && (
              <PresencesView
                presences={presences}
                users={users}
                onBack={() => setCurrentScreen('dashboard')}
                onAddPresence={handleAddPresence}
                activeUser={activeUser}
              />
            )}

            {currentScreen === 'rdv' && (
              <AppointmentsView
                appointments={appointments}
                onBack={() => setCurrentScreen('dashboard')}
              />
            )}
          </main>
        </div>

        {/* Floating Active Session Pill */}
        <SessionIndicator
          user={activeUser}
          secondsRemaining={sessionSeconds}
          onRenew={handleRenewSession}
          onLogout={handleLogout}
        />

        {/* Identification Modal */}
        <IdentificationModal
          isOpen={isIdModalOpen}
          onClose={() => {
            setIsIdModalOpen(false);
            setPendingAction(null);
            setPendingActionDesc('');
          }}
          presumedName={presumedDutyName}
          familyMembers={users}
          onConfirmUser={handleConfirmUser}
          actionDescription={pendingActionDesc}
        />

        {/* Ambient Rotation / Veille Mode */}
        {isRotationActive && (
          <RotationView
            onDismiss={() => setIsRotationActive(false)}
            carouselMessages={carouselMessages.map((m) => m.texte)}
            dutyInfo={dutyInfo}
            appointments={appointments}
          />
        )}

        {/* Admin Configuration Modal */}
        <AdminModal
          isOpen={isAdminOpen}
          onClose={() => setIsAdminOpen(false)}
          users={users}
          tasks={tasks}
          medications={medications}
          appointments={appointments}
          presences={presences}
          onAddTask={handleAddTask}
          onDeleteTask={handleDeleteTask}
          onAddMedication={handleAddMedication}
          onDeleteMedication={handleDeleteMedication}
          onAddAppointment={handleAddAppointment}
          onDeleteAppointment={handleDeleteAppointment}
          onAddPresence={handleAddPresence}
          onDeletePresence={handleDeletePresence}
          onSimulateMidnight={handleSimulateMidnight}
          onResetData={handleResetData}
        />

        {/* OVH Starter Export Modal */}
        <ExportOvhModal
          isOpen={isExportOpen}
          onClose={() => setIsExportOpen(false)}
        />
      </div>
    </div>
  );
}
