<?php

declare(strict_types=1);

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

use FecaMailshots\Application\AttachmentService;
use FecaMailshots\Application\DataSourceService;
use FecaMailshots\Application\DslCompiler;
use FecaMailshots\Application\DslValidator;
use FecaMailshots\Application\MailshotService;
use FecaMailshots\Application\PdfAssetService;
use FecaMailshots\Domain\DslParser;
use FecaMailshots\Infrastructure\DatabaseSourceMetadataProvider;
use FecaMailshots\Infrastructure\Env;
use FecaMailshots\Infrastructure\PdoDatabaseRouter;
use FecaMailshots\Repository\AttachmentRepository;
use FecaMailshots\Repository\LastRunRepository;
use FecaMailshots\Repository\MailshotQueryRepository;
use FecaMailshots\Repository\MailshotRepository;
use FecaMailshots\Repository\PdfAssetRepository;

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

$dbConfig = [
    'MYSQL_HOST' => '127.0.0.1',
    'MYSQL_PORT' => (string) (getenv('MYSQL_TUNNEL_LOCAL_PORT') ?: '13306'),
    '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);
$queryRepo = new MailshotQueryRepository($router);
$mailshotRepo = new MailshotRepository($router);
$dataSourceService = new DataSourceService($queryRepo, $router, $parser, $validator, $compiler, $metadata, $mailshotRepo);
$attachmentRepo = new AttachmentRepository($router);
$pdfRepo = new PdfAssetRepository($router);
$lastRunRepo = new LastRunRepository($router);

$mailshotService = new MailshotService($mailshotRepo, $queryRepo, $attachmentRepo, $lastRunRepo, $dataSourceService);
$attachmentService = new AttachmentService($attachmentRepo);
$pdfService = new PdfAssetService($pdfRepo);

$unique = gmdate('Ymd_His') . '_' . bin2hex(random_bytes(3));
$queryName = 'phase3_ds_' . $unique;
$attachmentId = null;
$pdfId = null;
$mailshotId = null;
$queryId = null;
$lastRunId = null;

$membersDb = $router->membersDbName();
$stmt = $router->membersPdo()->prepare('SELECT table_name FROM information_schema.tables WHERE table_schema = :schema ORDER BY table_name ASC LIMIT 1');
$stmt->execute(['schema' => $membersDb]);
$firstTable = $stmt->fetchColumn();
if (!is_string($firstTable) || $firstTable === '') {
    fwrite(STDERR, "No source table in members db\n");
    exit(1);
}
$dsl = $membersDb . '.' . $firstTable;

try {
    $saveDs = $dataSourceService->save(null, $queryName, $dsl);
    if (($saveDs['ok'] ?? false) !== true) {
        fwrite(STDERR, 'Failed to save datasource: ' . json_encode($saveDs) . "\n");
        exit(1);
    }
    $queryId = (int) ($saveDs['id'] ?? 0);

    $tokenProbe = $mailshotService->tokenInsertionData($queryName);
    $recipientEmailField = '';
    foreach (($tokenProbe['tokens'] ?? []) as $token) {
        if (!is_array($token) || !isset($token['field'])) {
            continue;
        }
        $field = (string) $token['field'];
        if (stripos($field, 'email') !== false) {
            $recipientEmailField = $field;
            break;
        }
        if ($recipientEmailField === '') {
            $recipientEmailField = $field;
        }
    }
    if ($recipientEmailField === '') {
        fwrite(STDERR, "Expected at least one token field for datasource\n");
        exit(1);
    }

    $saveAtt = $attachmentService->save(null, [
        'name' => 'phase3_att_' . $unique,
        'file_name' => 'terms.txt',
        'mime_type' => 'text/plain',
        'file_bytes_base64' => base64_encode('phase3 attachment bytes'),
    ]);
    if (($saveAtt['ok'] ?? false) !== true) {
        fwrite(STDERR, 'Failed to save attachment: ' . json_encode($saveAtt) . "\n");
        exit(1);
    }
    $attachmentId = (int) ($saveAtt['id'] ?? 0);

    $savePdf = $pdfService->save(null, [
        'name' => 'phase3_pdf_' . $unique,
        'file_name' => 'logo.png',
        'file_bytes_base64' => base64_encode('fakepngbytes'),
        'width_mm' => '20',
        'height_mm' => '10',
        'justification' => 'left',
    ]);
    if (($savePdf['ok'] ?? false) !== true) {
        fwrite(STDERR, 'Failed to save pdf asset: ' . json_encode($savePdf) . "\n");
        exit(1);
    }
    $pdfId = (int) ($savePdf['id'] ?? 0);

    $saveMailshot = $mailshotService->save(null, [
        'Purpose' => 'Phase3 Mailshot ' . $unique,
        'DataSource' => $queryName,
        'RecipientEmailField' => $recipientEmailField,
        'Subject' => 'Subject {{ ' . strtolower($firstTable) . '_id }}',
        'Message' => '<p>Hello</p>',
        'AttachmentNames' => json_encode(['phase3_att_' . $unique], JSON_UNESCAPED_SLASHES),
    ]);
    if (($saveMailshot['ok'] ?? false) !== true) {
        fwrite(STDERR, 'Failed to save mailshot: ' . json_encode($saveMailshot) . "\n");
        exit(1);
    }
    $mailshotId = (int) ($saveMailshot['id'] ?? 0);

    $tokenData = $mailshotService->tokenInsertionData($queryName);
    if (($tokenData['errors'] ?? []) !== []) {
        fwrite(STDERR, 'Token generation failed: ' . json_encode($tokenData) . "\n");
        exit(1);
    }
    if (count($tokenData['tokens'] ?? []) === 0) {
        fwrite(STDERR, "Expected token list for datasource\n");
        exit(1);
    }

    $lastRunId = $lastRunRepo->create([
        'mailshot_id' => $mailshotId,
        'data_source' => $queryName,
        'row_index' => 1,
        'recipient_key' => 'phase3-key',
        'recipient_key_field' => 'ID',
        'recipient_email_last' => 'a@example.org',
        'status' => 'failed',
        'error_message' => 'smtp failure',
        'attempt_count' => 1,
    ]);

    $rows = $mailshotService->lastRun($mailshotId);
    if (count($rows) < 1) {
        fwrite(STDERR, "Expected last_run rows\n");
        exit(1);
    }

    $mailshotService->clearLastRun($mailshotId);
    $lastRunId = null;

    $rowsAfter = $mailshotService->lastRun($mailshotId);
    if (count($rowsAfter) !== 0) {
        fwrite(STDERR, "Expected no last_run rows after clear\n");
        exit(1);
    }

    echo "Phase 3 DB integration test passed\n";
    echo "query_name={$queryName}\n";
    echo "mailshot_id={$mailshotId}\n";
} finally {
    if ($mailshotId !== null) {
        try { $mailshotService->delete($mailshotId); } catch (Throwable $e) {}
    }
    if ($attachmentId !== null) {
        try { $attachmentService->delete($attachmentId); } catch (Throwable $e) {}
    }
    if ($pdfId !== null) {
        try { $pdfService->delete($pdfId); } catch (Throwable $e) {}
    }
    if ($queryId !== null) {
        try { $queryRepo->delete($queryId); } catch (Throwable $e) {}
    }
}
