import { TablePagination, getInitialParams } from '../_ui/table-pagination'
import { Filtres } from './filtres'
import { Column, TableRow } from '../_ui/table'
import { PageContentHeader, type Props as PageContentHeaderProps } from './page-header-content'
import { computed, defineComponent, onMounted, ref, Ref } from 'vue'
import { z } from 'zod'
import { getInitialFiltres } from '../_ui/filters/filters'
import { CaminoFiltre, caminoFiltres } from 'camino-common/src/filters'
import { ApiClient } from '../../api/api-client'
import { AsyncData } from '../../api/client-rest'
import { Entreprise } from 'camino-common/src/entreprise'
import { CaminoRouteLocation } from '@/router/routes'
import { CaminoRouter } from '@/typings/vue-router'
import { PageWithFilters } from './page-with-filters'
import { CaminoError } from 'camino-common/src/zod-tools'

export type Params<ColumnId extends string> = {
  colonne: ColumnId
  ordre: 'asc' | 'desc'
  page: number
  filtres?: { [key in CaminoFiltre]: z.infer<(typeof caminoFiltres)[key]['validator']> }
}

type ListeFiltreProps = {
  filtres: readonly CaminoFiltre[]
  updateUrlQuery: Pick<CaminoRouter, 'push'>
  apiClient: Pick<ApiClient, 'titresRechercherByNom' | 'getTitresByIds'>
  entreprises: Entreprise[]
}

type GetColumnId<ColumnWithId> = ColumnWithId extends { id: infer Id } ? Id : never

type ToColumnId<List> = List extends [infer First, ...infer Rest] ? (First extends { noSort: true } ? ToColumnId<Rest> : [GetColumnId<First>, ...ToColumnId<Rest>]) : []

type Props<ColumnId extends string, Columns> = {
  listeFiltre: ListeFiltreProps
  colonnes: Readonly<Columns>
  getData: (params: Params<ToColumnId<Columns>[number]>) => Promise<{ values: TableRow<ColumnId>[]; total: number } | CaminoError<string>>
  route: CaminoRouteLocation
} & PageContentHeaderProps

export const Liste = defineComponent(<ColumnId extends string, Columns extends Column<ColumnId>[]>(props: Props<ColumnId, Columns>) => {
  const initialParams = getInitialParams(props.route, props.colonnes)
  const params = ref<Params<ColumnId>>({
    ...initialParams,
  }) as Ref<Params<ColumnId>>

  params.value.filtres = getInitialFiltres(props.route, props.listeFiltre?.filtres)

  const paramsTableUpdate = (newParams: { page: number; colonne: ColumnId; ordre: 'asc' | 'desc' }) => {
    if (newParams.page !== params.value.page || newParams.colonne !== params.value.colonne || newParams.ordre !== params.value.ordre) {
      params.value.page = newParams.page
      params.value.colonne = newParams.colonne
      params.value.ordre = newParams.ordre
      getData(params.value)
    }
  }

  const tableData = ref<AsyncData<{ rows: TableRow[]; total: number }>>({ status: 'LOADING' })

  const getData = async (params: Params<ColumnId>) => {
    tableData.value = { status: 'LOADING' }
    try {
      const loaded = await props.getData(params)
      if ('message' in loaded) {
        tableData.value = { status: 'NEW_ERROR', error: loaded }
      } else {
        tableData.value = { status: 'LOADED', value: { rows: loaded.values, total: loaded.total } }
      }
    } catch (e: any) {
      console.error('error', e)
      tableData.value = {
        status: 'ERROR',
        message: e.message ?? "Une erreur s'est produite",
      }
    }
  }
  onMounted(async () => {
    await getData(params.value)
  })

  const paramsFiltresUpdate = (filtres: Params<ColumnId>['filtres']) => {
    if (JSON.stringify(params.value.filtres) !== JSON.stringify(filtres)) {
      params.value.filtres = filtres
      params.value.page = 1
      getData(params.value)
    }
  }

  const resultat = computed<string>(() => {
    if (tableData.value.status !== 'LOADED') {
      return '...'
    } else {
      const res = tableData.value.value.total > tableData.value.value.rows.length ? `${tableData.value.value.rows.length} / ${tableData.value.value.total}` : tableData.value.value.rows.length

      return `(${res} résultat${tableData.value.value.rows.length > 1 ? 's' : ''})`
    }
  })

  return () => (
    <PageWithFilters
      content={
        <>
          <PageContentHeader nom={props.nom} download={props.download} renderButton={props.renderButton} />

          <TablePagination data={tableData.value} columns={props.colonnes} caption={{ value: props.nom, visible: false }} route={props.route} updateParams={paramsTableUpdate} />
        </>
      }
      filtres={
        <Filtres
          updateUrlQuery={props.listeFiltre.updateUrlQuery}
          route={props.route}
          filters={props.listeFiltre.filtres}
          subtitle={resultat.value}
          apiClient={props.listeFiltre.apiClient}
          entreprises={props.listeFiltre.entreprises}
          paramsUpdate={paramsFiltresUpdate}
        />
      }
    />
  )
})

// @ts-ignore waiting for https://github.com/vuejs/core/issues/7833
Liste.props = ['colonnes', 'download', 'listeFiltre', 'nom', 'renderButton', 'route', 'updateUrlQuery', 'getData']
