<?php
declare(strict_types=1);

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

function golder_zakat_ui_text(string $key, string $tr, string $en = ''): string
{
    if (function_exists('ui_text')) {
        return (string)ui_text($key, $tr, $en);
    }
    return $tr;
}

function golder_zakat_ascii_lower(string $value): string
{
    $value = strtr($value, [
        'Ç' => 'c', 'ç' => 'c',
        'Ğ' => 'g', 'ğ' => 'g',
        'İ' => 'i', 'I' => 'i', 'ı' => 'i',
        'Ö' => 'o', 'ö' => 'o',
        'Ş' => 's', 'ş' => 's',
        'Ü' => 'u', 'ü' => 'u',
    ]);
    return strtolower(trim($value));
}

function golder_zakat_purity_factor(string $karat, string $category = ''): float
{
    static $map = [
        '24' => 0.995, 'has' => 0.995, '999' => 0.999, '995' => 0.995,
        '22' => 0.916, '916' => 0.916,
        '21' => 0.875,
        '18' => 0.750, '750' => 0.750,
        '14' => 0.585, '585' => 0.585,
        '8' => 0.333,
        'gumus' => 1.00, '925' => 0.925, '1000' => 1.00,
    ];

    $key = strtolower(trim(str_replace(['ayar', 'k'], '', $karat)));
    $cat = strtolower(trim($category));
    if (str_contains($cat, 'gumus')) {
        if (in_array($key, ['925', '900', '800'], true) && is_numeric($key)) {
            return ((float)$key) / 1000.0;
        }
        return 1.0;
    }
    if (isset($map[$key])) {
        return (float)$map[$key];
    }
    if (is_numeric($key)) {
        $value = (float)$key;
        return ($value > 1.0) ? ($value / 1000.0) : $value;
    }
    return 0.916;
}

function golder_zakat_normalize_rate_value(mixed $value): float
{
    $normalized = str_replace([' ', ','], ['', '.'], trim((string)$value));
    if ($normalized === '' || !is_numeric($normalized)) {
        return 0.0;
    }
    return (float)$normalized;
}

function golder_zakat_extract_buy_sell(array $item): array
{
    $buy = 0.0;
    $sell = 0.0;
    foreach ($item as $key => $value) {
        $normalized = strtolower(trim((string)$key));
        if (in_array($normalized, ['buy', 'alis', 'al', 'b'], true)) {
            $buy = golder_zakat_normalize_rate_value($value);
        }
        if (in_array($normalized, ['sell', 'satis', 'sat', 's'], true)) {
            $sell = golder_zakat_normalize_rate_value($value);
        }
    }
    return [$buy, $sell];
}

function golder_zakat_rates_to_try(array $rates): array
{
    $map = ['TRY' => 1.0];
    foreach ($rates as $key => $item) {
        $label = strtoupper(trim((string)$key));
        if ($label === '' || !is_array($item)) {
            continue;
        }
        [$buy, $sell] = golder_zakat_extract_buy_sell($item);
        $map[$label] = ($buy > 0 ? $buy : $sell);
    }
    return $map;
}

function golder_zakat_exchange_rate(array $rates, string $fromCurrency, string $toCurrency): float
{
    $from = strtoupper(trim($fromCurrency));
    $to = strtoupper(trim($toCurrency));
    if ($from === '' || $to === '' || $from === $to) {
        return 1.0;
    }

    $rateMap = golder_zakat_rates_to_try($rates);
    $fromRate = $rateMap[$from] ?? 0.0;
    $toRate = $rateMap[$to] ?? 0.0;
    if ($from === 'TRY') {
        return $toRate > 0 ? (1.0 / $toRate) : 0.0;
    }
    if ($to === 'TRY') {
        return $fromRate;
    }
    if ($fromRate <= 0 || $toRate <= 0) {
        return 0.0;
    }
    return $fromRate / $toRate;
}

function golder_zakat_base_prices(array $rates, string $targetCurrency = 'TRY'): array
{
    $target = strtoupper(trim($targetCurrency));
    if ($target === '') {
        $target = 'TRY';
    }
    $goldBuySell = is_array($rates['gram-altin'] ?? null) ? golder_zakat_extract_buy_sell($rates['gram-altin']) : [0.0, 0.0];
    $silverBuySell = is_array($rates['gumus'] ?? null) ? golder_zakat_extract_buy_sell($rates['gumus']) : [0.0, 0.0];
    $goldTry = $goldBuySell[0] > 0 ? $goldBuySell[0] : $goldBuySell[1];
    $silverTry = $silverBuySell[0] > 0 ? $silverBuySell[0] : $silverBuySell[1];
    $rate = golder_zakat_exchange_rate($rates, 'TRY', $target);
    if ($rate <= 0) {
        $rate = 1.0;
    }
    return [
        'gold' => $goldTry * $rate,
        'silver' => $silverTry * $rate,
        'currency' => $target,
    ];
}

function golder_zakat_calculate_guest(
    array $rates,
    array $items,
    float $debtsAmount = 0.0,
    string $debtsCurrency = 'TRY',
    string $targetCurrency = 'TRY',
    float $nisapGoldGrams = 85.0
): array {
    $prices = golder_zakat_base_prices($rates, $targetCurrency);
    $target = (string)$prices['currency'];
    $valueGold = 0.0;
    $valueSilver = 0.0;
    $valueCash = 0.0;

    foreach ($items as $item) {
        if (!is_array($item)) {
            continue;
        }
        $type = strtolower(trim((string)($item['type'] ?? 'cash')));
        $amount = (float)($item['amount'] ?? 0);
        if ($amount <= 0) {
            continue;
        }
        $detail = trim((string)($item['detail'] ?? ''));
        if (in_array($type, ['gold', 'altin'], true)) {
            $purity = golder_zakat_purity_factor($detail !== '' ? $detail : '24', 'altin');
            $valueGold += ($amount * $purity) * (float)$prices['gold'];
            continue;
        }
        if (in_array($type, ['silver', 'gumus'], true)) {
            $purity = golder_zakat_purity_factor($detail !== '' ? $detail : '1000', 'gumus');
            $valueSilver += ($amount * $purity) * (float)$prices['silver'];
            continue;
        }
        $sourceCurrency = strtoupper($detail !== '' ? $detail : 'TRY');
        $rate = golder_zakat_exchange_rate($rates, $sourceCurrency, $target);
        if ($rate <= 0) {
            $rate = 1.0;
        }
        $valueCash += $amount * $rate;
    }

    $debtRate = golder_zakat_exchange_rate($rates, $debtsCurrency, $target);
    if ($debtRate <= 0) {
        $debtRate = 1.0;
    }
    $valueDebt = $debtsAmount * $debtRate;
    $netAssets = ($valueGold + $valueSilver + $valueCash) - $valueDebt;
    $nisapValue = $nisapGoldGrams * (float)$prices['gold'];
    $isReached = $nisapValue > 0 && $netAssets >= $nisapValue;

    return [
        'currency' => $target,
        'val_gold' => golder_zakat_money($valueGold),
        'val_silver' => golder_zakat_money($valueSilver),
        'val_cash' => golder_zakat_money($valueCash),
        'val_debt' => golder_zakat_money($valueDebt),
        'net_assets' => golder_zakat_money($netAssets),
        'nisap_val' => golder_zakat_money($nisapValue),
        'is_reached' => $isReached,
        'zakat_due' => $isReached ? golder_zakat_money($netAssets / 40.0) : 0.0,
    ];
}

function golder_zakat_calculate_manual_store(
    float $hasGoldGrams,
    float $goldPriceTry,
    float $cashTry,
    float $tradeTry,
    float $debtTry,
    float $nisapGrams,
    string $nisapStartDate = ''
): array {
    $goldValue = max(0.0, $hasGoldGrams) * max(0.0, $goldPriceTry);
    $grossAssets = max(0.0, $goldValue + max(0.0, $cashTry) + max(0.0, $tradeTry));
    $netValue = max(0.0, $grossAssets - max(0.0, $debtTry));
    $nisapValue = max(0.0, $nisapGrams) * max(0.0, $goldPriceTry);
    $isReached = $nisapValue > 0 && $netValue >= $nisapValue;

    $hawl = '-';
    if ($nisapStartDate !== '') {
        $date = strtotime($nisapStartDate);
        if ($date !== false) {
            $days = (int)floor((time() - $date) / 86400);
            $hawl = ($days >= 354)
                ? golder_zakat_ui_text('web_hawl_completed', 'Yıl Doldu (Farz)', 'Year Completed (Obligatory)')
                : str_replace('{days}', (string)max(0, 354 - $days), golder_zakat_ui_text('web_hawl_days_left', '{days} gün kaldı', '{days} days left'));
        }
    }

    return [
        'currency' => 'TRY',
        'gold_value' => golder_zakat_money($goldValue),
        'gross_assets' => golder_zakat_money($grossAssets),
        'net_asset_value' => golder_zakat_money($netValue),
        'nisap_value' => golder_zakat_money($nisapValue),
        'is_reached' => $isReached,
        'zakat_due' => $isReached ? golder_zakat_money($netValue / 40.0) : 0.0,
        'hawl_status' => $hawl,
    ];
}

function golder_zakat_guess_ziynet_weight(string $name): float
{
    $normalized = golder_zakat_ascii_lower($name);
    if (str_contains($normalized, 'ceyrek')) {
        return 1.75;
    }
    if (str_contains($normalized, 'yarim')) {
        return 3.50;
    }
    if (str_contains($normalized, 'tam')) {
        return 7.00;
    }
    if (str_contains($normalized, 'ata')) {
        return 7.20;
    }
    return 0.0;
}

function golder_zakat_is_silver_item(string $name, string $karat = ''): bool
{
    $nameNorm = golder_zakat_ascii_lower($name);
    $karatNorm = golder_zakat_ascii_lower($karat);
    if (str_contains($nameNorm, 'gumus')) {
        return true;
    }
    return in_array($karatNorm, ['gumus', '925', '900', '800', '1000'], true);
}

function golder_zakat_hawl_status(string $nisapStartDate = ''): string
{
    $nisapStartDate = trim($nisapStartDate);
    if ($nisapStartDate === '') {
        return '-';
    }
    $date = strtotime($nisapStartDate);
    if ($date === false) {
        return golder_zakat_ui_text('web_invalid_date', 'Tarih Hatalı', 'Invalid Date');
    }
    $days = (int)floor((time() - $date) / 86400);
    return ($days >= 354)
        ? golder_zakat_ui_text('web_hawl_completed', 'Yıl Doldu (Farz)', 'Year Completed (Obligatory)')
        : str_replace('{days}', (string)max(0, 354 - $days), golder_zakat_ui_text('web_hawl_days_left', '{days} gün kaldı', '{days} days left'));
}

function golder_zakat_calculate_store_snapshot(
    PDO $db,
    string $profileId,
    array $rates,
    string $targetCurrency = 'TRY',
    string $nisapStartDate = ''
): array {
    $prices = golder_zakat_base_prices($rates, $targetCurrency);
    $target = (string)($prices['currency'] ?? 'TRY');
    $priceGold = (float)($prices['gold'] ?? 0);
    $priceSilver = (float)($prices['silver'] ?? 0);

    $report = [
        'details' => [],
        'total_gold_pure_gr' => 0.0,
        'total_silver_pure_gr' => 0.0,
        'total_cash' => 0.0,
        'total_debts' => 0.0,
        'gross_asset_value' => 0.0,
        'net_asset_value' => 0.0,
        'nisap_value' => 0.0,
        'zakat_due' => 0.0,
        'currency' => $target,
        'gold_price' => $priceGold,
        'silver_price' => $priceSilver,
        'is_reached' => false,
        'hawl_status' => golder_zakat_hawl_status($nisapStartDate),
    ];

    $definitionMap = [];
    $definitionNameMap = [];
    $stDefs = $db->prepare(
        "SELECT stock_type, name, karat_purity, default_weight_gr
         FROM product_definitions
         WHERE profile_id = :pid AND COALESCE(is_deleted, 0) = 0"
    );
    $stDefs->execute([':pid' => $profileId]);
    foreach ($stDefs->fetchAll() ?: [] as $defRow) {
        $stockType = golder_zakat_ascii_lower((string)($defRow['stock_type'] ?? 'product'));
        $name = trim((string)($defRow['name'] ?? ''));
        if ($name === '') {
            continue;
        }
        $key = $stockType . '|' . golder_zakat_ascii_lower($name);
        $definitionMap[$key] = $defRow;
        $definitionNameMap[golder_zakat_ascii_lower($name)] = $defRow;
    }

    $stStock = $db->prepare(
        "SELECT stock_type, item_type_name, SUM(quantity) total_qty, SUM(COALESCE(quantity_gr, 0)) total_gr
         FROM stock_items
         WHERE profile_id = :pid AND COALESCE(is_deleted, 0) = 0 AND quantity > 0
         GROUP BY stock_type, item_type_name
         ORDER BY stock_type ASC, item_type_name ASC"
    );
    $stStock->execute([':pid' => $profileId]);
    foreach ($stStock->fetchAll() ?: [] as $stockRow) {
        $stockType = golder_zakat_ascii_lower((string)($stockRow['stock_type'] ?? 'product'));
        $itemName = trim((string)($stockRow['item_type_name'] ?? ''));
        if ($itemName === '') {
            continue;
        }
        $definitionKey = $stockType . '|' . golder_zakat_ascii_lower($itemName);
        $defRow = $definitionMap[$definitionKey] ?? $definitionNameMap[golder_zakat_ascii_lower($itemName)] ?? [];
        $karat = trim((string)($defRow['karat_purity'] ?? ''));
        $defaultWeight = (float)($defRow['default_weight_gr'] ?? 0);
        $qty = (float)($stockRow['total_qty'] ?? 0);
        $totalGr = (float)($stockRow['total_gr'] ?? 0);
        if ($qty <= 0 && $totalGr <= 0) {
            continue;
        }

        $isSilver = golder_zakat_is_silver_item($itemName, $karat);
        $categoryHint = $isSilver ? 'gumus' : 'altin';
        $gross = 0.0;
        $detailLabel = $karat !== '' ? $karat : ($isSilver ? '1000' : '22');

        if ($stockType === 'ziynet') {
            $weightPerUnit = $defaultWeight > 0 ? $defaultWeight : golder_zakat_guess_ziynet_weight($itemName);
            $gross = max(0.0, $qty * $weightPerUnit);
            $detailLabel = $detailLabel . ($weightPerUnit > 0 ? ' (x' . number_format($weightPerUnit, 3, '.', '') . 'g)' : '');
        } elseif ($stockType === 'scrap') {
            $gross = max(0.0, $qty);
        } else {
            $gross = $totalGr > 0 ? max(0.0, $totalGr) : max(0.0, $qty);
        }

        if ($gross <= 0) {
            continue;
        }
        $purity = golder_zakat_purity_factor($karat !== '' ? $karat : ($isSilver ? '1000' : '22'), $categoryHint);
        $pure = $gross * $purity;
        $unitPrice = $isSilver ? $priceSilver : $priceGold;
        $value = $pure * $unitPrice;
        if ($isSilver) {
            $report['total_silver_pure_gr'] += $pure;
        } else {
            $report['total_gold_pure_gr'] += $pure;
        }
        $report['details'][] = [
            'group' => ($stockType === 'ziynet' ? 'Ziynet' : ($stockType === 'scrap' ? 'Hurda' : ($isSilver ? 'Gumus' : 'Altin'))),
            'name' => $itemName,
            'karat' => $detailLabel,
            'gross' => golder_zakat_money($gross),
            'pure' => golder_zakat_money($pure),
            'value' => golder_zakat_money($value),
        ];
    }

    $stBalances = $db->prepare(
        "SELECT fa.name account_name, ft.currency currency,
                COALESCE(SUM(CASE WHEN ft.transaction_type='Income' THEN ft.amount ELSE -ft.amount END), 0) amount
         FROM financial_accounts fa
         LEFT JOIN financial_transactions ft
           ON ft.account_id = fa.id
          AND ft.profile_id = fa.profile_id
          AND COALESCE(ft.is_deleted, 0) = 0
         WHERE fa.profile_id = :pid
           AND COALESCE(fa.is_deleted, 0) = 0
           AND fa.type IN ('cash', 'card')
         GROUP BY fa.id, fa.name, ft.currency
         ORDER BY fa.name ASC"
    );
    $stBalances->execute([':pid' => $profileId]);
    foreach ($stBalances->fetchAll() ?: [] as $balanceRow) {
        $amount = (float)($balanceRow['amount'] ?? 0);
        $currency = strtoupper(trim((string)($balanceRow['currency'] ?? 'TRY')));
        if ($amount <= 0.01 || $currency === '') {
            continue;
        }
        $rate = golder_zakat_exchange_rate($rates, $currency, $target);
        if ($rate <= 0) {
            continue;
        }
        $value = $amount * $rate;
        $report['total_cash'] += $value;
        $report['details'][] = [
            'group' => 'Nakit',
            'name' => trim((string)($balanceRow['account_name'] ?? 'Kasa')),
            'karat' => $currency,
            'gross' => golder_zakat_money($amount),
            'pure' => 0.0,
            'value' => golder_zakat_money($value),
        ];
    }

    $tryToTarget = golder_zakat_exchange_rate($rates, 'TRY', $target);
    if ($tryToTarget <= 0) {
        $tryToTarget = 1.0;
    }

    $stReceivables = $db->prepare(
        "SELECT person_full_name, total_amount_base, paid_amount_base
         FROM debt_records
         WHERE profile_id = :pid
           AND COALESCE(is_deleted, 0) = 0
           AND COALESCE(is_paid, 0) = 0
           AND record_type = 'Receivable'
           AND debt_category = 'Cash'"
    );
    $stReceivables->execute([':pid' => $profileId]);
    foreach ($stReceivables->fetchAll() ?: [] as $debtRow) {
        $remaining = (float)($debtRow['total_amount_base'] ?? 0) - (float)($debtRow['paid_amount_base'] ?? 0);
        if ($remaining <= 0.01) {
            continue;
        }
        $value = $remaining * $tryToTarget;
        $report['total_cash'] += $value;
        $report['details'][] = [
            'group' => 'Alacak',
            'name' => trim((string)($debtRow['person_full_name'] ?? 'Cari')),
            'karat' => 'TRY',
            'gross' => golder_zakat_money($remaining),
            'pure' => 0.0,
            'value' => golder_zakat_money($value),
        ];
    }

    $stPayables = $db->prepare(
        "SELECT person_full_name, total_amount_base, paid_amount_base
         FROM debt_records
         WHERE profile_id = :pid
           AND COALESCE(is_deleted, 0) = 0
           AND COALESCE(is_paid, 0) = 0
           AND record_type = 'Payable'
           AND debt_category = 'Cash'"
    );
    $stPayables->execute([':pid' => $profileId]);
    foreach ($stPayables->fetchAll() ?: [] as $debtRow) {
        $remaining = (float)($debtRow['total_amount_base'] ?? 0) - (float)($debtRow['paid_amount_base'] ?? 0);
        if ($remaining <= 0.01) {
            continue;
        }
        $value = $remaining * $tryToTarget;
        $report['total_debts'] += $value;
        $report['details'][] = [
            'group' => 'Borc',
            'name' => trim((string)($debtRow['person_full_name'] ?? 'Cari')),
            'karat' => 'TRY',
            'gross' => golder_zakat_money($remaining),
            'pure' => 0.0,
            'value' => golder_zakat_money(-$value),
        ];
    }

    $goldValue = $report['total_gold_pure_gr'] * $priceGold;
    $silverValue = $report['total_silver_pure_gr'] * $priceSilver;
    $grossAssetValue = $goldValue + $silverValue + $report['total_cash'];
    $netAssetValue = $grossAssetValue - $report['total_debts'];
    $nisapValue = 85.0 * $priceGold;
    $isReached = $nisapValue > 0 && $netAssetValue >= $nisapValue;

    $report['gross_asset_value'] = golder_zakat_money($grossAssetValue);
    $report['net_asset_value'] = golder_zakat_money($netAssetValue);
    $report['nisap_value'] = golder_zakat_money($nisapValue);
    $report['is_reached'] = $isReached;
    $report['zakat_due'] = $isReached ? golder_zakat_money($netAssetValue / 40.0) : 0.0;
    $report['total_gold_pure_gr'] = golder_zakat_money($report['total_gold_pure_gr']);
    $report['total_silver_pure_gr'] = golder_zakat_money($report['total_silver_pure_gr']);
    $report['total_cash'] = golder_zakat_money($report['total_cash']);
    $report['total_debts'] = golder_zakat_money($report['total_debts']);

    return $report;
}


