import { AppError } from '../errors/app-error';
import {
  countAnomaliesParStatut,
  countEmpruntsParStatut,
  countMaterielsParStatut,
  countNotificationsNonLues,
  findActiviteRecente,
  findAnomaliesResponsable,
  findEmpruntsResponsable,
  findHistoriqueResponsable,
  findMaterielsResponsable,
  findNotificationsResponsable,
  marquerNotificationLue,
  marquerNotificationsResponsableLues,
  StatutCount,
  ActiviteResponsable,
  AnomalieResponsable,
  EmpruntResponsable,
  HistoriqueResponsable,
  MaterielResponsable,
  NotificationResponsable,
} from '../repositories/responsable.repository';
import {
  STATUT_ANOMALIE,
  STATUT_EMPRUNT,
  STATUT_MATERIEL,
  StatutAnomalie,
  StatutEmprunt,
  StatutMateriel,
} from '../models/enums';

export interface DashboardResponsableData {
  materiels: StatutCount[];
  emprunts: StatutCount[];
  anomalies: StatutCount[];
  notificationsNonLues: number;
  activiteRecente: ActiviteResponsable[];
}

export interface ListerEmpruntsResponsableFiltres {
  statut?: StatutEmprunt;
}

export interface ListerMaterielsResponsableFiltres {
  statut?: StatutMateriel;
  categorieId?: number;
  recherche?: string;
}

export interface ListerAnomaliesResponsableFiltres {
  statut?: StatutAnomalie;
  type?: string;
}

export interface ListerNotificationsResponsableFiltres {
  lu?: boolean;
}

export interface ListerHistoriqueResponsableFiltres {
  action?: string;
  utilisateurId?: number;
  materielId?: number;
  empruntId?: number;
  dateDebut?: Date;
  dateFin?: Date;
}

function verifierResponsable(roleCode: string): void {
  if (roleCode !== 'RESPONSABLE') {
    throw new AppError(403, 'Acces reserve au responsable materiel');
  }
}

export async function getDashboardResponsable(
  utilisateurId: number,
  roleCode: string,
  campusId: number,
): Promise<DashboardResponsableData> {
  verifierResponsable(roleCode);

  const [materiels, emprunts, anomalies, notificationsNonLues, activiteRecente] = await Promise.all(
    [
      countMaterielsParStatut(campusId),
      countEmpruntsParStatut(campusId),
      countAnomaliesParStatut(campusId),
      countNotificationsNonLues(utilisateurId),
      findActiviteRecente(campusId, 10),
    ],
  );

  return {
    materiels,
    emprunts,
    anomalies,
    notificationsNonLues,
    activiteRecente,
  };
}

export function parseStatutEmprunt(value: unknown): StatutEmprunt | undefined {
  if (value === undefined) {
    return undefined;
  }
  if (typeof value !== 'string' || !(STATUT_EMPRUNT as readonly string[]).includes(value)) {
    throw new AppError(400, 'statut invalide');
  }
  return value as StatutEmprunt;
}

export function parseStatutMateriel(value: unknown): StatutMateriel | undefined {
  if (value === undefined) {
    return undefined;
  }
  if (typeof value !== 'string' || !(STATUT_MATERIEL as readonly string[]).includes(value)) {
    throw new AppError(400, 'statut invalide');
  }
  return value as StatutMateriel;
}

export function parseStatutAnomalie(value: unknown): StatutAnomalie | undefined {
  if (value === undefined) {
    return undefined;
  }
  if (typeof value !== 'string' || !(STATUT_ANOMALIE as readonly string[]).includes(value)) {
    throw new AppError(400, 'statut invalide');
  }
  return value as StatutAnomalie;
}

export function parseCategorieId(value: unknown): number | undefined {
  if (value === undefined) {
    return undefined;
  }

  const parsed = Number(value);
  if (!Number.isInteger(parsed) || parsed <= 0) {
    throw new AppError(400, 'categorieId invalide');
  }

  return parsed;
}

export function parseNotificationId(value: unknown): number {
  if (typeof value !== 'string') {
    throw new AppError(400, 'notificationId invalide');
  }

  const parsed = Number(value);
  if (!Number.isInteger(parsed) || parsed <= 0) {
    throw new AppError(400, 'notificationId invalide');
  }

  return parsed;
}

export function parsePositiveIntQuery(value: unknown, champ: string): number | undefined {
  if (value === undefined) {
    return undefined;
  }
  if (typeof value !== 'string') {
    throw new AppError(400, `${champ} invalide`);
  }

  const parsed = Number(value);
  if (!Number.isInteger(parsed) || parsed <= 0) {
    throw new AppError(400, `${champ} invalide`);
  }

  return parsed;
}

export function parseDateQuery(value: unknown, champ: string): Date | undefined {
  if (value === undefined) {
    return undefined;
  }
  if (typeof value !== 'string') {
    throw new AppError(400, `${champ} invalide`);
  }

  const parsed = new Date(value);
  if (Number.isNaN(parsed.getTime())) {
    throw new AppError(400, `${champ} invalide`);
  }

  return parsed;
}

export function parseLu(value: unknown): boolean | undefined {
  if (value === undefined) {
    return undefined;
  }
  if (value === 'true') {
    return true;
  }
  if (value === 'false') {
    return false;
  }
  throw new AppError(400, 'lu invalide');
}

export function listerEmpruntsResponsable(
  roleCode: string,
  campusId: number,
  filtres: ListerEmpruntsResponsableFiltres,
): Promise<EmpruntResponsable[]> {
  verifierResponsable(roleCode);
  return findEmpruntsResponsable(campusId, filtres);
}

export function listerMaterielsResponsable(
  roleCode: string,
  campusId: number,
  filtres: ListerMaterielsResponsableFiltres,
): Promise<MaterielResponsable[]> {
  verifierResponsable(roleCode);
  return findMaterielsResponsable(campusId, filtres);
}

export function listerAnomaliesResponsable(
  roleCode: string,
  campusId: number,
  filtres: ListerAnomaliesResponsableFiltres,
): Promise<AnomalieResponsable[]> {
  verifierResponsable(roleCode);
  return findAnomaliesResponsable(campusId, filtres);
}

export function listerNotificationsResponsable(
  utilisateurId: number,
  roleCode: string,
  filtres: ListerNotificationsResponsableFiltres,
): Promise<NotificationResponsable[]> {
  verifierResponsable(roleCode);
  return findNotificationsResponsable(utilisateurId, filtres);
}

export async function marquerNotificationResponsableLue(
  utilisateurId: number,
  roleCode: string,
  notificationId: number,
): Promise<NotificationResponsable> {
  verifierResponsable(roleCode);

  try {
    return await marquerNotificationLue(utilisateurId, notificationId);
  } catch {
    throw new AppError(404, 'Notification introuvable');
  }
}

export function marquerToutesNotificationsResponsableLues(
  utilisateurId: number,
  roleCode: string,
): Promise<number> {
  verifierResponsable(roleCode);
  return marquerNotificationsResponsableLues(utilisateurId);
}

export function listerHistoriqueResponsable(
  roleCode: string,
  campusId: number,
  filtres: ListerHistoriqueResponsableFiltres,
): Promise<HistoriqueResponsable[]> {
  verifierResponsable(roleCode);
  return findHistoriqueResponsable(campusId, filtres);
}
