<?php
declare(strict_types=1);

namespace Apexl\Vault\Tests;

use Apexl\Vault\Operators\Drivers\MySql;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use stdClass;

/**
 * Builder-level coverage for the insert()/upsert() split introduced with
 * the ERRMODE_EXCEPTION fix. No database needed — the mysql driver
 * connects lazily, so we can construct it, build a query, and inspect the
 * generated SQL via the public $query object.
 *
 * The contract under test:
 *  - insert() emits a PLAIN insert. Historically fieldsForInsert()
 *    unconditionally attached `ON DUPLICATE KEY UPDATE col = VALUES(col)`
 *    for every column, silently turning key collisions into full-row
 *    upserts at the SQL level (so not even ERRMODE_EXCEPTION could
 *    surface them).
 *  - upsert() is the explicit opt-in for merge-on-conflict, defaulting to
 *    all inserted columns, or a caller-supplied subset.
 */
final class MysqlInsertBuilderTest extends TestCase
{
    private function driver(): MySql
    {
        $cfg = new stdClass();
        $cfg->driver = 'mysql';
        $cfg->dbhost = 'localhost';
        $cfg->dbname = 'unused';
        $cfg->dbuser = 'unused';
        $cfg->dbpass = 'unused';

        return new MySql($cfg);
    }

    #[Test]
    public function plain_insert_has_no_on_duplicate_key_update_clause(): void
    {
        $drv = $this->driver();
        $drv->insert('widgets')->fields(['name' => 'a', 'slug' => 'b']);

        $sql = $drv->query->getStatement();

        self::assertStringContainsString('INSERT INTO', $sql);
        self::assertStringNotContainsString('ON DUPLICATE KEY UPDATE', $sql);
    }

    #[Test]
    public function upsert_defaults_to_updating_every_inserted_column(): void
    {
        $drv = $this->driver();
        $drv->upsert('widgets')->fields(['name' => 'a', 'slug' => 'b']);

        $sql = $drv->query->getStatement();

        self::assertStringContainsString('ON DUPLICATE KEY UPDATE', $sql);
        self::assertStringContainsString('VALUES(`name`)', $sql);
        self::assertStringContainsString('VALUES(`slug`)', $sql);
    }

    #[Test]
    public function upsert_with_subset_only_updates_named_columns(): void
    {
        $drv = $this->driver();
        $drv->upsert('widgets', ['name'])->fields(['name' => 'a', 'slug' => 'b']);

        $sql = $drv->query->getStatement();

        self::assertStringContainsString('ON DUPLICATE KEY UPDATE', $sql);
        self::assertStringContainsString('VALUES(`name`)', $sql);
        self::assertStringNotContainsString('slug', substr($sql, strpos($sql, 'ON DUPLICATE KEY UPDATE')));
    }

    /**
     * Reserved-word columns (`key`, `condition`, ...) must be backticked
     * inside VALUES() — the raw form is a MySQL 1064 syntax error, which
     * broke every upsert on tables with a `key` column (e.g. settings).
     */
    #[Test]
    public function upsert_backticks_reserved_word_columns_in_values_refs(): void
    {
        $drv = $this->driver();
        $drv->upsert('settings')->fields(['key' => 'a.b', 'value' => '1']);

        $sql = $drv->query->getStatement();

        self::assertStringContainsString('VALUES(`key`)', $sql);
        self::assertStringContainsString('VALUES(`value`)', $sql);
        self::assertStringNotContainsString('VALUES(key)', $sql);
    }

    #[Test]
    public function insert_after_upsert_clears_the_upsert_state(): void
    {
        $drv = $this->driver();
        $drv->upsert('widgets')->fields(['name' => 'a']);
        $drv->insert('widgets')->fields(['name' => 'a']);

        self::assertStringNotContainsString(
            'ON DUPLICATE KEY UPDATE',
            $drv->query->getStatement()
        );
    }

    #[Test]
    public function new_query_does_not_inherit_upsert_state(): void
    {
        $drv = $this->driver();
        $drv->upsert('widgets');

        $fresh = $drv->newQuery();
        $fresh->insert('widgets')->fields(['name' => 'a']);

        self::assertStringNotContainsString(
            'ON DUPLICATE KEY UPDATE',
            $fresh->query->getStatement()
        );
    }
}
