<?php

declare(strict_types=1);

require_once dirname(__DIR__, 2) . '/feca_mailshots_plugin/src/autoload.php';

use FecaMailshots\Application\DataSourceService;
use FecaMailshots\Application\DslCompiler;
use FecaMailshots\Application\DslValidator;
use FecaMailshots\Domain\DslParser;
use FecaMailshots\Infrastructure\DatabaseSourceMetadataProvider;
use FecaMailshots\Infrastructure\Env;
use FecaMailshots\Infrastructure\PdoDatabaseRouter;
use FecaMailshots\Repository\MailshotRepository;
use FecaMailshots\Repository\MailshotQueryRepository;

Env::load(dirname(__DIR__, 2) . '/credentials/.env');

$host = getenv('MYSQL_TUNNEL_HOST');
if ($host === false || $host === '') {
    $host = '127.0.0.1';
}

$port = getenv('MYSQL_TUNNEL_LOCAL_PORT');
if ($port === false || $port === '') {
    $port = '13306';
}

$dbConfig = [
    'MYSQL_HOST' => (string) $host,
    'MYSQL_PORT' => (string) $port,
    'MYSQL_USER' => Env::require('REMOTE_MYSQL_USER'),
    'MYSQL_PASSWORD' => Env::require('REMOTE_MYSQL_PASSWORD'),
    'MAILSHOTS_REMOTE_MYSQL_DB' => Env::require('MAILSHOTS_REMOTE_MYSQL_DB'),
    'MEMBERS_REMOTE_MYSQL_DB' => Env::require('MEMBERS_REMOTE_MYSQL_DB'),
    'FEN_REMOTE_MYSQL_DB' => Env::require('FEN_REMOTE_MYSQL_DB'),
];

$router = new PdoDatabaseRouter($dbConfig);
$metadata = new DatabaseSourceMetadataProvider($router);
$parser = new DslParser();
$validator = new DslValidator($metadata);
$compiler = new DslCompiler($metadata);
$queries = new MailshotQueryRepository($router);
$mailshots = new MailshotRepository($router);
$service = new DataSourceService($queries, $router, $parser, $validator, $compiler, $metadata, $mailshots);

$membersDb = $router->membersDbName();
$mailshotsDb = $router->mailshotsDbName();

$stmt = $router->membersPdo()->prepare(
    'SELECT table_name FROM information_schema.tables WHERE table_schema = :schema AND table_name REGEXP :rx ORDER BY table_name ASC LIMIT 1'
);
$stmt->execute(['schema' => $membersDb, 'rx' => '^[A-Za-z][A-Za-z0-9_]*$']);
$firstTable = $stmt->fetchColumn();

if ($firstTable === false || $firstTable === null || $firstTable === '') {
    fwrite(STDERR, "No usable tables found in MEMBERS db for integration preview test.\n");
    exit(1);
}

$source = $membersDb . '.' . $firstTable;
$dsl = $source;

$validation = $service->validateDsl($dsl);
if (($validation['errors'] ?? []) !== []) {
    fwrite(STDERR, "Validation failed for source {$source}: " . json_encode($validation['errors']) . "\n");
    exit(1);
}

$preview = $service->preview($dsl, 5);
if (($preview['errors'] ?? []) !== []) {
    fwrite(STDERR, "Preview failed for source {$source}: " . json_encode($preview['errors']) . "\n");
    exit(1);
}

if (!isset($preview['count']) || !is_int($preview['count'])) {
    fwrite(STDERR, "Preview response missing integer count.\n");
    exit(1);
}

if (!isset($preview['columns']) || !is_array($preview['columns'])) {
    fwrite(STDERR, "Preview response missing columns array.\n");
    exit(1);
}

$name = 'phase2_db_access_' . gmdate('Ymd_His') . '_' . bin2hex(random_bytes(3));
$savedId = null;

try {
    $save = $service->save(null, $name, $dsl);
    if (($save['ok'] ?? false) !== true) {
        fwrite(STDERR, "Save failed: " . json_encode($save) . "\n");
        exit(1);
    }

    $savedId = (int) ($save['id'] ?? 0);
    if ($savedId <= 0) {
        fwrite(STDERR, "Save did not return a valid ID.\n");
        exit(1);
    }

    $row = $queries->find($savedId);
    if ($row === null) {
        fwrite(STDERR, "Saved mailshot_queries row not found for ID {$savedId}.\n");
        exit(1);
    }

    if (($row['name'] ?? '') !== $name || trim((string) ($row['dsl_text'] ?? '')) !== $dsl) {
        fwrite(STDERR, "Saved row contents mismatch for ID {$savedId}.\n");
        exit(1);
    }

    $service->delete($savedId);
    $savedId = null;

    echo "Phase 2 DB integration test passed\n";
    echo "members_db={$membersDb}\n";
    echo "mailshots_db={$mailshotsDb}\n";
    echo "preview_source={$source}\n";
    echo "preview_count=" . $preview['count'] . "\n";
} finally {
    if ($savedId !== null) {
        try {
            $service->delete($savedId);
        } catch (Throwable $e) {
            fwrite(STDERR, "Cleanup warning for ID {$savedId}: {$e->getMessage()}\n");
        }
    }
}
