import type { FastifyInstance } from 'fastify'

/**
 * Locales API Routes
 */
async function routes(app: FastifyInstance) {
  app.get(
    '/',
    {
      config: {
        publicAccess: true
      },
      schema: {
        summary: 'List all locales',
        description:
          'Every locale this wiki knows of, installed or merely published upstream, named and coded as this wiki refers to them.',
        tags: ['Locales'],
        response: {
          200: {
            description: 'The locale list',
            type: 'array',
            items: { $ref: 'Locale#' }
          }
        }
      }
    },
    async () => {
      return WIKI.models.locales.getLocales()
    }
  )

  /**
   * FETCH LOCALES FROM UPSTREAM
   *
   * Runs the update to completion rather than queueing it, because the caller is a dialog waiting
   * for a count to show. It is the same work the nightly `updateLocales` job does, and cheap for the
   * same reason: the metadata is one small document, and only an installed locale whose hash moved
   * is actually downloaded.
   */
  app.post(
    '/fetch',
    {
      config: {
        permissions: ['manage:system']
      },
      schema: {
        summary: 'Fetch the latest locales from the Wiki.js repository',
        description:
          "Reads the published locale metadata and records any locale not seen before as available. An installed locale is re-downloaded only when its published hash differs from the one stored, so a run that finds nothing new costs a single request.\n\n`en` is never fetched: it is the locale the interface is written in and ships with the wiki, loaded from `locales/en.json` on every boot. It counts as unchanged.",
        tags: ['Locales'],
        response: {
          200: {
            description: 'Locales fetched successfully',
            type: 'object',
            properties: {
              ok: { type: 'boolean' },
              added: {
                type: 'integer',
                description: 'Locales newly available, whose strings were not downloaded.'
              },
              updated: {
                type: 'integer',
                description: 'Installed locales whose strings changed upstream and were refreshed.'
              },
              unchanged: { type: 'integer' },
              failed: { type: 'integer' }
            }
          }
        }
      }
    },
    async () => {
      return { ok: true, ...(await WIKI.models.locales.updateFromRemote()) }
    }
  )

  /**
   * INSTALL A LOCALE
   */
  app.post<{ Params: { code: string } }>(
    '/:code/install',
    {
      config: {
        permissions: ['manage:system']
      },
      schema: {
        summary: 'Download the strings of an available locale',
        description:
          "Downloads the published strings file for a locale that has a row but no strings, making it installable on a site. Fetch the locale list first: a locale nobody has heard of yet has no row to install.\n\nRefused for `en`, which ships with the wiki and is always installed.",
        tags: ['Locales'],
        params: {
          type: 'object',
          properties: {
            code: { type: 'string', description: 'The locale code, e.g. `fr-FR`.' }
          }
        },
        response: {
          200: {
            description: 'Locale installed successfully',
            type: 'object',
            properties: {
              ok: { type: 'boolean' },
              message: { type: 'string' }
            }
          }
        }
      }
    },
    async (req, reply) => {
      try {
        await WIKI.models.locales.install(req.params.code)
      } catch (err: any) {
        return reply.badRequest(err.message)
      }
      return { ok: true, message: 'Locale installed successfully.' }
    }
  )

  /**
   * SET A LOCALE'S ALIASES
   */
  app.put<{
    Params: { code: string }
    Body: { customName?: string | null; customCode?: string | null }
  }>(
    '/:code/aliases',
    {
      config: {
        permissions: ['manage:system']
      },
      schema: {
        summary: 'Set what a locale is called and addressed as',
        description:
          'Overrides the name and the short code derived from the language tag — `zh` for `zh-CN`. The locale is still identified everywhere by its `code`, so nothing already recorded against it moves. An empty value puts the derived form back, and so does the derived form itself.',
        tags: ['Locales'],
        params: {
          type: 'object',
          properties: {
            code: { type: 'string', description: 'The locale code, e.g. `zh-CN`.' }
          }
        },
        body: {
          type: 'object',
          properties: {
            customName: {
              type: ['string', 'null'],
              maxLength: 255,
              description: 'The name to show, or empty to go back to the derived one.'
            },
            customCode: {
              type: ['string', 'null'],
              maxLength: 255,
              description: 'The short code to show, or empty to go back to the derived one.'
            }
          }
        },
        response: {
          200: {
            description: 'Aliases updated successfully',
            type: 'object',
            properties: {
              ok: { type: 'boolean' },
              message: { type: 'string' }
            }
          }
        }
      }
    },
    async (req, reply) => {
      try {
        await WIKI.models.locales.setAliases(req.params.code, {
          customName: req.body?.customName ?? null,
          customCode: req.body?.customCode ?? null
        })
      } catch (err: any) {
        return reply.badRequest(err.message)
      }
      return { ok: true, message: 'Aliases updated successfully.' }
    }
  )

  app.get<{ Params: { code: string } }>(
    '/:code/strings',
    {
      config: {
        publicAccess: true
      },
      schema: {
        summary: 'Get locale strings',
        tags: ['Locales']
      }
    },
    async (req) => {
      return WIKI.models.locales.getStrings(req.params.code)
    }
  )
}

export default routes
