import mysql from 'mysql2/promise';

const host = process.env.MYSQL_HOST || '127.0.0.1';
const port = parseInt(process.env.MYSQL_PORT || '3306', 10);
const user = process.env.MYSQL_USER || 'root';
const password = process.env.MYSQL_PASSWORD || '';

let pool: mysql.Pool | null = null;

async function ensureColumn(
  db: mysql.PoolConnection,
  tableName: string,
  columnName: string,
  definition: string
): Promise<void> {
  const [rows] = await db.execute<mysql.RowDataPacket[]>(
    `SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS
     WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ?`,
    [tableName, columnName]
  );
  if (Array.isArray(rows) && rows.length > 0) return;
  await db.execute(`ALTER TABLE \`${tableName}\` ADD COLUMN \`${columnName}\` ${definition}`);
}

async function ensureIndex(
  db: mysql.PoolConnection,
  tableName: string,
  indexName: string,
  definition: string
): Promise<void> {
  const [rows] = await db.execute<mysql.RowDataPacket[]>(
    `SELECT INDEX_NAME FROM INFORMATION_SCHEMA.STATISTICS
     WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND INDEX_NAME = ?`,
    [tableName, indexName]
  );
  if (Array.isArray(rows) && rows.length > 0) return;
  await db.execute(`ALTER TABLE \`${tableName}\` ADD ${definition}`);
}

export function getPool(): mysql.Pool {
  if (!pool) {
    throw new Error('Database pool not initialized. Call initDatabase() first.');
  }
  return pool;
}

export function isPoolReady(): boolean {
  return pool !== null;
}

export async function initDatabase(): Promise<void> {
  // Create database if it doesn't exist
  const tmpConn = await mysql.createConnection({ host, port, user, password });
  await tmpConn.execute('CREATE DATABASE IF NOT EXISTS hermes_oauth');
  await tmpConn.end();

  pool = mysql.createPool({
    host,
    port,
    user,
    password,
    database: 'hermes_oauth',
    waitForConnections: true,
    connectionLimit: 10,
    queueLimit: 0,
    timezone: 'Z',
  });

  const db = await pool.getConnection();
  try {
    await db.execute(`
      CREATE TABLE IF NOT EXISTS oauth_clients (
        client_id VARCHAR(255) PRIMARY KEY,
        client_secret VARCHAR(255) NOT NULL,
        client_name VARCHAR(255),
        redirect_urls JSON,
        grant_types JSON,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        last_used TIMESTAMP NULL,
        is_static BOOLEAN DEFAULT FALSE,
        INDEX idx_last_used (last_used)
      )
    `);

    await db.execute(`
      CREATE TABLE IF NOT EXISTS oauth_auth_codes (
        code VARCHAR(255) PRIMARY KEY,
        client_id VARCHAR(255),
        redirect_uri TEXT,
        scope TEXT NULL,
        code_challenge TEXT NULL,
        code_challenge_method VARCHAR(20) NULL,
        expires_at TIMESTAMP,
        used BOOLEAN DEFAULT FALSE,
        INDEX idx_expires (expires_at)
      )
    `);

    await ensureColumn(db, 'oauth_auth_codes', 'scope', 'TEXT NULL');
    await ensureColumn(db, 'oauth_auth_codes', 'code_challenge', 'TEXT NULL');
    await ensureColumn(db, 'oauth_auth_codes', 'code_challenge_method', 'VARCHAR(20) NULL');
    await ensureColumn(db, 'oauth_auth_codes', 'customer_id', 'VARCHAR(255) NULL');
    await ensureColumn(db, 'oauth_tokens', 'customer_id', 'VARCHAR(255) NULL');
    await ensureColumn(db, 'customers', 'password_hash', 'VARCHAR(255) NULL');
    await ensureColumn(db, 'customers', 'webhook_url', 'VARCHAR(512) NULL');
    await ensureColumn(db, 'customers', 'webhook_secret', 'VARCHAR(64) NULL');

    await db.execute(`
      CREATE TABLE IF NOT EXISTS oauth_tokens (
        token VARCHAR(255) PRIMARY KEY,
        client_id VARCHAR(255),
        token_type ENUM('access', 'refresh') DEFAULT 'access',
        expires_at TIMESTAMP,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        INDEX idx_expires (expires_at)
      )
    `);

    await db.execute(`
      CREATE TABLE IF NOT EXISTS customers (
        id VARCHAR(255) PRIMARY KEY,
        api_key VARCHAR(255) NOT NULL UNIQUE,
        plan ENUM('free', 'starter', 'growth', 'enterprise') DEFAULT 'free',
        active BOOLEAN DEFAULT TRUE,
        email VARCHAR(255) NOT NULL,
        password_hash VARCHAR(255) NULL,
        role ENUM('user', 'admin') DEFAULT 'user',
        reset_token VARCHAR(255) NULL,
        reset_expires_at TIMESTAMP NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        INDEX idx_api_key (api_key),
        INDEX idx_email (email),
        INDEX idx_reset_token (reset_token)
      )
    `);

    await db.execute(`
      CREATE TABLE IF NOT EXISTS usage_logs (
        id INT AUTO_INCREMENT PRIMARY KEY,
        customer_id VARCHAR(255) NOT NULL,
        platform VARCHAR(32) NOT NULL,
        action VARCHAR(64) NOT NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        INDEX idx_customer_time (customer_id, created_at)
      )
    `);

    await db.execute(`
      CREATE TABLE IF NOT EXISTS invoices (
        id INT AUTO_INCREMENT PRIMARY KEY,
        customer_id VARCHAR(255) NOT NULL,
        invoice_number VARCHAR(64) NOT NULL UNIQUE,
        amount DECIMAL(10,2) NOT NULL,
        currency VARCHAR(3) DEFAULT 'USD',
        status ENUM('draft', 'sent', 'paid', 'overdue') DEFAULT 'draft',
        period_start DATE NOT NULL,
        period_end DATE NOT NULL,
        line_items JSON,
        sent_at TIMESTAMP NULL,
        paid_at TIMESTAMP NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        INDEX idx_customer (customer_id),
        INDEX idx_status (status)
      )
    `);

    await db.execute(`
      CREATE TABLE IF NOT EXISTS tracking_links (
        token           VARCHAR(32) PRIMARY KEY,
        customer_id     VARCHAR(255) NOT NULL,
        draft_id        INT NULL,
        destination_url VARCHAR(2048) NOT NULL,
        click_count     BIGINT UNSIGNED NOT NULL DEFAULT 0,
        expires_at      TIMESTAMP NULL,
        created_at      TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        INDEX idx_customer_created (customer_id, created_at),
        INDEX idx_draft (draft_id)
      )
    `);

    await db.execute(`
      CREATE TABLE IF NOT EXISTS post_drafts (
        id                INT AUTO_INCREMENT PRIMARY KEY,
        tenant_id         VARCHAR(255) NOT NULL,
        draft_text_social TEXT NOT NULL,
        draft_text_wa     TEXT NOT NULL,
        destination_url   VARCHAR(512) NULL,
        utm_token         VARCHAR(32) NULL,
        status            ENUM('pending','approved','rejected','expired','publish_error') DEFAULT 'pending',
        created_at        TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        approved_at       TIMESTAMP NULL,
        INDEX idx_tenant_status (tenant_id, status),
        INDEX idx_tenant_created (tenant_id, created_at)
      )
    `);

    // Ensure new columns on existing customers table
    await ensureColumn(db, 'customers', 'role', "ENUM('user','admin') DEFAULT 'user'");
    await ensureColumn(db, 'customers', 'reset_token', 'VARCHAR(255) NULL');
    await ensureColumn(db, 'customers', 'reset_expires_at', 'TIMESTAMP NULL');
    await ensureColumn(db, 'customers', 'pilot_active', 'TINYINT(1) DEFAULT 0');
    await ensureColumn(db, 'customers', 'pilot_paused', 'TINYINT(1) DEFAULT 0');
    await ensureColumn(db, 'customers', 'pilot_end_date', 'DATE NULL');
    await ensureColumn(db, 'customers', 'pilot_owner_phone', 'VARCHAR(32) NULL');
    await ensureColumn(db, 'customers', 'industry', 'VARCHAR(128) NULL');
    await ensureColumn(db, 'customers', 'location', 'VARCHAR(128) NULL');

    // Remove duplicate (customer_id, period_start) rows before adding unique constraint
    // Keeps the earliest invoice (lowest id) for each customer+period pair
    await db.execute(`
      DELETE i1 FROM invoices i1
      INNER JOIN invoices i2
        ON i1.customer_id = i2.customer_id
       AND i1.period_start = i2.period_start
       AND i1.id > i2.id
    `);
    await ensureIndex(db, 'invoices', 'uq_customer_period',
      'UNIQUE KEY uq_customer_period (customer_id, period_start)');
  } finally {
    db.release();
  }

  console.log('[db] MySQL connected and schema initialized');
}
