import {
  User,
  Task,
  TaskInstance,
  Medication,
  MedicationInstance,
  Appointment,
  Presence,
  CarouselMessage,
  AlertItem,
} from './types';
import {
  INITIAL_USERS,
  INITIAL_TASKS,
  INITIAL_MEDICATIONS,
  INITIAL_APPOINTMENTS,
  INITIAL_PRESENCES,
  INITIAL_CAROUSEL_MESSAGES,
  getTodayDateString,
} from './mockData';

const STORAGE_KEYS = {
  USERS: 'kiosk_soins_users',
  TASKS: 'kiosk_soins_tasks',
  TASK_INSTANCES: 'kiosk_soins_task_instances',
  MEDICATIONS: 'kiosk_soins_medications',
  MED_INSTANCES: 'kiosk_soins_med_instances',
  APPOINTMENTS: 'kiosk_soins_appointments',
  PRESENCES: 'kiosk_soins_presences',
  CAROUSEL: 'kiosk_soins_carousel',
  THEME: 'kiosk_soins_theme',
};

export function loadStoredData<T>(key: string, defaultValue: T): T {
  try {
    const raw = localStorage.getItem(key);
    if (!raw) return defaultValue;
    return JSON.parse(raw) as T;
  } catch (e) {
    console.error(`Error loading key ${key}:`, e);
    return defaultValue;
  }
}

export function saveStoredData<T>(key: string, value: T): void {
  try {
    localStorage.setItem(key, JSON.stringify(value));
  } catch (e) {
    console.error(`Error saving key ${key}:`, e);
  }
}

// Generate today's instances from recurring definitions
export function generateDailyInstances(
  tasks: Task[],
  medications: Medication[],
  existingTaskInstances: TaskInstance[],
  existingMedInstances: MedicationInstance[]
): { taskInstances: TaskInstance[]; medInstances: MedicationInstance[] } {
  const today = getTodayDateString(0);
  const now = new Date();
  const dayOfWeek = (now.getDay() === 0 ? 7 : now.getDay()); // 1=Lundi, 7=Dimanche

  // Check which task instances already exist for today
  const currentDayTaskIds = new Set(
    existingTaskInstances.filter((ti) => ti.date === today).map((ti) => ti.tache_id)
  );

  const newTaskInstances = [...existingTaskInstances];
  let nextTaskId = existingTaskInstances.length > 0 ? Math.max(...existingTaskInstances.map((t) => t.id)) + 1 : 1;

  for (const task of tasks) {
    if (!currentDayTaskIds.has(task.id)) {
      // Check if task applies today
      const isForToday =
        task.frequence === 'quotidien' ||
        task.jours_semaine.includes(dayOfWeek);

      if (isForToday) {
        newTaskInstances.push({
          id: nextTaskId++,
          tache_id: task.id,
          nom: task.nom,
          categorie: task.categorie,
          afficher_alerte: task.afficher_alerte,
          date: today,
          fait: false,
          fait_par: null,
          fait_a: null,
        });
      }
    }
  }

  // Medications instances for today
  const currentDayMedIds = new Set(
    existingMedInstances.filter((mi) => mi.date === today).map((mi) => mi.medicament_id)
  );

  const newMedInstances = [...existingMedInstances];
  let nextMedId = existingMedInstances.length > 0 ? Math.max(...existingMedInstances.map((m) => m.id)) + 1 : 1;

  for (const med of medications) {
    if (!currentDayMedIds.has(med.id)) {
      newMedInstances.push({
        id: nextMedId++,
        medicament_id: med.id,
        patient: med.patient,
        nom: med.nom,
        dosage: med.dosage,
        moment: med.moment,
        heure_prevue: med.heure_prevue,
        date: today,
        fait: false,
        fait_par: null,
        fait_a: null,
      });
    }
  }

  return {
    taskInstances: newTaskInstances,
    medInstances: newMedInstances,
  };
}

// Find who is on duty today
export function getTodaysDuty(presences: Presence[]): {
  dutyName: string;
  dutyUser: User | null;
  hoursRange: string;
  hasDuty: boolean;
  rawPresences: Presence[];
} {
  const today = getTodayDateString(0);
  const todaysList = presences
    .filter((p) => p.date === today)
    .sort((a, b) => a.heure_debut.localeCompare(b.heure_debut));

  if (todaysList.length === 0) {
    return {
      dutyName: 'Non assigné (Trou de planning)',
      dutyUser: null,
      hoursRange: 'Aucun membre assigné',
      hasDuty: false,
      rawPresences: [],
    };
  }

  // Group by person or merge consecutive slots
  const first = todaysList[0];
  const last = todaysList[todaysList.length - 1];
  const names = Array.from(new Set(todaysList.map((p) => p.utilisateur_nom))).join(', ');
  const range = `De ${first.heure_debut.replace(':', 'h')} à ${last.heure_fin.replace(':', 'h')}`;

  return {
    dutyName: names,
    dutyUser: {
      id: first.utilisateur_id,
      nom: first.utilisateur_nom,
      role: 'membre',
      actif: true,
    },
    hoursRange: range,
    hasDuty: true,
    rawPresences: todaysList,
  };
}

// Check coverage gaps for J+1 and J+2
export function checkPlanningGaps(presences: Presence[]): Array<{
  date: string;
  label: string;
  dayName: string;
}> {
  const gaps: Array<{ date: string; label: string; dayName: string }> = [];

  const checkDates = [
    { offset: 1, label: 'Demain (J+1)' },
    { offset: 2, label: 'Après-demain (J+2)' },
  ];

  for (const item of checkDates) {
    const dStr = getTodayDateString(item.offset);
    const hasPerson = presences.some((p) => p.date === dStr);
    if (!hasPerson) {
      const dObj = new Date(dStr + 'T12:00:00');
      const dayName = dObj.toLocaleDateString('fr-FR', {
        weekday: 'long',
        day: 'numeric',
        month: 'long',
      });
      gaps.push({
        date: dStr,
        label: item.label,
        dayName: dayName.charAt(0).toUpperCase() + dayName.slice(1),
      });
    }
  }

  return gaps;
}

// Build stacked priority alerts
export function buildSortedAlerts(
  taskInstances: TaskInstance[],
  medInstances: MedicationInstance[],
  appointments: Appointment[],
  ignoredIds: Set<string>
): AlertItem[] {
  const today = getTodayDateString(0);
  const alerts: AlertItem[] = [];

  // 1. Medications due today not yet done
  for (const med of medInstances) {
    const idKey = `med-${med.id}`;
    if (med.date === today && !med.fait && !ignoredIds.has(idKey)) {
      alerts.push({
        id: idKey,
        type: 'medicament',
        titre: `Médicament ${med.patient} — ${med.heure_prevue.replace(':', 'h')}`,
        heure: med.heure_prevue,
        details: `${med.nom} (${med.dosage})`,
        sourceId: med.id,
        patient: med.patient,
      });
    }
  }

  // 2. Tasks due today with afficher_alerte = true and not yet done
  for (const task of taskInstances) {
    const idKey = `task-${task.id}`;
    if (task.date === today && !task.fait && task.afficher_alerte && !ignoredIds.has(idKey)) {
      alerts.push({
        id: idKey,
        type: 'tache',
        titre: task.nom,
        heure: '12:00', // default placement or based on category
        details: `Catégorie : ${task.categorie}`,
        sourceId: task.id,
      });
    }
  }

  // 3. Appointments: today and tomorrow
  const tomorrow = getTodayDateString(1);
  for (const rdv of appointments) {
    const rdvDate = rdv.date_debut.split(' ')[0];
    const rdvTime = rdv.date_debut.split(' ')[1] || '09:00';

    if (rdvDate === today) {
      alerts.push({
        id: `rdv-${rdv.id}`,
        type: 'rdv',
        titre: `${rdv.titre} — ${rdv.moment ? rdv.moment : rdvTime.replace(':', 'h')}`,
        heure: rdvTime,
        details: `${rdv.lieu}${rdv.notes ? ' • ' + rdv.notes : ''}`,
        sourceId: rdv.id,
        patient: rdv.patient,
      });
    } else if (rdvDate === tomorrow) {
      alerts.push({
        id: `rdv-${rdv.id}`,
        type: 'rdv',
        titre: `${rdv.titre} — demain ${rdvTime.replace(':', 'h')}`,
        heure: '23:59', // tomorrow events pushed to end of green list
        details: `${rdv.lieu}${rdv.notes ? ' • ' + rdv.notes : ''}`,
        sourceId: rdv.id,
        patient: rdv.patient,
      });
    }
  }

  // Sort rule:
  // Red (medicaments) > Orange (taches) > Green (rdv)
  // Within each category: chronological order by heure
  const typeWeight: Record<string, number> = {
    medicament: 1,
    tache: 2,
    rdv: 3,
  };

  alerts.sort((a, b) => {
    const weightDiff = typeWeight[a.type] - typeWeight[b.type];
    if (weightDiff !== 0) return weightDiff;
    return a.heure.localeCompare(b.heure);
  });

  return alerts;
}

export { STORAGE_KEYS };
