import { TitreTypeId } from 'camino-common/src/static/titresTypes'
import { ArmOctMachine } from './arm/oct.machine'
import { ArmRenProMachine } from './arm/ren-pro.machine'
import { AxmOctMachine } from './axm/oct.machine'
import { AxmProMachine } from './axm/pro.machine'
import { PrmOctMachine } from './prm/oct.machine'
import { ProcedureSimplifieeMachine } from './procedure-simplifiee/procedure-simplifiee.machine'
import { ProcedureSpecifiqueMachine } from './procedure-specifique/procedure-specifique.machine'
import { MachineInfo } from 'camino-common/src/machines'
import { DemarcheTypeId } from 'camino-common/src/static/demarchesTypes'
import { DemarcheId } from 'camino-common/src/demarche'
import { CaminoMachineId } from 'camino-common/src/validators/machine'
import { CaminoDate, FirstEtapeDate, firstEtapeDateValidator } from 'camino-common/src/date'
import { EtapeTypeId, ETAPES_TYPES } from 'camino-common/src/static/etapesTypes'
import { isNullOrUndefinedOrEmpty, isNotNullNorUndefined, toSorted } from 'camino-common/src/typescript-tools'
import { NonEmptyArray } from 'zod-validation-error'

const machines = {
  AncienLogigrammeOctroiARM: (titreTypeId, demarcheTypeId) => new ArmOctMachine(titreTypeId, demarcheTypeId),
  AncienLogigrammeRenonciationEtProlongationARM: (titreTypeId, demarcheTypeId) => new ArmRenProMachine(titreTypeId, demarcheTypeId),
  AncienLogigrammeOctroiAXM: (titreTypeId, demarcheTypeId) => new AxmOctMachine(titreTypeId, demarcheTypeId),
  AncienLogigrammeProlongationAXM: (titreTypeId, demarcheTypeId) => new AxmProMachine(titreTypeId, demarcheTypeId),
  AncienLogigrammeOctroiPRM: (titreTypeId, demarcheTypeId) => new PrmOctMachine(titreTypeId, demarcheTypeId),
  ProcedureSimplifiee: (titreTypeId, demarcheTypeId) => new ProcedureSimplifieeMachine(titreTypeId, demarcheTypeId),
  ProcedureSpecifique: (titreTypeId, demarcheTypeId) => new ProcedureSpecifiqueMachine(titreTypeId, demarcheTypeId),
} as const satisfies Record<CaminoMachineId, (titreTypeId: TitreTypeId, demarcheTypeId: DemarcheTypeId) => CaminoMachines>

export class ApiMachineInfo {
  private _machineInfo: MachineInfo
  private _machine: CaminoMachines | undefined
  public constructor(machineInfo: MachineInfo) {
    this._machineInfo = machineInfo
    this._machine = machineInfo.machineId === undefined ? undefined : machines[machineInfo.machineId](machineInfo.titreTypeId, machineInfo.demarcheTypeId)
  }

  get machineId(): CaminoMachineId | undefined {
    return this._machineInfo.machineId
  }
  get titreTypeId(): TitreTypeId {
    return this._machineInfo.titreTypeId
  }
  get demarcheTypeId(): DemarcheTypeId {
    return this._machineInfo.demarcheTypeId
  }
  get demarcheId(): DemarcheId {
    return this._machineInfo.demarcheId
  }
  get machine(): CaminoMachines | undefined {
    return this._machine
  }
}

export type CaminoMachines = ArmOctMachine | AxmOctMachine | AxmProMachine | ArmRenProMachine | PrmOctMachine | ProcedureSimplifieeMachine | ProcedureSpecifiqueMachine

type DemarcheEnregistrementDemandeDateFindEtape = { date: CaminoDate; typeId: EtapeTypeId }
export function demarcheEnregistrementDemandeDateFind<T extends DemarcheEnregistrementDemandeDateFindEtape[] | NonEmptyArray<DemarcheEnregistrementDemandeDateFindEtape>>(
  titreEtapes: T | undefined
): T extends [DemarcheEnregistrementDemandeDateFindEtape, ...DemarcheEnregistrementDemandeDateFindEtape[]] ? FirstEtapeDate : FirstEtapeDate | null
export function demarcheEnregistrementDemandeDateFind(titreEtapes: DemarcheEnregistrementDemandeDateFindEtape[] | undefined): null | FirstEtapeDate {
  if (isNullOrUndefinedOrEmpty(titreEtapes)) {
    return null
  }

  const titreEtapeDemande = titreEtapes.find(te => te.typeId === ETAPES_TYPES.enregistrementDeLaDemande)

  if (isNotNullNorUndefined(titreEtapeDemande)) {
    return firstEtapeDateValidator.parse(titreEtapeDemande.date)
  }

  return firstEtapeDateValidator.parse(toSorted(titreEtapes.map(te => te.date))[0])
}
