import { type Plugin } from '@hapi/hapi'
import { type ServerYar, type Yar } from '@hapi/yar'
import { type Logger } from 'pino'

import {
  type COMPONENT_STATE_ERROR,
  type EXTERNAL_STATE_APPENDAGE,
  type EXTERNAL_STATE_PAYLOAD
} from '../../server/constants.js'
import { type FormModel } from '../../server/plugins/engine/models/index.js'
import {
  type AnyFormRequest,
  type FormSubmissionError,
  type PluginOptions
} from '../../server/plugins/engine/types.ts'
import { type CacheService } from '../../server/services/index.js'

declare module '@hapi/yar' {
  interface YarFlashes {
    [EXTERNAL_STATE_APPENDAGE]: object
    [EXTERNAL_STATE_PAYLOAD]: object
    [COMPONENT_STATE_ERROR]: string
    [key: string]: { errors: FormSubmissionError[] }
  }
}

declare module '@hapi/hapi' {
  // Here we are decorating Hapi interface types with
  // props from plugins which doesn't export @types
  interface PluginProperties {
    crumb: {
      generate?: (request: AnyRequest) => string
    }
    'forms-engine-plugin': {
      baseLayoutPath: string
      cacheService: CacheService
      viewContext?: (
        request: AnyFormRequest | null
      ) => Record<string, unknown> | Promise<Record<string, unknown>>
      saveAndExit?: PluginOptions['saveAndExit']
      baseUrl: string
      services: PluginOptions['services']
    }
  }

  interface Request {
    logger: Logger
    yar: Yar
  }

  interface RequestApplicationState {
    model?: FormModel
  }

  interface Server {
    logger: Logger
    yar: ServerYar
  }

  interface ServerApplicationState {
    model?: FormModel
    models?: Map<string, { model: FormModel; updatedAt: Date }>
  }
}

declare module 'blankie' {
  declare const blankie: {
    plugin: Plugin<Record<string, boolean | string | string[]>>
  }

  export = blankie
}

declare module 'blipp' {
  declare const blipp: {
    plugin: Plugin
  }

  export = blipp
}

declare module 'hapi-pulse' {
  declare const hapiPulse: {
    plugin: Plugin<{
      timeout: number
    }>
  }

  export = hapiPulse
}
