import { EntrepriseDocumentId, EntrepriseId } from '../entreprise'
import { FlattenEtape } from '../etape-form'
import { EtapeAvis, EtapeDocument, TempEtapeAvis, TempEtapeDocument } from '../etape'
import { User, isAdministrationAdmin, isAdministrationEditeur, isSuper } from '../roles'
import { CommuneId } from '../static/communes'
import { DemarcheTypeId } from '../static/demarchesTypes'
import { DocumentsTypes, EntrepriseDocumentTypeId } from '../static/documentsTypes'
import { EtapeTypeId, EtapesTypes } from '../static/etapesTypes'
import { SDOMZoneId } from '../static/sdom'
import { TitreTypeId } from '../static/titresTypes'
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 { DemarcheId } from '../demarche'
import { FirstEtapeDate } from '../date'
import { isArmMecanise } from '../static/mecanise'
import { getAvisTypes } from '../avisTypes'

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'>,
  demarcheTypeId: DemarcheTypeId,
  titreTypeId: TitreTypeId,
  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(titreTypeId, demarcheTypeId, user)
  if (editDuree.visibility === 'present' && editDuree.required && (isNullOrUndefined(flattened.duree.value) || flattened.duree.value === 0)) {
    errors.push(editDuree.message)
  }

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

  const editAmodiataires = canEditAmodiataires(titreTypeId, demarcheTypeId, 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'>, demarcheTypeId: DemarcheTypeId, titreTypeId: TitreTypeId): boolean => {
  return getSections(titreTypeId, demarcheTypeId, etape.typeId).length > 0
}
export const sectionsStepIsComplete = (etape: Pick<FlattenEtape, 'typeId' | 'contenu'>, demarcheTypeId: DemarcheTypeId, titreTypeId: TitreTypeId): ValidReturn => {
  if (!sectionsStepIsVisible(etape, demarcheTypeId, titreTypeId)) {
    return { valid: true }
  }

  const sections = getSections(titreTypeId, demarcheTypeId, 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'>, demarcheTypeId: DemarcheTypeId): boolean => {
  const editPerimetre = canEditPerimetre(demarcheTypeId, etape.typeId)

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

  const errors: string[] = []
  const editPerimetre = canEditPerimetre(demarcheTypeId, 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'>,
  demarcheTypeId: DemarcheTypeId,
  titreTypeId: TitreTypeId,
  demarcheId: DemarcheId,
  etapeDocuments: Pick<EtapeDocument | TempEtapeDocument, 'etape_document_type_id'>[],
  sdomZoneIds: SDOMZoneId[],
  firstEtapeDate: FirstEtapeDate
): ValidReturn => {
  const errors: string[] = []
  const documentTypes = getDocuments(titreTypeId, demarcheTypeId, etape.typeId, firstEtapeDate, demarcheId, 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'>,
  titreTypeId: TitreTypeId,
  demarcheTypeId: DemarcheTypeId,
  demarcheId: DemarcheId,
  firstEtapeDate: FirstEtapeDate,
  communeIds: CommuneId[]
): boolean => {
  return Object.keys(getAvisTypes(etape.typeId, titreTypeId, demarcheTypeId, demarcheId, firstEtapeDate, communeIds, isArmMecanise(etape.contenu))).length > 0
}

export const etapeAvisStepIsComplete = (
  etape: Pick<FlattenEtape, 'typeId' | 'contenu'>,
  etapeAvis: Pick<EtapeAvis | TempEtapeAvis, 'avis_type_id'>[],
  titreTypeId: TitreTypeId,
  demarcheTypeId: DemarcheTypeId,
  demarcheId: DemarcheId,
  firstEtapeDate: FirstEtapeDate,
  communeIds: CommuneId[]
): ValidReturn => {
  if (!etapeAvisStepIsVisible(etape, titreTypeId, demarcheTypeId, demarcheId, firstEtapeDate, communeIds)) {
    return { valid: true }
  }

  const avisTypes = getAvisTypes(etape.typeId, titreTypeId, demarcheTypeId, demarcheId, firstEtapeDate, 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'>, demarcheTypeId: DemarcheTypeId, titreTypeId: TitreTypeId): boolean => {
  return getEntrepriseDocuments(titreTypeId, demarcheTypeId, etape.typeId).length > 0
}
export const entrepriseDocumentsStepIsComplete = (
  etape: Pick<FlattenEtape, 'typeId' | 'contenu' | 'titulaires' | 'amodiataires'>,
  demarcheTypeId: DemarcheTypeId,
  titreTypeId: TitreTypeId,
  entreprisesDocuments: Pick<SelectedEntrepriseDocument, 'documentTypeId' | 'entrepriseId'>[]
): ValidReturn => {
  if (!entrepriseDocumentsStepIsVisible(etape, demarcheTypeId, titreTypeId)) {
    return { valid: true }
  }

  const documentTypes = getEntrepriseDocuments(titreTypeId, demarcheTypeId, etape.typeId)

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

  if (isNullOrUndefinedOrEmpty(entrepriseIds) && getEntrepriseDocuments(titreTypeId, demarcheTypeId, 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
}
