import { EntrepriseDocumentId, EntrepriseId } from '../entreprise'
import { User, isAdministrationAdmin, isAdministrationEditeur, isSuper } from '../roles'
import { CommuneId } from '../static/communes'
import { DocumentsTypes, EntrepriseDocumentTypeId } from '../static/documentsTypes'
import { EtapeTypeId, EtapesTypes } from '../static/etapesTypes'
import { SDOMZoneId } from '../static/sdom'
import { getDocuments } from '../static/titresTypes_demarchesTypes_etapesTypes/documents'
import { getEntrepriseDocuments } from '../static/titresTypes_demarchesTypes_etapesTypes/entrepriseDocuments'
import { getSections, getSectionsWithValue } from '../static/titresTypes_demarchesTypes_etapesTypes/sections'
import { onlyUnique, NonEmptyArray, isNonEmptyArray, isNullOrUndefinedOrEmpty, isNullOrUndefined, Nullable } from '../typescript-tools'
import { sectionsWithValueCompleteValidate } from './sections'
import { canEditAmodiataires, canEditDuree, canEditPerimetre, canEditTitulaires } from './titres-etapes'
import { isArmMecanise } from '../static/mecanise'
import { getAvisTypes } from '../avisTypes'
import { EtapeDocument, TempEtapeDocument, EtapeAvis, TempEtapeAvis } from '../etape'
import { FlattenEtape } from '../etape-form'
import { MachineInfo } from '../machines'

type ValidReturn = { valid: true } | { valid: false; errors: NonEmptyArray<string> }

export const dateTypeStepIsVisible = (user: User): boolean => {
  return isSuper(user) || isAdministrationAdmin(user) || isAdministrationEditeur(user)
}
export const dateTypeStepIsComplete = (etape: Nullable<Pick<FlattenEtape, 'typeId' | 'date' | 'statutId'>>, user: User): ValidReturn => {
  if (!dateTypeStepIsVisible(user)) {
    return { valid: true }
  }

  const errors: string[] = []
  if (isNullOrUndefined(etape.date)) {
    errors.push("La date de l'étape est obligatoire")
  }

  if (isNullOrUndefined(etape.typeId)) {
    errors.push("Le type de l'étape est obligatoire")
  }

  if (isNullOrUndefined(etape.statutId)) {
    errors.push("Le statut de l'étape est obligatoire")
  }

  if (isNonEmptyArray(errors)) {
    return { valid: false, errors }
  }

  return { valid: true }
}

export const fondamentaleStepIsVisible = (etapeTypeId: EtapeTypeId): boolean => {
  return EtapesTypes[etapeTypeId].fondamentale
}

export const fondamentaleStepIsComplete = (flattened: Pick<FlattenEtape, 'typeId' | 'duree' | 'substances' | 'titulaires' | 'amodiataires'>, machineInfo: MachineInfo, user: User): ValidReturn => {
  if (!fondamentaleStepIsVisible(flattened.typeId)) {
    return { valid: true }
  }
  const errors: string[] = []

  if (isNullOrUndefinedOrEmpty(flattened.substances.value)) {
    errors.push('Les substances sont obligatoires')
  }

  const editDuree = canEditDuree(machineInfo, user)
  if (editDuree.visibility === 'present' && editDuree.required && (isNullOrUndefined(flattened.duree.value) || flattened.duree.value === 0)) {
    errors.push(editDuree.message)
  }

  const editTitulaires = canEditTitulaires(machineInfo, user)
  if (editTitulaires.visibility === 'present' && editTitulaires.required && isNullOrUndefinedOrEmpty(flattened.titulaires.value)) {
    errors.push(editTitulaires.message)
  }

  const editAmodiataires = canEditAmodiataires(machineInfo, user)
  if (editAmodiataires.visibility === 'present' && editAmodiataires.required && isNullOrUndefinedOrEmpty(flattened.amodiataires.value)) {
    errors.push(editAmodiataires.message)
  }

  if (isNonEmptyArray(errors)) {
    return { valid: false, errors }
  }

  return { valid: true }
}

export const sectionsStepIsVisible = (etape: Pick<FlattenEtape, 'typeId'>, machineInfo: MachineInfo): boolean => {
  return getSections(machineInfo, etape.typeId).length > 0
}
export const sectionsStepIsComplete = (etape: Pick<FlattenEtape, 'typeId' | 'contenu'>, machineInfo: MachineInfo): ValidReturn => {
  if (!sectionsStepIsVisible(etape, machineInfo)) {
    return { valid: true }
  }

  const sections = getSections(machineInfo, etape.typeId)
  const sectionsWithValue = getSectionsWithValue(sections, etape.contenu)
  const errors: string[] = sectionsWithValueCompleteValidate(sectionsWithValue)

  if (isNonEmptyArray(errors)) {
    return { valid: false, errors }
  }

  return { valid: true }
}

export const perimetreStepIsVisible = (etape: Pick<FlattenEtape, 'typeId'>, machineInfo: MachineInfo): boolean => {
  const editPerimetre = canEditPerimetre(machineInfo, etape.typeId)

  return editPerimetre.visibility === 'present'
}
export const perimetreStepIsComplete = (etape: Pick<FlattenEtape, 'typeId' | 'perimetre'>, machineInfo: MachineInfo): ValidReturn => {
  if (!perimetreStepIsVisible(etape, machineInfo)) {
    return { valid: true }
  }

  const errors: string[] = []
  const editPerimetre = canEditPerimetre(machineInfo, etape.typeId)
  if (editPerimetre.visibility === 'present' && editPerimetre.required && isNullOrUndefined(etape.perimetre.value?.geojson4326Perimetre)) {
    errors.push(editPerimetre.message)
  }

  if (isNonEmptyArray(errors)) {
    return { valid: false, errors }
  }

  return { valid: true }
}

export const etapeDocumentsStepIsVisible = (): boolean => {
  return true // il y'a forcément au moins le document "Autre" que l'on peut saisir, donc si on a le droit d'éditer une étape, on peut voir les documents dans la page d'édition d'une étape
}

export const etapeDocumentsStepIsComplete = (
  etape: Pick<FlattenEtape, 'typeId' | 'contenu' | 'isBrouillon'>,
  machineInfo: MachineInfo,
  etapeDocuments: Pick<EtapeDocument | TempEtapeDocument, 'etape_document_type_id'>[],
  sdomZoneIds: SDOMZoneId[]
): ValidReturn => {
  const errors: string[] = []
  const documentTypes = getDocuments(machineInfo, etape.typeId, sdomZoneIds, isArmMecanise(etape.contenu))

  errors.push(
    ...documentTypes
      .filter(({ optionnel, id }) => !optionnel && etapeDocuments.every(({ etape_document_type_id }) => etape_document_type_id !== id))
      .map(({ id }) => `le document "${DocumentsTypes[id].nom}" (${id}) est obligatoire`)
  )

  if (isNonEmptyArray(errors)) {
    return { valid: false, errors }
  }

  return { valid: true }
}

export const etapeAvisStepIsVisible = (etape: Pick<FlattenEtape, 'typeId' | 'contenu'>, machineInfo: MachineInfo, communeIds: CommuneId[]): boolean => {
  return Object.keys(getAvisTypes(etape.typeId, machineInfo, communeIds, isArmMecanise(etape.contenu))).length > 0
}

export const etapeAvisStepIsComplete = (
  etape: Pick<FlattenEtape, 'typeId' | 'contenu'>,
  etapeAvis: Pick<EtapeAvis | TempEtapeAvis, 'avis_type_id'>[],
  machineInfo: MachineInfo,
  communeIds: CommuneId[]
): ValidReturn => {
  if (!etapeAvisStepIsVisible(etape, machineInfo, communeIds)) {
    return { valid: true }
  }

  const avisTypes = getAvisTypes(etape.typeId, machineInfo, communeIds, isArmMecanise(etape.contenu))
  if (Object.values(avisTypes).some(avisType => !avisType.optionnel && etapeAvis.every(avis => avis.avis_type_id !== avisType.id))) {
    return { valid: false, errors: ['Il manque des avis obligatoires'] }
  }

  return { valid: true }
}

export const entrepriseDocumentsStepIsVisible = (etape: Pick<FlattenEtape, 'typeId'>, machineInfo: MachineInfo): boolean => {
  return getEntrepriseDocuments(machineInfo, etape.typeId).length > 0
}
export const entrepriseDocumentsStepIsComplete = (
  etape: Pick<FlattenEtape, 'typeId' | 'contenu' | 'titulaires' | 'amodiataires'>,
  machineInfo: MachineInfo,
  entreprisesDocuments: Pick<SelectedEntrepriseDocument, 'documentTypeId' | 'entrepriseId'>[]
): ValidReturn => {
  if (!entrepriseDocumentsStepIsVisible(etape, machineInfo)) {
    return { valid: true }
  }

  const documentTypes = getEntrepriseDocuments(machineInfo, etape.typeId)

  const entrepriseIds = [...etape.titulaires.value, ...etape.amodiataires.value].filter(onlyUnique)

  if (isNullOrUndefinedOrEmpty(entrepriseIds) && getEntrepriseDocuments(machineInfo, etape.typeId).some(({ optionnel }) => !optionnel)) {
    return { valid: false, errors: ["Il y a des documents d'entreprise obligatoires, mais il n'y a pas de titulaire"] }
  }

  if (
    entrepriseIds.some(eId => documentTypes.some(({ optionnel, id }) => !optionnel && entreprisesDocuments.every(({ documentTypeId, entrepriseId }) => documentTypeId !== id || entrepriseId !== eId)))
  ) {
    return { valid: false, errors: ["Il manque des documents d'entreprise obligatoires"] }
  }

  return { valid: true }
}

export type SelectedEntrepriseDocument = {
  id: EntrepriseDocumentId
  entrepriseId: EntrepriseId
  documentTypeId: EntrepriseDocumentTypeId
}
