import { EstadoPieza } from '@prisma/client';
import { randomUUID } from 'crypto';
import { readDataFile, writeDataFile } from './local-store';
import { getFallbackPatientById, listFallbackPatients } from './patient.store';

export type StoredOdontogramPiece = {
  id: string;
  pacienteId: string;
  numero: number;
  estado: EstadoPieza;
  caras: string[];
  observacion: string | null;
  updatedAt: string;
};

type UpdateOdontogramPieceInput = {
  estado?: EstadoPieza;
  caras?: string[];
  observacion?: string | null;
};

const toothNumbers = [
  18, 17, 16, 15, 14, 13, 12, 11, 21, 22, 23, 24, 25, 26, 27, 28, 48, 47, 46, 45, 44, 43, 42, 41,
  31, 32, 33, 34, 35, 36, 37, 38,
] as const;

const fileName = 'odontogram.json';

const buildPatientOdontogram = (
  patientId: string,
  overrides: Record<number, { estado: EstadoPieza; caras?: string[]; observacion?: string | null }> = {},
) =>
  toothNumbers.map((toothNumber) => {
    const override = overrides[toothNumber];

    return {
      id: randomUUID(),
      pacienteId: patientId,
      numero: toothNumber,
      estado: override?.estado ?? EstadoPieza.SANO,
      caras: override?.caras ?? [],
      observacion: override?.observacion ?? null,
      updatedAt: new Date().toISOString(),
    };
  });

const buildSeedOdontogram = async () => {
  const patients = await listFallbackPatients();

  return patients.flatMap((patient, index) => {
    if (index === 0) {
      return buildPatientOdontogram(patient.id, {
        17: { estado: EstadoPieza.CARIES, caras: ['oclusal', 'mesial'], observacion: 'Control prioritario' },
        14: { estado: EstadoPieza.RESTAURADO, caras: ['oclusal'], observacion: 'Resina en seguimiento' },
        26: { estado: EstadoPieza.EXTRAIDO, observacion: 'Exodoncia previa' },
        46: { estado: EstadoPieza.CARIES, caras: ['oclusal', 'vestibular'], observacion: 'Dolor al masticar' },
      });
    }

    if (index === 1) {
      return buildPatientOdontogram(patient.id, {
        24: { estado: EstadoPieza.RESTAURADO, caras: ['oclusal'] },
        35: { estado: EstadoPieza.CORONA, observacion: 'Corona ceramica estable' },
      });
    }

    return buildPatientOdontogram(patient.id);
  });
};

const readPieces = async () => readDataFile<StoredOdontogramPiece[]>(fileName, buildSeedOdontogram);

const writePieces = async (pieces: StoredOdontogramPiece[]) => {
  await writeDataFile(fileName, pieces);
};

const ensurePatientOdontogram = async (patientId: string) => {
  const pieces = await readPieces();
  const patient = await getFallbackPatientById(patientId);

  if (!patient) {
    return [] as StoredOdontogramPiece[];
  }

  const patientPieces = pieces.filter((piece) => piece.pacienteId === patientId);

  if (patientPieces.length === toothNumbers.length) {
    return patientPieces.sort((left, right) => left.numero - right.numero);
  }

  const missingNumbers = toothNumbers.filter(
    (toothNumber) => !patientPieces.some((piece) => piece.numero === toothNumber),
  );

  if (missingNumbers.length === 0) {
    return patientPieces.sort((left, right) => left.numero - right.numero);
  }

  const now = new Date().toISOString();
  const nextPieces = [
    ...pieces,
    ...missingNumbers.map((toothNumber) => ({
      id: randomUUID(),
      pacienteId: patientId,
      numero: toothNumber,
      estado: EstadoPieza.SANO,
      caras: [],
      observacion: null,
      updatedAt: now,
    })),
  ];

  await writePieces(nextPieces);
  return nextPieces
    .filter((piece) => piece.pacienteId === patientId)
    .sort((left, right) => left.numero - right.numero);
};

export const listFallbackOdontogram = async (patientId: string) => ensurePatientOdontogram(patientId);

export const updateFallbackOdontogramPiece = async (
  patientId: string,
  toothNumber: number,
  input: UpdateOdontogramPieceInput,
) => {
  const patient = await getFallbackPatientById(patientId);

  if (!patient) {
    throw new Error('Paciente no encontrado');
  }

  const pieces = await readPieces();
  const patientPieces = await ensurePatientOdontogram(patientId);
  const existingPiece = patientPieces.find((piece) => piece.numero === toothNumber);

  if (!existingPiece) {
    throw new Error('Pieza no encontrada');
  }

  const updatedPiece: StoredOdontogramPiece = {
    ...existingPiece,
    estado: input.estado ?? existingPiece.estado,
    caras: input.caras ?? existingPiece.caras,
    observacion: input.observacion !== undefined ? input.observacion : existingPiece.observacion,
    updatedAt: new Date().toISOString(),
  };

  const nextPieces = pieces.map((piece) =>
    piece.pacienteId === patientId && piece.numero === toothNumber ? updatedPiece : piece,
  );

  await writePieces(nextPieces);
  return updatedPiece;
};
