import { ETAPES_TYPES, EtapeTypeId, EtapesTypes } from 'camino-common/src/static/etapesTypes'
import { computed, defineComponent, onMounted, ref } from 'vue'
import { DsfrSeparator } from '../_ui/dsfr-separator'
import { capitalize } from 'camino-common/src/strings'
import { ETAPES_STATUTS, EtapeStatutId } from 'camino-common/src/static/etapesStatuts'
import { getEtapesStatuts } from 'camino-common/src/static/etapesTypesEtapesStatuts'
import { CaminoDate, dateFormat } from 'camino-common/src/date'
import { DsfrIcon } from '../_ui/icon'
import { EtapeStatut } from '../_common/etape-statut'
import { PropDuree } from '../etape/prop-duree'
import { SubstancesLegale } from 'camino-common/src/static/substancesLegales'
import { EtapePropEntreprisesItem, EtapePropItem } from '../etape/etape-prop-item'
import { DemarcheEtape as CommonDemarcheEtape, DemarcheConsentement, demarcheEnregistrementDemandeDateFind, DemarcheId } from 'camino-common/src/demarche'
import { DsfrPerimetre, TabId } from '../_common/dsfr-perimetre'
import { TitreSlug } from 'camino-common/src/validators/titres'
import { numberFormat } from 'camino-common/src/number'
import { OmitDistributive, getValues, isNotNullNorUndefined, isNotNullNorUndefinedNorEmpty, isNullOrUndefined } from 'camino-common/src/typescript-tools'
import { ElementWithValue, valeurFind } from 'camino-common/src/sections'
import { EtapeDocuments } from '../etape/etape-documents'
import { isEntrepriseOrBureauDEtude, User } from 'camino-common/src/roles'
import styles from './demarche-etape.module.css'
import { DsfrButton, DsfrButtonIcon, DsfrLink } from '../_ui/dsfr-button'
import { PureDownloads } from '../_common/downloads'
import { canCreateEtape, canDeleteEtape, canDeposeEtape, canEditEtape } from 'camino-common/src/permissions/titres-etapes'
import { AdministrationId } from 'camino-common/src/static/administrations'
import { DemarcheTypeId } from 'camino-common/src/static/demarchesTypes'
import { TitreStatutId } from 'camino-common/src/static/titresStatuts'
import { TitreTypeId } from 'camino-common/src/static/titresTypes'
import { RemoveEtapePopup } from './remove-etape-popup'
import { SDOMZoneId } from 'camino-common/src/static/sdom'
import { DeposeEtapePopup } from './depose-etape-popup'
import { ApiClient } from '@/api/api-client'
import { TitreGetDemarche, getMostRecentValuePropFromEtapeFondamentaleValide } from 'camino-common/src/titres'
import { Unites } from 'camino-common/src/static/unites'
import { EntrepriseId, Entreprise } from 'camino-common/src/entreprise'
import { Badge } from '../_ui/badge'
import { CaminoRouter } from '@/typings/vue-router'
import { CommuneId } from 'camino-common/src/static/communes'
import { EtapeAvisTable } from '../etape/etape-avis'
import { FlattenEtape } from 'camino-common/src/etape-form'
import { getSections } from 'camino-common/src/static/titresTypes_demarchesTypes_etapesTypes/sections'
import { Alert } from '../_ui/alert'
import { getInfo } from '../_common/new-sections-edit'
import { getDemandesConsentement } from '../titre/demarche-consentement'
import { DemarcheStatutId } from 'camino-common/src/static/demarchesStatuts'
import { ETAPE_IS_BROUILLON } from 'camino-common/src/etape'

import { AsyncData } from '@/api/client-rest'
import { LoadingElement } from '../_ui/functional-loader'
import { useState } from '@/utils/vue-tsx-utils'
// Il ne faut pas utiliser de literal dans le 'in' il n'y aura jamais d'erreur typescript
const fondamentalePropsName = 'fondamentale'

type Props = {
  etape: OmitDistributive<CommonDemarcheEtape, 'ordre'>
  demarche: {
    id: DemarcheId
    titulaireIds: EntrepriseId[]
    administrationsLocales: AdministrationId[]
    demarche_type_id: DemarcheTypeId
    demarche_statut_id: DemarcheStatutId
    sdom_zones: SDOMZoneId[]
    communes: CommuneId[]
    etapes: TitreGetDemarche['etapes']
  }
  titre: {
    typeId: TitreTypeId
    slug: TitreSlug
    nom: string
    titreStatutId: TitreStatutId
  }
  apiClient: Pick<ApiClient, 'deleteEtape' | 'deposeEtape' | 'getEtapesTypesEtapesStatuts' | 'etapeCreer'>
  router: Pick<CaminoRouter, 'push'>
  user: User
  entreprises: Entreprise[]
  currentDate: CaminoDate
  initTab?: TabId
}

const displayEtapeStatus = (etape_type_id: EtapeTypeId, etape_statut_id: EtapeStatutId): boolean => {
  switch (etape_type_id) {
    case ETAPES_TYPES.demande:
      return etape_statut_id !== ETAPES_STATUTS.FAIT
    default:
      return getEtapesStatuts(etape_type_id).length > 1
  }
}

export const DemarcheEtape = defineComponent<Props>(props => {
  const hasContent = computed<boolean>(() => {
    if (isNotNullNorUndefinedNorEmpty(props.etape.note.valeur)) {
      return true
    }

    const hasSectionWithValue = props.etape.sections_with_values.some(section => section.elements.filter(element => valeurFind(element) !== '–').length > 0)
    if (hasSectionWithValue) {
      return true
    }
    if (fondamentalePropsName in props.etape) {
      const { perimetre: _perimetre, ...fondamentale } = props.etape.fondamentale

      return getValues(fondamentale).some(v => isNotNullNorUndefined(v) && (!Array.isArray(v) || v.length > 0))
    }

    return false
  })

  const consentement = computed<DemarcheConsentement[] | null>(() => {
    if (props.etape.etape_type_id === ETAPES_TYPES.demandeDeConsentement) {
      return getDemandesConsentement(props.demarche)
    }
    return null
  })

  const entreprisesIndex = props.entreprises.reduce<Record<EntrepriseId, string>>((acc, entreprise) => {
    acc[entreprise.id] = entreprise.nom

    return acc
  }, {})

  const removePopupVisible = ref<boolean>(false)
  const removePopupOpen = () => {
    removePopupVisible.value = true
  }
  const closeRemovePopup = () => {
    removePopupVisible.value = !removePopupVisible.value
  }
  const deposePopupVisible = ref<boolean>(false)
  const deposePopupOpen = () => {
    deposePopupVisible.value = true
  }
  const closeDeposePopup = () => {
    deposePopupVisible.value = !deposePopupVisible.value
  }

  const canDownloadZip = computed<boolean>(() => {
    return props.etape.avis_documents.filter(({ has_file }) => has_file).length + props.etape.entreprises_documents.length + props.etape.etape_documents.length > 1
  })

  const canDelete = computed<boolean>(() =>
    canDeleteEtape(props.user, props.etape.etape_type_id, props.etape.is_brouillon, props.demarche.titulaireIds, props.demarche.administrationsLocales, props.demarche.demarche_type_id, props.titre)
  )

  const canEditOrDeleteEtape = computed<boolean>(
    () =>
      canEditEtape(props.user, props.etape.etape_type_id, props.etape.is_brouillon, props.demarche.titulaireIds, props.demarche.administrationsLocales, props.demarche.demarche_type_id, props.titre) ||
      canDelete.value
  )

  const isDeposable = computed<boolean>(() => {
    const titulaireIds = getMostRecentValuePropFromEtapeFondamentaleValide('titulaireIds', [{ ...props.demarche, ordre: 0 }])
    const amodiataireIds = getMostRecentValuePropFromEtapeFondamentaleValide('amodiataireIds', [{ ...props.demarche, ordre: 0 }])
    const perimetre = getMostRecentValuePropFromEtapeFondamentaleValide('perimetre', [{ ...props.demarche, ordre: 0 }])
    const substances = getMostRecentValuePropFromEtapeFondamentaleValide('substances', [{ ...props.demarche, ordre: 0 }])
    const duree = getMostRecentValuePropFromEtapeFondamentaleValide('duree', [{ ...props.demarche, ordre: 0 }])

    const sections = getSections(props.titre.typeId, props.demarche.demarche_type_id, props.etape.etape_type_id)
    const sortedEtapes = [...props.demarche.etapes].sort((a, b) => b.ordre - a.ordre)
    const contenu: FlattenEtape['contenu'] = {}

    sections.forEach(section => {
      contenu[section.id] = {}
      section.elements.forEach(element => {
        let elementValue = null
        for (const etape of sortedEtapes) {
          const sectionWithValue = etape.sections_with_values.find(s => s.id === section.id)
          const elementWithValue = sectionWithValue?.elements.find(e => e.id === element.id)

          if (isNotNullNorUndefined(elementWithValue)) {
            elementValue = elementWithValue.value
            break
          }
        }

        contenu[section.id]![element.id] = { value: elementValue, heritee: false, etapeHeritee: null }
      })
    })

    const firstEtapeDate = demarcheEnregistrementDemandeDateFind(props.demarche.etapes.map(({ date, etape_type_id }) => ({ date, typeId: etape_type_id })))
    if (isNullOrUndefined(firstEtapeDate)) {
      return false
    }

    return canDeposeEtape(
      props.user,
      { typeId: props.titre.typeId, titreStatutId: props.titre.titreStatutId, titulaires: props.demarche.titulaireIds, administrationsLocales: props.demarche.administrationsLocales },
      props.demarche.id,
      props.demarche.demarche_type_id,
      {
        amodiataires: { value: amodiataireIds ?? [], heritee: false, etapeHeritee: null },
        titulaires: { value: titulaireIds ?? [], heritee: false, etapeHeritee: null },
        contenu,
        date: props.etape.date,
        typeId: props.etape.etape_type_id,
        duree: { value: duree, heritee: false, etapeHeritee: null },
        perimetre: {
          value: {
            geojson4326Forages: perimetre?.geojson4326_forages ?? null,
            geojson4326Perimetre: perimetre?.geojson4326_perimetre ?? null,
            geojson4326Points: perimetre?.geojson4326_points ?? null,
            geojsonOrigineForages: perimetre?.geojson_origine_forages ?? null,
            geojsonOrigineGeoSystemeId: perimetre?.geojson_origine_geo_systeme_id ?? null,
            geojsonOriginePoints: perimetre?.geojson_origine_points ?? null,
            geojsonOriginePerimetre: perimetre?.geojson_origine_perimetre ?? null,
            surface: perimetre?.surface ?? null,
          },
          heritee: false,
          etapeHeritee: null,
        },
        substances: { value: substances ?? [], heritee: false, etapeHeritee: null },

        isBrouillon: props.etape.is_brouillon,
        statutId: props.etape.etape_statut_id,
      },
      props.etape.etape_documents,
      props.etape.entreprises_documents,
      props.demarche.sdom_zones,
      props.demarche.communes,
      props.etape.avis_documents,
      firstEtapeDate
    )
  })

  const isBrouillon = computed<boolean>(() => props.etape.is_brouillon)

  const [showReponseComplementButton, setShowReponseComplementButton] = useState<AsyncData<boolean>>({ status: 'LOADED', value: false })
  onMounted(async () => {
    const lastDemandeComplements = props.demarche.etapes.findLast(({ etape_type_id }) => etape_type_id === ETAPES_TYPES.demandeDeComplements)
    if (isNotNullNorUndefined(lastDemandeComplements) && lastDemandeComplements.id === props.etape.id) {
      const canCreateReponseComplement = canCreateEtape(
        props.user,
        ETAPES_TYPES.receptionDeComplements,
        ETAPE_IS_BROUILLON,
        props.demarche.titulaireIds,
        props.demarche.administrationsLocales,
        props.demarche.demarche_type_id,
        props.titre
      )
      if (canCreateReponseComplement) {
        setShowReponseComplementButton({ status: 'LOADING' })
        const etapeTypesPotential = await props.apiClient.getEtapesTypesEtapesStatuts(props.demarche.id, null, props.currentDate)
        if ('message' in etapeTypesPotential) {
          setShowReponseComplementButton({ status: 'NEW_ERROR', error: etapeTypesPotential })
        } else {
          setShowReponseComplementButton({ status: 'LOADED', value: Object.keys(etapeTypesPotential).includes(ETAPES_TYPES.receptionDeComplements) })
        }
      }
    }
  })

  const goToEditEtapeReponseComplement = async () => {
    setShowReponseComplementButton({ status: 'LOADING' })
    const result = await props.apiClient.etapeCreer({
      typeId: ETAPES_TYPES.receptionDeComplements,
      statutId: ETAPES_STATUTS.FAIT,
      date: props.currentDate,
      titreDemarcheId: props.demarche.id,
      note: { valeur: '', is_avertissement: false },
      dateDebut: null,
      dateFin: null,
      duree: null,
      substances: [],
      titulaireIds: [],
      amodiataireIds: [],
      geojson4326Perimetre: null,
      geojson4326Points: null,
      geojsonOriginePoints: null,
      geojsonOriginePerimetre: null,
      geojsonOrigineGeoSystemeId: null,
      geojsonOrigineForages: null,
      contenu: {},
      heritageProps: {
        dateDebut: { actif: true },
        dateFin: { actif: true },
        duree: { actif: true },
        perimetre: { actif: true },
        substances: { actif: true },
        titulaires: { actif: true },
        amodiataires: { actif: true },
      },
      heritageContenu: {},
      etapeDocuments: [],
      entrepriseDocumentIds: [],
      etapeAvis: [],
    })

    if ('message' in result) {
      setShowReponseComplementButton({ status: 'NEW_ERROR', error: result })
    } else {
      props.router.push({ name: 'etapeEdition', params: { id: result.id } })
    }
  }

  const deposeEtape = () => props.apiClient.deposeEtape(props.etape.id)

  return () => (
    <div class="fr-pb-2w fr-pl-2w fr-pr-2w fr-tile--shadow" style={{ border: '1px solid var(--grey-900-175)' }}>
      <div class={`${styles.sticky} fr-pt-1w`}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
          <div style={{ display: 'flex' }}>
            <h4 class="fr-text--lg fr-mb-0" style={{ color: 'var(--text-title-blue-france)', fontWeight: '500' }}>
              {capitalize(EtapesTypes[props.etape.etape_type_id].nom)}
            </h4>
            {isBrouillon.value ? <Badge class="fr-ml-1w" systemLevel="new" ariaLabel={`Brouillon de l'étape ${EtapesTypes[props.etape.etape_type_id].nom}`} label="Brouillon" /> : null}
          </div>

          <div style={{ display: 'flex', gap: '0.25rem' }}>
            <LoadingElement data={showReponseComplementButton.value} renderItem={() => <></>} />
            {showReponseComplementButton.value.status === 'LOADED' && showReponseComplementButton.value.value === false ? null : (
              <DsfrButton
                label="Répondre à la demande de compléments"
                disabled={showReponseComplementButton.value.status === 'LOADING'}
                buttonType={isEntrepriseOrBureauDEtude(props.user) ? 'primary' : 'secondary'}
                onClick={goToEditEtapeReponseComplement}
                title={`Répondre à la demande de compléments du ${props.etape.date}`}
              />
            )}
            {canEditOrDeleteEtape.value ? (
              <>
                {isBrouillon.value ? <DsfrButton buttonType="primary" label="Finaliser" title="Finaliser l'étape" onClick={deposePopupOpen} disabled={!isDeposable.value} /> : null}
                <DsfrLink
                  icon={{ name: 'fr-icon-pencil-line', position: 'right' }}
                  disabled={false}
                  to={{ name: 'etapeEdition', params: { id: props.etape.slug } }}
                  buttonType="secondary"
                  title="Modifier l’étape"
                  label={null}
                />
                {canDelete.value ? <DsfrButtonIcon icon={'fr-icon-delete-bin-line'} buttonType="secondary" title="Supprimer l’étape" onClick={removePopupOpen} /> : null}
              </>
            ) : null}
            {canDownloadZip.value ? (
              <PureDownloads
                downloadTitle={`Télécharger l’ensemble des documents de l'étape "${EtapesTypes[props.etape.etape_type_id].nom}" dans un fichier .zip`}
                downloadRoute="/etape/zip/:etapeId"
                params={{ etapeId: props.etape.id }}
                formats={['pdf']}
                route={{ query: {} }}
              />
            ) : null}
          </div>
        </div>

        {displayEtapeStatus(props.etape.etape_type_id, props.etape.etape_statut_id) ? <EtapeStatut etapeStatutId={props.etape.etape_statut_id} /> : null}
        <div class="fr-mt-1w">
          <DsfrIcon name="fr-icon-calendar-line" color="text-title-blue-france" aria-hidden="true" /> {dateFormat(props.etape.date)}
        </div>
      </div>{' '}
      {isNotNullNorUndefinedNorEmpty(consentement.value) ? (
        <>
          <DsfrSeparator />
          <span>Les titres suivants ont donné leur consentement :</span>
          <ul>
            {consentement.value.map(({ demarcheId, titreNom }) => (
              <li>
                <DsfrLink title={titreNom} disabled={false} icon={null} to={{ name: 'demarche', params: { demarcheId } }} />
              </li>
            ))}
          </ul>
        </>
      ) : null}
      {hasContent.value ? (
        <>
          <DsfrSeparator />
          <div
            style={{
              display: 'grid',
              gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))',
              alignContent: 'flex-start',
              columnGap: '16px',
              rowGap: '8px',
            }}
          >
            {fondamentalePropsName in props.etape ? (
              <>
                {props.etape.fondamentale.date_debut ? <EtapePropItem title="Date de début" text={dateFormat(props.etape.fondamentale.date_debut)} /> : null}
                {props.etape.fondamentale.duree !== null ? <EtapePropItem title="Durée" item={<PropDuree duree={props.etape.fondamentale.duree} />} /> : null}
                {props.etape.fondamentale.date_fin ? <EtapePropItem title="Date de fin" text={dateFormat(props.etape.fondamentale.date_fin)} /> : null}
                {(props.etape.fondamentale.substances?.length ?? 0) > 0 ? (
                  <EtapePropItem title="Substances" text={(props.etape.fondamentale.substances ?? []).map(s => capitalize(SubstancesLegale[s].nom)).join(', ')} />
                ) : null}
                <EtapePropEntreprisesItem title="Titulaire" entreprises={props.etape.fondamentale.titulaireIds?.map(id => ({ id, nom: entreprisesIndex[id] })) ?? []} />
                <EtapePropEntreprisesItem title="Amodiataire" entreprises={props.etape.fondamentale.amodiataireIds?.map(id => ({ id, nom: entreprisesIndex[id] })) ?? []} />
                {isNotNullNorUndefined(props.etape.fondamentale.perimetre) && isNotNullNorUndefined(props.etape.fondamentale.perimetre.surface) ? (
                  <EtapePropItem title="Surface" text={`${numberFormat(props.etape.fondamentale.perimetre.surface)} km² environ`} />
                ) : null}
              </>
            ) : null}
            {props.etape.sections_with_values.map(section => (
              <>
                {section.elements
                  .filter(element => valeurFind(element) !== '–')
                  .map(element => (
                    <>
                      <EtapePropItem
                        title={element.nom ?? element.id}
                        item={
                          <>
                            {element.type === 'url' ? (
                              <a target="_blank" rel="noopener noreferrer" href={valeurFind(element)} title={`${element.nom} - Lien externe`}>
                                {valeurFind(element)}
                              </a>
                            ) : (
                              <p>
                                {element.id === 'jorf' && element.value !== null && element.value !== '' ? (
                                  <a target="_blank" rel="noopener noreferrer" href={`https://www.legifrance.gouv.fr/jorf/id/${valeurFind(element)}`} title={`Numéro JORF Légifrance - Lien externe`}>
                                    {valeurFind(element)}
                                  </a>
                                ) : (
                                  <>
                                    {valeurFind(element)} {element.type === 'number' && isNotNullNorUndefined(element.uniteId) ? Unites[element.uniteId].symbole : null}
                                    <SectionElementInfo element={element} sectionId={section.id} etapeDate={props.etape.date} />
                                  </>
                                )}
                              </p>
                            )}
                          </>
                        }
                      />
                    </>
                  ))}
              </>
            ))}
            {isNotNullNorUndefinedNorEmpty(props.etape.note.valeur) ? (
              <>
                {props.etape.note.is_avertissement ? (
                  <Alert style={{ gridColumn: '1 / -1' }} small={true} title={props.etape.note.valeur} type="warning" />
                ) : (
                  <EtapePropItem style={{ gridColumn: '1 / -1', whiteSpace: 'pre-line' }} title="Notes" text={props.etape.note.valeur} />
                )}
              </>
            ) : null}
          </div>
        </>
      ) : null}
      {fondamentalePropsName in props.etape && isNotNullNorUndefined(props.etape.fondamentale.perimetre) && isNotNullNorUndefined(props.etape.fondamentale.perimetre.geojson4326_perimetre) ? (
        <DsfrPerimetre
          class="fr-pt-2w"
          initTab={props.initTab}
          titreSlug={props.titre.slug}
          titreTypeId={props.titre.typeId}
          id={props.etape.id}
          calculateNeighbours={false}
          perimetre={{
            geojson4326_perimetre: props.etape.fondamentale.perimetre.geojson4326_perimetre,
            geojson4326_points: props.etape.fondamentale.perimetre.geojson4326_points,
            geojson_origine_perimetre: props.etape.fondamentale.perimetre.geojson_origine_perimetre,
            geojson_origine_points: props.etape.fondamentale.perimetre.geojson_origine_points,
            geojson_origine_geo_systeme_id: props.etape.fondamentale.perimetre.geojson_origine_geo_systeme_id,
            geojson4326_forages: props.etape.fondamentale.perimetre.geojson4326_forages,
            geojson_origine_forages: props.etape.fondamentale.perimetre.geojson_origine_forages,
            surface: props.etape.fondamentale.perimetre.surface,
          }}
        />
      ) : null}
      <EtapeDocuments etapeDocuments={props.etape.etape_documents} entrepriseDocuments={props.etape.entreprises_documents} user={props.user} entreprises={props.entreprises} />
      <EtapeAvisTable etapeAvis={props.etape.avis_documents} user={props.user} />
      {removePopupVisible.value ? (
        <RemoveEtapePopup
          close={closeRemovePopup}
          apiClient={props.apiClient}
          demarcheTypeId={props.demarche.demarche_type_id}
          etapeTypeId={props.etape.etape_type_id}
          id={props.etape.id}
          titreTypeId={props.titre.typeId}
          titreNom={props.titre.nom}
        />
      ) : null}
      {deposePopupVisible.value ? <DeposeEtapePopup close={closeDeposePopup} deposeEtape={deposeEtape} etapeTypeId={props.etape.etape_type_id} /> : null}
    </div>
  )
})

const SectionElementInfo = (props: { element: ElementWithValue; sectionId: string; etapeDate: CaminoDate }) => {
  const info = getInfo(props.element, props.sectionId, props.etapeDate)
  if (isNotNullNorUndefinedNorEmpty(info)) {
    return <span class="fr-info-text fr-mt-0">{info}</span>
  }

  return null
}

// @ts-ignore waiting for https://github.com/vuejs/core/issues/7833
DemarcheEtape.props = ['demarche', 'titre', 'router', 'user', 'entreprises', 'etape', 'apiClient', 'initTab', 'currentDate']
