import { BaseSchema } from '@adonisjs/lucid/schema'

/**
 * posts — articles du blog rubis.pro/blog
 *
 * SSR par AdonisJS (cf. apps/api/app/controllers/blog_controller.ts), routé
 * via Traefik Host(`rubis.pro`) && PathPrefix(`/blog`) → service rubis-api.
 * Le même pod Adonis sert /api/v1/* (host app.rubis.pro) et /blog/* (host
 * rubis.pro), distingués au niveau du routeur Adonis.
 *
 * Champs SEO :
 *  - slug : segment d'URL stable, unique
 *  - title : <title> + og:title + JSON-LD headline (≤60 chars validé côté admin)
 *  - excerpt : meta description + og:description + card preview (≤160 chars)
 *  - content_md : markdown source (édité dans l'admin)
 *  - content_html : rendu cache au save pour éviter le coût marked à chaque hit
 *  - hero_image_url : visuel d'en-tête, sert aussi de og:image par défaut
 *  - og_image_url : OG dédié si on veut un crop différent (sinon = hero)
 *  - canonical_url : pour cross-posting éventuel (sinon défaut = rubis.pro/blog/{slug})
 *  - tags : pour articles liés (recherche par tag commun) + filtres future
 *  - published_at : timestamp de publication (NULL tant que draft)
 *  - reading_time_minutes / word_count : calculés au save, affichés dans l'UI
 *  - ai_generated : flag pour distinguer les drafts générés par le cron weekly
 *  - noindex : permet de cacher un article aux crawlers (legal/test)
 */
export default class extends BaseSchema {
  protected tableName = 'posts'

  async up() {
    this.schema.createTable(this.tableName, (table) => {
      table.uuid('id').primary().notNullable().defaultTo(this.raw('gen_random_uuid()'))

      // Clés SEO
      table.string('slug', 200).notNullable().unique()
      table.string('title', 200).notNullable()
      table.string('excerpt', 280).notNullable()

      // Contenu
      table.text('content_md').notNullable()
      table.text('content_html').notNullable()

      // Visuels
      table.string('hero_image_url', 500).nullable()
      table.string('hero_image_alt', 250).nullable()
      table.string('og_image_url', 500).nullable()

      // Métadonnées éditoriales
      table.string('author_name', 100).notNullable().defaultTo('Arthur Barré')
      table.specificType('tags', 'text[]').notNullable().defaultTo('{}')

      // État + publication
      table
        .enum('status', ['draft', 'published'], {
          useNative: true,
          enumName: 'post_status',
        })
        .notNullable()
        .defaultTo('draft')
      table.timestamp('published_at', { useTz: true }).nullable()

      // Calculé au save
      table.integer('reading_time_minutes').notNullable().defaultTo(0)
      table.integer('word_count').notNullable().defaultTo(0)

      // SEO advanced
      table.string('canonical_url', 500).nullable()
      table.boolean('noindex').notNullable().defaultTo(false)

      // Pipeline IA (PR4) — pas de FK pour l'instant, table blog_topics arrive plus tard
      table.boolean('ai_generated').notNullable().defaultTo(false)
      table.uuid('ai_topic_id').nullable()

      table.timestamp('created_at', { useTz: true }).notNullable().defaultTo(this.now())
      table.timestamp('updated_at', { useTz: true }).nullable()

      // Index : la requête publique principale = WHERE status='published' ORDER BY published_at DESC.
      // Partial index pour ne pas peser sur les drafts (qui ne seront jamais listés publiquement).
      table.index(['status', 'published_at'], 'posts_published_idx')
      // Recherche par tag : GIN sur le tableau text[] pour les requêtes "articles liés".
      this.schema.raw('CREATE INDEX posts_tags_gin_idx ON posts USING GIN (tags)')
    })
  }

  async down() {
    this.schema.raw('DROP INDEX IF EXISTS posts_tags_gin_idx')
    this.schema.dropTable(this.tableName)
    this.schema.raw('DROP TYPE IF EXISTS post_status')
  }
}
