<?php

require_once __DIR__ . '/family_settings.php';
require_once __DIR__ . '/persona.php';

function bankingEnabled(array $familySettings): bool {
    return !empty($familySettings['banking_enabled']);
}

function bankingRoundMoney(float $value): float {
    return round($value, 2);
}

function bankingYmd(string $isoDate): string {
    if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $isoDate)) {
        return $isoDate;
    }
    if ($isoDate !== '' && strlen($isoDate) >= 10) {
        $candidate = substr($isoDate, 0, 10);
        if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $candidate)) {
            return $candidate;
        }
    }
    return gmdate('Y-m-d');
}

function bankingDaysInMonth(string $ymd): int {
    $parts = explode('-', $ymd);
    if (count($parts) !== 3) {
        return 30;
    }
    $year = (int) $parts[0];
    $month = (int) $parts[1];
    if ($year < 1970 || $month < 1 || $month > 12) {
        return 30;
    }
    return cal_days_in_month(CAL_GREGORIAN, $month, $year);
}

function bankingDailyRate(float $monthlyRatePercent, string $ymd): float {
    if ($monthlyRatePercent <= 0) {
        return 0.0;
    }
    $days = bankingDaysInMonth($ymd);
    if ($days <= 0) {
        return 0.0;
    }
    $monthlyRate = $monthlyRatePercent / 100.0;
    return pow(1 + $monthlyRate, 1.0 / $days) - 1.0;
}

function bankingApplySavingsInterestToPerson(array $person, array $familySettings, ?string $asOfYmd = null): array {
    if (!bankingEnabled($familySettings)) {
        return $person;
    }
    $asOf = $asOfYmd !== null ? bankingYmd($asOfYmd) : gmdate('Y-m-d');
    $last = bankingYmd((string) ($person['banking_interest_last_applied_at'] ?? ''));
    if (($person['banking_interest_last_applied_at'] ?? '') === '') {
        $person['banking_interest_last_applied_at'] = $asOf;
        return $person;
    }
    if ($last >= $asOf) {
        return $person;
    }
    $monthlyRate = (float) ($familySettings['banking_savings_monthly_interest_rate'] ?? 0);
    if ($monthlyRate <= 0) {
        $person['banking_interest_last_applied_at'] = $asOf;
        return $person;
    }
    $savings = is_numeric($person['savings_balance'] ?? null) ? (float) $person['savings_balance'] : 0.0;
    if ($savings <= 0) {
        $person['banking_interest_last_applied_at'] = $asOf;
        return $person;
    }

    $cursor = $last;
    while ($cursor < $asOf) {
        $next = gmdate('Y-m-d', strtotime($cursor . ' +1 day'));
        $dailyRate = bankingDailyRate($monthlyRate, $next);
        if ($dailyRate > 0 && $savings > 0) {
            $savings = $savings * (1 + $dailyRate);
        }
        $cursor = $next;
    }
    $person['savings_balance'] = bankingRoundMoney($savings);
    $person['banking_interest_last_applied_at'] = $asOf;
    return $person;
}

function bankingApplySavingsInterestToPeople(array $people, array $familySettings, ?string $asOfYmd = null): array {
    $out = [];
    foreach ($people as $person) {
        if (!is_array($person)) {
            continue;
        }
        $out[] = bankingApplySavingsInterestToPerson($person, $familySettings, $asOfYmd);
    }
    return $out;
}

function bankingCreditCheckingByRule(array $person, float $amount, array $familySettings): array {
    $amount = bankingRoundMoney($amount);
    if ($amount <= 0) {
        return ['person' => $person, 'allocations' => ['checking' => 0.0, 'savings' => 0.0, 'charity' => 0.0, 'roundup' => 0.0]];
    }
    $checking = $amount;
    $savings = 0.0;
    $charity = 0.0;
    $roundup = 0.0;

    if (!empty($familySettings['banking_auto_split_enabled'])) {
        $sPct = (float) ($familySettings['banking_auto_split_savings_pct'] ?? 0);
        $cPct = (float) ($familySettings['banking_auto_split_charity_pct'] ?? 0);
        if (($sPct + $cPct) > 100) {
            $cPct = max(0, 100 - $sPct);
        }
        $savings = bankingRoundMoney($amount * ($sPct / 100.0));
        $charity = bankingRoundMoney($amount * ($cPct / 100.0));
        $checking = bankingRoundMoney($amount - $savings - $charity);
    }

    $roundupDest = (string) ($familySettings['banking_roundup_destination'] ?? 'off');
    if ($roundupDest !== 'off' && $checking > 0) {
        $fraction = $checking - floor($checking);
        $needed = $fraction > 0 ? bankingRoundMoney(1 - $fraction) : 0.0;
        if ($needed > 0) {
            $roundup = min($needed, $checking);
            $checking = bankingRoundMoney($checking - $roundup);
            if ($roundupDest === 'savings') {
                $savings = bankingRoundMoney($savings + $roundup);
            } elseif ($roundupDest === 'charity') {
                $charity = bankingRoundMoney($charity + $roundup);
            }
        }
    }

    $person['checking_balance'] = bankingRoundMoney((float) ($person['checking_balance'] ?? 0) + $checking);
    $person['savings_balance'] = bankingRoundMoney((float) ($person['savings_balance'] ?? 0) + $savings);
    $person['charity_pending_balance'] = bankingRoundMoney((float) ($person['charity_pending_balance'] ?? 0) + $charity);
    $person['currency_balance'] = $person['checking_balance'];

    return [
        'person' => $person,
        'allocations' => [
            'checking' => $checking,
            'savings' => $savings,
            'charity' => $charity,
            'roundup' => $roundup,
        ],
    ];
}

function appendBankTransaction(array $tx): bool {
    $rows = readJsonFile('bank_transactions.json');
    if (!is_array($rows)) {
        $rows = [];
    }
    $rows[] = $tx;
    return writeJsonFile('bank_transactions.json', $rows);
}

function bankingCategoryOrDefault(string $category, string $default): string {
    $category = trim($category);
    if ($category === '') {
        return $default;
    }
    return substr($category, 0, 50);
}
