<?php
/**
 * HasSchema trait
 *
 * @package KimaAI
 * @since 1.1.0
 */

declare(strict_types=1);

namespace KimaAI\Models;

use ReflectionClass;
use wpdb;

defined('ABSPATH') || exit;

/**
 * HasSchema trait
 *
 * Models must define:
 * - public const TABLE
 * - public const PRIMARY_KEY
 * - public const COLUMNS (columns only; BUT we also tolerate index definitions for backward compatibility)
 * - public const INDEXES (optional) array of strings like "KEY foo_idx (foo)"
 */
trait HasSchema {

  /**
   * Builds the full CREATE TABLE statement for the model
   * (prefix included, ready for dbDelta).
   */
  public static function createTableSql(wpdb $wpdb): string {
    $ref = new ReflectionClass(static::class);

    $table = $wpdb->prefix . (string) $ref->getConstant('TABLE');
    $columns = (array) $ref->getConstant('COLUMNS');
    $pk = (string) $ref->getConstant('PRIMARY_KEY');

    $table_options = trim((string) $wpdb->get_charset_collate());
    // dbDelta accepts ENGINE in CREATE TABLE statement.
    $table_options .= ' ENGINE=InnoDB';

    $lines = [];

    // Backward-compatible parsing:
    // - If keys inside COLUMNS look like "KEY ..." or "UNIQUE KEY ..." we treat them as index lines.
    foreach ($columns as $name => $definition) {
      $name = (string) $name;
      $definition = trim((string) $definition);

      // Numeric keys -> assume $definition already contains a full column or index line
      if (is_int($name)) {
        if ($definition !== '') {
          $lines[] = $definition;
        }
        continue;
      }

      // If someone put index definitions in COLUMNS like:
      // 'KEY idx_post' => '(post_id)'  => produce: "KEY idx_post (post_id)"
      // or 'UNIQUE KEY ...' => '(...)'
      if (preg_match('/^(PRIMARY KEY|UNIQUE KEY|KEY|FULLTEXT KEY|SPATIAL KEY)\b/i', $name)) {
        $lines[] = trim($name . ' ' . $definition);
        continue;
      }

      // Normal column line: "col_name TYPE ..."
      $lines[] = trim($name . ' ' . $definition);
    }

    // Ensure PK exists exactly once.
    $has_pk = false;
    foreach ($lines as $line) {
      if (stripos($line, 'PRIMARY KEY') === 0) {
        $has_pk = true;
        break;
      }
    }
    if (!$has_pk) {
      $lines[] = "PRIMARY KEY ({$pk})";
    }

    // INDEXES constant (preferred)
    if ($ref->hasConstant('INDEXES')) {
      $indexes = $ref->getConstant('INDEXES');
      if (is_array($indexes)) {
        foreach ($indexes as $index_line) {
          $index_line = trim((string) $index_line);
          if ($index_line !== '') {
            $lines[] = $index_line;
          }
        }
      }
    }

    return sprintf(
      "CREATE TABLE IF NOT EXISTS %s (\n  %s\n) %s;",
      $table,
      implode(",\n  ", $lines),
      $table_options
    );
  }
}
