<?php

declare(strict_types=1);

require __DIR__ . '/dev-db.php';
require __DIR__ . '/golden-master-data.php';
require __DIR__ . '/../app/ledger.php';

function m4_service_env(string $name, string $default): string
{
    $value = getenv($name);
    if ($value === false || trim($value) === '') {
        return $default;
    }

    return trim($value);
}

function m4_service_assert_equal(string $label, mixed $expected, mixed $actual, array &$failures, int &$passes): void
{
    if ($expected === $actual) {
        $passes++;
        echo "PASS {$label}\n";
        return;
    }

    $failures[] = "{$label}: expected " . var_export($expected, true) . ', got ' . var_export($actual, true);
    echo "FAIL {$label}\n";
}

function m4_service_assert(string $label, bool $condition, array &$failures, int &$passes): void
{
    m4_service_assert_equal($label, true, $condition, $failures, $passes);
}

function m4_service_fetch_tenant_id(PDO $pdo, string $slug): int
{
    $stmt = $pdo->prepare('SELECT id FROM tenants WHERE slug = ?');
    $stmt->execute([$slug]);
    $tenantId = $stmt->fetchColumn();

    if ($tenantId === false) {
        throw new RuntimeException("Tenant '{$slug}' not found.");
    }

    return (int)$tenantId;
}

/**
 * @return array{total_payments_cents: int, total_costs_cents: int, total_marks: int, balance_cents: int, year_payments_cents: int, year_costs_cents: int, year_marks: int}
 */
function m4_service_totals_from_summaries(array $summaries): array
{
    $totals = ledger_empty_totals();

    foreach ($summaries as $summary) {
        $totals['total_payments_cents'] += (int)$summary['total_payments_cents'];
        $totals['total_costs_cents'] += (int)$summary['total_costs_cents'];
        $totals['total_marks'] += (int)$summary['total_marks'];
        $totals['balance_cents'] += (int)$summary['balance_cents'];
        $totals['year_payments_cents'] += (int)$summary['year_payments_cents'];
        $totals['year_costs_cents'] += (int)$summary['year_costs_cents'];
        $totals['year_marks'] += (int)$summary['year_marks'];
    }

    return $totals;
}

$pdo = dev_pdo();
dev_apply_schema($pdo);

$tenantSlug = m4_service_env('M4_DEFAULT_TENANT_SLUG', m4_service_env('M3_DEFAULT_TENANT_SLUG', 'default'));
$tenantId = m4_service_fetch_tenant_id($pdo, $tenantSlug);
$expected = gm_expected_summaries();
$emails = array_keys($expected);
$failures = [];
$passes = 0;

$summaries = ledger_fetch_participant_summaries($pdo, $tenantId, [
    'email_norms' => $emails,
    'year' => gm_current_year(),
]);

$summariesByEmail = [];
foreach ($summaries as $summary) {
    if ($summary['email_norm'] !== null) {
        $summariesByEmail[$summary['email_norm']] = $summary;
    }
}

m4_service_assert_equal('ledger service summary count', count($expected), count($summariesByEmail), $failures, $passes);

$keyMap = [
    'total_payments' => 'total_payments_cents',
    'total_costs' => 'total_costs_cents',
    'total_marks' => 'total_marks',
    'balance' => 'balance_cents',
    'year_payments' => 'year_payments_cents',
    'year_costs' => 'year_costs_cents',
    'year_marks' => 'year_marks',
];

foreach ($expected as $email => $expectedSummary) {
    m4_service_assert("ledger service summary exists {$email}", isset($summariesByEmail[$email]), $failures, $passes);
    if (!isset($summariesByEmail[$email])) {
        continue;
    }

    m4_service_assert(
        "ledger service {$email} keeps legacy member id",
        $summariesByEmail[$email]['legacy_mitarbeiter_id'] !== null,
        $failures,
        $passes
    );

    foreach ($keyMap as $expectedKey => $actualKey) {
        m4_service_assert_equal(
            "ledger service {$email} {$expectedKey}",
            $expectedSummary[$expectedKey],
            $summariesByEmail[$email][$actualKey],
            $failures,
            $passes
        );
    }
}

$allSummaries = ledger_fetch_participant_summaries($pdo, $tenantId, [
    'year' => gm_current_year(),
]);
$tenantTotals = ledger_fetch_tenant_totals($pdo, $tenantId, gm_current_year());
foreach (m4_service_totals_from_summaries($allSummaries) as $key => $value) {
    m4_service_assert_equal("ledger service tenant total {$key}", $value, $tenantTotals[$key], $failures, $passes);
}

$stmt = $pdo->prepare('SELECT COUNT(*) FROM participants WHERE tenant_id = ? AND active = 1');
$stmt->execute([$tenantId]);
$activeExpectedCount = (int)$stmt->fetchColumn();
$activeSummaries = ledger_fetch_participant_summaries($pdo, $tenantId, ['active_only' => true]);
m4_service_assert_equal('ledger service active participant count', $activeExpectedCount, count($activeSummaries), $failures, $passes);

$paypalSummary = $summariesByEmail['gm-paypal@test.local'] ?? null;
m4_service_assert('ledger service paypal summary is present', $paypalSummary !== null, $failures, $passes);
if ($paypalSummary !== null) {
    $singleSummary = ledger_fetch_participant_summary($pdo, $tenantId, $paypalSummary['participant_id'], gm_current_year());
    m4_service_assert('ledger service single participant summary is present', $singleSummary !== null, $failures, $passes);
    if ($singleSummary !== null) {
        m4_service_assert_equal('ledger service single participant email', 'gm-paypal@test.local', $singleSummary['email_norm'], $failures, $passes);
        m4_service_assert_equal('ledger service single participant balance', 650, $singleSummary['balance_cents'], $failures, $passes);
    }

    $legacySummary = ledger_fetch_participant_summary_by_legacy_id(
        $pdo,
        $tenantId,
        (int)$paypalSummary['legacy_mitarbeiter_id'],
        gm_current_year()
    );
    m4_service_assert('ledger service legacy participant summary is present', $legacySummary !== null, $failures, $passes);
    if ($legacySummary !== null) {
        m4_service_assert_equal('ledger service legacy participant id matches', $paypalSummary['participant_id'], $legacySummary['participant_id'], $failures, $passes);
        m4_service_assert_equal('ledger service legacy participant balance', 650, $legacySummary['balance_cents'], $failures, $passes);
    }

    $paypalEntries = ledger_fetch_recent_entries($pdo, $tenantId, [
        'participant_id' => $paypalSummary['participant_id'],
        'limit' => 100,
    ]);
    m4_service_assert_equal('ledger service paypal entry count', 2, count($paypalEntries), $failures, $passes);
    foreach ($paypalEntries as $entry) {
        m4_service_assert_equal('ledger service paypal entry tenant', $tenantId, $entry['tenant_id'], $failures, $passes);
        m4_service_assert_equal('ledger service paypal entry participant', $paypalSummary['participant_id'], $entry['participant_id'], $failures, $passes);
    }
}

$recentEntries = ledger_fetch_recent_entries($pdo, $tenantId, ['limit' => 5]);
m4_service_assert_equal('ledger service recent entry limit', 5, count($recentEntries), $failures, $passes);
$previousBookedAt = null;
foreach ($recentEntries as $entry) {
    m4_service_assert_equal('ledger service recent entry tenant', $tenantId, $entry['tenant_id'], $failures, $passes);
    m4_service_assert('ledger service recent entry has amount', $entry['amount_cents'] !== 0, $failures, $passes);
    if ($previousBookedAt !== null) {
        m4_service_assert('ledger service recent entries are sorted', $previousBookedAt >= $entry['booked_at'], $failures, $passes);
    }
    $previousBookedAt = $entry['booked_at'];
}

$legacyConsumptionCount = (int)$pdo->query('SELECT COUNT(*) FROM kl_Kaffeeverbrauch')->fetchColumn();
$consumptionEntries = ledger_fetch_recent_entries($pdo, $tenantId, [
    'type' => 'consumption',
    'limit' => 100,
]);
m4_service_assert_equal('ledger service consumption entry count', $legacyConsumptionCount, count($consumptionEntries), $failures, $passes);

m4_service_assert_equal('ledger service empty participant id filter', [], ledger_fetch_participant_summaries($pdo, $tenantId, [
    'participant_ids' => [],
]), $failures, $passes);
m4_service_assert_equal('ledger service empty legacy id filter', [], ledger_fetch_participant_summaries($pdo, $tenantId, [
    'legacy_mitarbeiter_ids' => [],
]), $failures, $passes);
m4_service_assert_equal('ledger service unknown legacy summary', null, ledger_fetch_participant_summary_by_legacy_id($pdo, $tenantId, 0), $failures, $passes);
m4_service_assert_equal('ledger service unknown tenant summaries', [], ledger_fetch_participant_summaries($pdo, 0), $failures, $passes);
m4_service_assert_equal('ledger service unknown tenant entries', [], ledger_fetch_recent_entries($pdo, 0), $failures, $passes);
m4_service_assert_equal('ledger service unknown tenant totals', ledger_empty_totals(), ledger_fetch_tenant_totals($pdo, 0), $failures, $passes);

if ($failures !== []) {
    echo "\nM4 ledger service check failed with " . count($failures) . " failure(s):\n";
    foreach ($failures as $failure) {
        echo "- {$failure}\n";
    }
    exit(1);
}

echo "\nM4 ledger service check passed with {$passes} assertions.\n";
