import { CaminoMachineId } from 'camino-common/src/validators/machine'
import { CaminoError } from 'camino-common/src/zod-tools'
import { Effect } from 'effect'
import { Pool } from 'pg'
import { DemarcheId, DemarcheSlug } from 'camino-common/src/demarche'
import { getDemarcheByIdOrSlug, GetDemarcheByIdOrSlugErrors, getDemarches, getFirstEtapeDateByDemarcheIdOrSlug, GetFirstEtapeDateByDemarcheIdOrSlugErrors } from '../../api/rest/demarches.queries'
import { MachineInfo } from 'camino-common/src/machines'
import { isNotNullNorUndefined } from 'camino-common/src/typescript-tools'
import { updateMachineId, UpdateMachineIdErrors } from './update-machine-id.queries'

export const demarcheMachineIdsUpdate = (pool: Pool): Effect.Effect<Changes[], CaminoError<DemarcheMachineIdUpdateErrors>> => {
  console.info('')
  console.info('machine des démarches…')
  return Effect.Do.pipe(
    Effect.flatMap(() => getDemarches(pool)),
    Effect.flatMap(demarches => Effect.forEach(demarches, demarche => demarcheMachineIdUpdate(pool, demarche.id))),
    Effect.map(changesAndNoChanges => changesAndNoChanges.filter(value => value.changes))
  )
}

type Changes = { changes: true; demarcheSlug: DemarcheSlug; old: CaminoMachineId | null; new: CaminoMachineId | null }
type NoChange = { changes: false }
type ReturnValue = Changes | NoChange
type DemarcheMachineIdUpdateErrors = GetFirstEtapeDateByDemarcheIdOrSlugErrors | GetDemarcheByIdOrSlugErrors | UpdateMachineIdErrors
export const demarcheMachineIdUpdate = (pool: Pool, demarcheId: DemarcheId): Effect.Effect<ReturnValue, CaminoError<DemarcheMachineIdUpdateErrors>> => {
  return Effect.Do.pipe(
    Effect.bind('demarche', () => getDemarcheByIdOrSlug(pool, demarcheId)),
    Effect.bind('firstEtapeDate', () => getFirstEtapeDateByDemarcheIdOrSlug(demarcheId, pool)),
    Effect.let('newMachineId', ({ demarche, firstEtapeDate }) =>
      isNotNullNorUndefined(firstEtapeDate) ? (MachineInfo.withDate(demarche.titre_type_id, demarche.demarche_type_id, demarche.demarche_id, firstEtapeDate).machineId ?? null) : null
    ),
    Effect.flatMap(({ demarche, newMachineId }) => {
      if (demarche.machine_id === newMachineId) {
        return Effect.succeed<ReturnValue>({ changes: false })
      }

      return Effect.Do.pipe(
        Effect.flatMap(() => updateMachineId(pool, demarcheId, newMachineId)),
        Effect.map(() => {
          console.info(`Changement de machine pour la démarche https://camino.beta.gouv.fr/demarches/${demarche.demarche_slug} old: ${demarche.machine_id} -> ${newMachineId}`)
          return {
            changes: true,
            demarcheSlug: demarche.demarche_slug,
            old: demarche.machine_id,
            new: newMachineId,
          }
        })
      )
    })
  )
}
