<?php
declare(strict_types=1);

namespace App\Modules\Members\Services;

use App\Core\App;
use App\Modules\Rules\Services\RuleEngine;

final class BoardOfferService
{
    public static function getActiveOffers(?int $branchId = null): array
    {
        $db = App::getInstance()->db();
        $today = date('Y-m-d');

        $where = "`is_active` = 1 AND `effective_from` <= ? AND `effective_to` >= ?";
        $params = [$today, $today];

        if ($branchId !== null) {
            $where .= " AND (`branch_id` IS NULL OR `branch_id` = ?)";
            $params[] = $branchId;
        }

        return $db->select(
            "SELECT * FROM `board_offers` WHERE {$where} ORDER BY `branch_id` DESC, `effective_from` DESC",
            $params
        );
    }

    public static function getBestOffer(?int $branchId = null): ?array
    {
        $offers = self::getActiveOffers($branchId);
        if (empty($offers)) {
            return null;
        }
        // Branch-specific first (branch_id DESC puts non-null first)
        return $offers[0];
    }

    public static function getCashDiscount(string $amount, ?array $offer = null): array
    {
        if ($offer === null) {
            $offer = self::getBestOffer();
        }

        if (!$offer || !$offer['cash_discount_type'] || !$offer['cash_discount_value']) {
            return [
                'original'   => $amount,
                'discounted' => $amount,
                'savings'    => '0.00',
                'type'       => null,
                'value'      => null,
                'offer'      => null,
            ];
        }

        $savings = '0.00';
        if ($offer['cash_discount_type'] === 'percentage') {
            $savings = bcdiv(bcmul($amount, (string) $offer['cash_discount_value'], 4), '100', 2);
        } else {
            $savings = (string) $offer['cash_discount_value'];
            if (bccomp($savings, $amount, 2) > 0) {
                $savings = $amount;
            }
        }

        $discounted = bcsub($amount, $savings, 2);
        if (bccomp($discounted, '0', 2) < 0) {
            $discounted = '0.00';
        }

        return [
            'original'   => $amount,
            'discounted' => $discounted,
            'savings'    => $savings,
            'type'       => $offer['cash_discount_type'],
            'value'      => $offer['cash_discount_value'],
            'offer'      => $offer,
        ];
    }

    public static function getInstallmentTerms(?array $offer = null): array
    {
        $interestData = RuleEngine::get('INSTALLMENT_INTEREST_RATE');
        $minDownData = RuleEngine::get('INSTALLMENT_MIN_DOWN_PAYMENT');
        $maxMonthsData = RuleEngine::get('INSTALLMENT_MAX_MONTHS');

        $defaults = [
            'down_pct'         => $minDownData['percentage'] ?? '25.00',
            'max_months'       => (int) ($maxMonthsData['months'] ?? 30),
            'interest_rate'    => $interestData['percentage'] ?? '22.00',
            'grace_type'       => null,
            'grace_months'     => 0,
            'post_grace_rate'  => null,
            'offer'            => null,
        ];

        if (!$offer) {
            return $defaults;
        }

        $terms = $defaults;
        $terms['offer'] = $offer;

        if ($offer['inst_down_payment_pct'] !== null) {
            $terms['down_pct'] = (string) $offer['inst_down_payment_pct'];
        }
        if ($offer['inst_months'] !== null) {
            $terms['max_months'] = (int) $offer['inst_months'];
        }
        if ($offer['inst_interest_rate'] !== null) {
            $terms['interest_rate'] = (string) $offer['inst_interest_rate'];
        }
        if ($offer['inst_grace_type'] !== null) {
            $terms['grace_type'] = $offer['inst_grace_type'];
            $terms['grace_months'] = (int) $offer['inst_grace_months'];
        }
        if ($offer['inst_post_grace_rate'] !== null) {
            $terms['post_grace_rate'] = (string) $offer['inst_post_grace_rate'];
        }

        return $terms;
    }

    public static function getInstallmentOverrides(): array
    {
        $offer = self::getBestOffer();
        if (!$offer) {
            return [];
        }

        $overrides = [];
        if ($offer['inst_months'] !== null) {
            $overrides['max_months'] = (int) $offer['inst_months'];
        }
        if ($offer['inst_interest_rate'] !== null) {
            $overrides['interest_rate'] = (string) $offer['inst_interest_rate'];
        }
        if ($offer['inst_down_payment_pct'] !== null) {
            $overrides['min_down_pct'] = (string) $offer['inst_down_payment_pct'];
        }
        if ($offer['inst_grace_type'] !== null) {
            $overrides['grace_type'] = $offer['inst_grace_type'];
            $overrides['grace_months'] = (int) $offer['inst_grace_months'];
            if ($offer['inst_post_grace_rate'] !== null) {
                $overrides['post_grace_rate'] = (string) $offer['inst_post_grace_rate'];
            }
        }

        $overrides['offer'] = $offer;
        return $overrides;
    }

    public static function snapshotOffer(array $offer): string
    {
        return json_encode([
            'id'                    => $offer['id'],
            'title_ar'              => $offer['title_ar'],
            'cash_discount_type'    => $offer['cash_discount_type'],
            'cash_discount_value'   => $offer['cash_discount_value'],
            'inst_down_payment_pct' => $offer['inst_down_payment_pct'],
            'inst_months'           => $offer['inst_months'],
            'inst_interest_rate'    => $offer['inst_interest_rate'],
            'inst_grace_type'       => $offer['inst_grace_type'],
            'inst_grace_months'     => $offer['inst_grace_months'],
            'inst_post_grace_rate'  => $offer['inst_post_grace_rate'],
            'effective_from'        => $offer['effective_from'],
            'effective_to'          => $offer['effective_to'],
        ], JSON_UNESCAPED_UNICODE);
    }

    public static function restoreFromSnapshot(string $json): ?array
    {
        $data = json_decode($json, true);
        if (!is_array($data)) {
            return null;
        }
        return $data;
    }
}
