<?php

declare(strict_types=1);

function app_reporting_rows(PDO $pdo, string $tenantId): array
{
    return app_query_all(
        $pdo,
        <<<'SQL'
SELECT
    m.id,
    m.display_name,
    m.email,
    COALESCE(SUM(le.amount), 0) AS balance,
    COALESCE((
        SELECT SUM(ABS(ce.strokes))
        FROM coffee_entries ce
        WHERE ce.tenant_id = :tenant_id
          AND ce.member_id = m.id
    ), 0) AS total_strokes,
    COALESCE((
        SELECT SUM(pe.amount)
        FROM payment_entries pe
        WHERE pe.tenant_id = :tenant_id
          AND pe.member_id = m.id
    ), 0) AS total_payments,
    COALESCE((
        SELECT SUM(ABS(ce.total_cost))
        FROM coffee_entries ce
        WHERE ce.tenant_id = :tenant_id
          AND ce.member_id = m.id
    ), 0) AS total_coffee_cost
FROM members m
LEFT JOIN ledger_entries le ON le.member_id = m.id AND le.tenant_id = m.tenant_id
WHERE m.tenant_id = :tenant_id
  AND m.status = 'active'
GROUP BY m.id, m.display_name, m.email
ORDER BY m.display_name ASC
SQL,
        ['tenant_id' => $tenantId]
    );
}

function app_bulk_stroke_entries(array $input): array
{
    $entries = [];

    foreach ($input as $memberId => $value) {
        $strokes = max(0, (int) $value);
        if ($strokes > 0) {
            $entries[(string) $memberId] = $strokes;
        }
    }

    return $entries;
}

function app_bulk_payment_entries(array $input): array
{
    $entries = [];

    foreach ($input as $memberId => $value) {
        $amount = is_numeric($value) ? (float) $value : 0.0;
        if ($amount > 0) {
            $entries[(string) $memberId] = $amount;
        }
    }

    return $entries;
}

if (!function_exists('app_create_coffee_booking')) {
    function app_create_coffee_booking(PDO $pdo, string $tenantId, string $memberId, int $strokes, float $unitPrice, string $bookedAt, string $source = 'manual'): void
    {
        $entryId = app_uuid();
        $ledgerId = app_uuid();
        $totalCost = round($strokes * $unitPrice, 2);
        $now = date('Y-m-d H:i:s');

        app_execute(
            $pdo,
            'INSERT INTO coffee_entries (id, tenant_id, member_id, strokes, unit_price, total_cost, booking_source, booked_at, created_at, updated_at) VALUES (:id, :tenant_id, :member_id, :strokes, :unit_price, :total_cost, :booking_source, :booked_at, :created_at, :updated_at)',
            [
                'id' => $entryId,
                'tenant_id' => $tenantId,
                'member_id' => $memberId,
                'strokes' => $strokes,
                'unit_price' => number_format($unitPrice, 2, '.', ''),
                'total_cost' => number_format($totalCost, 2, '.', ''),
                'booking_source' => $source,
                'booked_at' => $bookedAt,
                'created_at' => $now,
                'updated_at' => $now,
            ]
        );

        app_execute(
            $pdo,
            'INSERT INTO ledger_entries (id, tenant_id, member_id, entry_type, amount, reference_type, reference_id, booked_at, created_at, updated_at) VALUES (:id, :tenant_id, :member_id, :entry_type, :amount, :reference_type, :reference_id, :booked_at, :created_at, :updated_at)',
            [
                'id' => $ledgerId,
                'tenant_id' => $tenantId,
                'member_id' => $memberId,
                'entry_type' => 'coffee_charge',
                'amount' => number_format($totalCost * -1, 2, '.', ''),
                'reference_type' => 'coffee_entry',
                'reference_id' => $entryId,
                'booked_at' => $bookedAt,
                'created_at' => $now,
                'updated_at' => $now,
            ]
        );
    }
}

if (!function_exists('app_create_payment_booking')) {
    function app_create_payment_booking(PDO $pdo, string $tenantId, string $memberId, float $amount, string $bookedAt, string $method = 'manual'): void
    {
        $entryId = app_uuid();
        $ledgerId = app_uuid();
        $now = date('Y-m-d H:i:s');

        app_execute(
            $pdo,
            'INSERT INTO payment_entries (id, tenant_id, member_id, amount, payment_method, booked_at, created_at, updated_at) VALUES (:id, :tenant_id, :member_id, :amount, :payment_method, :booked_at, :created_at, :updated_at)',
            [
                'id' => $entryId,
                'tenant_id' => $tenantId,
                'member_id' => $memberId,
                'amount' => number_format($amount, 2, '.', ''),
                'payment_method' => $method,
                'booked_at' => $bookedAt,
                'created_at' => $now,
                'updated_at' => $now,
            ]
        );

        app_execute(
            $pdo,
            'INSERT INTO ledger_entries (id, tenant_id, member_id, entry_type, amount, reference_type, reference_id, booked_at, created_at, updated_at) VALUES (:id, :tenant_id, :member_id, :entry_type, :amount, :reference_type, :reference_id, :booked_at, :created_at, :updated_at)',
            [
                'id' => $ledgerId,
                'tenant_id' => $tenantId,
                'member_id' => $memberId,
                'entry_type' => 'payment_credit',
                'amount' => number_format($amount, 2, '.', ''),
                'reference_type' => 'payment_entry',
                'reference_id' => $entryId,
                'booked_at' => $bookedAt,
                'created_at' => $now,
                'updated_at' => $now,
            ]
        );
    }
}

function app_handle_bulk_finance_action(PDO $pdo, array $auth): void
{
    if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST' || !app_can_manage_finance($auth)) {
        return;
    }

    $action = (string) ($_POST['action'] ?? '');
    $tenantId = (string) ($auth['tenant_id'] ?? '');
    $bookedAt = app_normalize_datetime_input((string) ($_POST['booked_at'] ?? ''));

    if (!in_array($action, ['bulk-record-coffee', 'bulk-record-payments'], true) || $tenantId === '') {
        return;
    }

    try {
        $pdo->beginTransaction();

        if ($action === 'bulk-record-coffee') {
            $unitPrice = (float) ($_POST['unit_price'] ?? 0);
            $entries = app_bulk_stroke_entries((array) ($_POST['bulk_strokes'] ?? []));

            if ($unitPrice <= 0 || $entries === []) {
                throw new RuntimeException('Bitte gib mindestens einen Sammel-Stricheintrag und einen gültigen Preis an.');
            }

            foreach ($entries as $memberId => $strokes) {
                app_create_coffee_booking($pdo, $tenantId, $memberId, $strokes, $unitPrice, $bookedAt, 'bulk');
            }

            $pdo->commit();
            app_flash(count($entries) . ' Sammel-Stricheinträge wurden verbucht.', 'success');
            app_redirect('/ledger/');
        }

        $entries = app_bulk_payment_entries((array) ($_POST['bulk_amounts'] ?? []));
        $method = trim((string) ($_POST['payment_method'] ?? 'manual'));
        $method = $method !== '' ? $method : 'manual';

        if ($entries === []) {
            throw new RuntimeException('Bitte gib mindestens eine Sammel-Einzahlung an.');
        }

        foreach ($entries as $memberId => $amount) {
            app_create_payment_booking($pdo, $tenantId, $memberId, $amount, $bookedAt, $method);
        }

        $pdo->commit();
        app_flash(count($entries) . ' Sammel-Einzahlungen wurden verbucht.', 'success');
        app_redirect('/payments/');
    } catch (Throwable $exception) {
        if ($pdo->inTransaction()) {
            $pdo->rollBack();
        }

        app_flash($exception->getMessage(), 'error');
        app_redirect(app_request_path());
    }
}

function app_handle_csv_import(PDO $pdo, array $auth): array
{
    $result = ['rows' => [], 'summary' => ['imported' => 0, 'duplicates' => 0, 'unmatched' => 0]];

    if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'POST' || (string) ($_POST['action'] ?? '') !== 'import-paypal-csv') {
        return $result;
    }

    if (!app_can_manage_finance($auth)) {
        app_flash('Für den CSV-Import brauchst du Finanz- oder Tenant-Rechte.', 'warning');
        app_redirect('/imports/');
    }

    if (!isset($_FILES['csv_file']) || (int) ($_FILES['csv_file']['error'] ?? 1) !== 0) {
        app_flash('Bitte lade eine CSV-Datei hoch.', 'error');
        app_redirect('/imports/');
    }

    $tenantId = (string) ($auth['tenant_id'] ?? '');
    $handle = fopen((string) $_FILES['csv_file']['tmp_name'], 'rb');
    if ($handle === false) {
        app_flash('Die CSV-Datei konnte nicht gelesen werden.', 'error');
        app_redirect('/imports/');
    }

    fgetcsv($handle, 0, ',');
    $members = app_members_for_tenant($pdo, $tenantId);
    $memberMap = [];
    foreach ($members as $member) {
        $display = strtolower(trim((string) ($member['display_name'] ?? '')));
        $email = strtolower(trim((string) ($member['email'] ?? '')));
        $reference = strtolower(trim((string) ($member['payment_reference'] ?? '')));

        foreach ([$display, $email, $reference] as $key) {
            if ($key !== '') {
                $memberMap[$key] = $member;
            }
        }
    }

    $pdo->beginTransaction();

    try {
        while (($row = fgetcsv($handle, 0, ',')) !== false) {
            $bookedAt = app_normalize_datetime_input((string) ($row[0] ?? ''));
            $name = strtolower(trim((string) ($row[3] ?? '')));
            $amount = (float) str_replace(',', '.', (string) ($row[7] ?? '0'));

            if ($name === '' || $amount <= 0) {
                continue;
            }

            $member = $memberMap[$name] ?? null;
            if (!is_array($member)) {
                $result['rows'][] = ['date' => $bookedAt, 'name' => $name, 'amount' => $amount, 'status' => 'unmatched'];
                $result['summary']['unmatched']++;
                continue;
            }

            $duplicate = app_query_one(
                $pdo,
                'SELECT id FROM payment_entries WHERE tenant_id = :tenant_id AND member_id = :member_id AND amount = :amount AND DATE(booked_at) = DATE(:booked_at) LIMIT 1',
                [
                    'tenant_id' => $tenantId,
                    'member_id' => (string) ($member['id'] ?? ''),
                    'amount' => number_format($amount, 2, '.', ''),
                    'booked_at' => $bookedAt,
                ]
            );

            if ($duplicate !== null) {
                $result['rows'][] = ['date' => $bookedAt, 'name' => (string) ($member['display_name'] ?? $name), 'amount' => $amount, 'status' => 'duplicate'];
                $result['summary']['duplicates']++;
                continue;
            }

            app_create_payment_booking($pdo, $tenantId, (string) ($member['id'] ?? ''), $amount, $bookedAt, 'paypal_csv');
            $result['rows'][] = ['date' => $bookedAt, 'name' => (string) ($member['display_name'] ?? $name), 'amount' => $amount, 'status' => 'imported'];
            $result['summary']['imported']++;
        }

        fclose($handle);
        $pdo->commit();
        app_flash('Der CSV-Import wurde verarbeitet.', 'success');
    } catch (Throwable $exception) {
        fclose($handle);
        if ($pdo->inTransaction()) {
            $pdo->rollBack();
        }

        app_flash($exception->getMessage(), 'error');
        app_redirect('/imports/');
    }

    return $result;
}
