<?php

declare(strict_types=1);

namespace OCA\Mitgliederverwaltung\Tests\Unit;

use OCA\Mitgliederverwaltung\Db\PlatformHelper;
use OCP\IDBConnection;
use PHPUnit\Framework\TestCase;

/**
 * Unit tests for PlatformHelper — validates that the correct SQL
 * expression is generated for each database platform.
 *
 * Part of Issue #192.
 */
class PlatformHelperTest extends TestCase {

    private function createMockDb(string $platform): IDBConnection {
        $db = $this->createMock(IDBConnection::class);
        $db->method('getDatabaseProvider')->willReturn($platform);
        return $db;
    }

    // ── getYearDiffExpression ──────────────────────────────────────

    public function testYearDiffMySQL(): void {
        $db = $this->createMockDb(IDBConnection::PLATFORM_MYSQL);
        $expr = PlatformHelper::getYearDiffExpression($db, 'm.geburtsdatum');
        $this->assertStringContainsString('TIMESTAMPDIFF', $expr);
        $this->assertStringContainsString('CURDATE()', $expr);
        $this->assertStringContainsString('m.geburtsdatum', $expr);
    }

    public function testYearDiffPostgreSQL(): void {
        $db = $this->createMockDb(IDBConnection::PLATFORM_POSTGRES);
        $expr = PlatformHelper::getYearDiffExpression($db, 'm.geburtsdatum');
        $this->assertStringContainsString('EXTRACT', $expr);
        $this->assertStringContainsString('AGE', $expr);
        $this->assertStringContainsString('CURRENT_DATE', $expr);
        $this->assertStringContainsString('m.geburtsdatum', $expr);
    }

    public function testYearDiffSQLite(): void {
        $db = $this->createMockDb(IDBConnection::PLATFORM_SQLITE);
        $expr = PlatformHelper::getYearDiffExpression($db, 'm.geburtsdatum');
        $this->assertStringContainsString("strftime('%Y'", $expr);
        $this->assertStringContainsString('m.geburtsdatum', $expr);
        // SQLite expression should include the birthday correction
        $this->assertStringContainsString('CASE WHEN', $expr);
    }

    // ── getMonthExpression ─────────────────────────────────────────

    public function testMonthMySQL(): void {
        $db = $this->createMockDb(IDBConnection::PLATFORM_MYSQL);
        $expr = PlatformHelper::getMonthExpression($db, 'geburtsdatum');
        $this->assertEquals('MONTH(geburtsdatum)', $expr);
    }

    public function testMonthPostgreSQL(): void {
        $db = $this->createMockDb(IDBConnection::PLATFORM_POSTGRES);
        $expr = PlatformHelper::getMonthExpression($db, 'geburtsdatum');
        $this->assertStringContainsString('EXTRACT(MONTH FROM geburtsdatum)', $expr);
    }

    public function testMonthSQLite(): void {
        $db = $this->createMockDb(IDBConnection::PLATFORM_SQLITE);
        $expr = PlatformHelper::getMonthExpression($db, 'geburtsdatum');
        $this->assertStringContainsString("strftime('%m', geburtsdatum)", $expr);
    }

    // ── getYearExpression ──────────────────────────────────────────

    public function testYearMySQL(): void {
        $db = $this->createMockDb(IDBConnection::PLATFORM_MYSQL);
        $expr = PlatformHelper::getYearExpression($db, 'startdatum');
        $this->assertEquals('YEAR(startdatum)', $expr);
    }

    public function testYearPostgreSQL(): void {
        $db = $this->createMockDb(IDBConnection::PLATFORM_POSTGRES);
        $expr = PlatformHelper::getYearExpression($db, 'startdatum');
        $this->assertStringContainsString('EXTRACT(YEAR FROM startdatum)', $expr);
    }

    public function testYearSQLite(): void {
        $db = $this->createMockDb(IDBConnection::PLATFORM_SQLITE);
        $expr = PlatformHelper::getYearExpression($db, 'startdatum');
        $this->assertStringContainsString("strftime('%Y', startdatum)", $expr);
    }

    // ── Column reference pass-through ──────────────────────────────

    public function testColumnReferencePreservedInAllMethods(): void {
        $db = $this->createMockDb(IDBConnection::PLATFORM_MYSQL);
        $col = 'x.custom_col';

        $this->assertStringContainsString($col, PlatformHelper::getYearDiffExpression($db, $col));
        $this->assertStringContainsString($col, PlatformHelper::getMonthExpression($db, $col));
        $this->assertStringContainsString($col, PlatformHelper::getYearExpression($db, $col));
    }

    // ── All three platforms produce non-empty expressions ──────────

    /**
     * @dataProvider platformProvider
     */
    public function testAllPlatformsProduceNonEmptyExpressions(string $platform): void {
        $db = $this->createMockDb($platform);

        $this->assertNotEmpty(PlatformHelper::getYearDiffExpression($db, 'col'));
        $this->assertNotEmpty(PlatformHelper::getMonthExpression($db, 'col'));
        $this->assertNotEmpty(PlatformHelper::getYearExpression($db, 'col'));
    }

    public static function platformProvider(): array {
        return [
            'mysql' => [IDBConnection::PLATFORM_MYSQL],
            'postgres' => [IDBConnection::PLATFORM_POSTGRES],
            'sqlite' => [IDBConnection::PLATFORM_SQLITE],
        ];
    }
}
