<?php
declare(strict_types=1);

namespace App\Modules\Transfers\Services;

use App\Core\App;
use App\Modules\Rules\Services\RuleEngine;
use App\Modules\Pricing\Services\PricingEngine;
use App\Modules\ServiceCatalog\Models\ServicePrice;

final class SeparationFeeCalculator
{
    /**
     * Calculate separation/transfer fee based on years since acquisition.
     */
    public static function calculate(int $sourceMemberId, ?int $childId = null, ?string $qualificationCode = null): array
    {
        $db = App::getInstance()->db();
        $member = $db->selectOne("SELECT * FROM members WHERE id = ?", [$sourceMemberId]);
        if (!$member) {
            return ['error' => 'العضو غير موجود', 'success' => false];
        }

        // Determine qualification code
        if ($qualificationCode === null && !empty($member['qualification_id'])) {
            $qual = $db->selectOne("SELECT code FROM qualifications WHERE id = ?", [(int) $member['qualification_id']]);
            $qualificationCode = $qual['code'] ?? null;
        }

        // Get new membership value at current date from pricing_configs
        $branchId = (int) ($member['branch_id'] ?? 1);
        $mType = $member['membership_type'] ?? 'working';
        $newMembershipValue = '0.00';

        if ($qualificationCode) {
            $priceInfo = PricingEngine::getMembershipPrice($branchId, $qualificationCode);
            $newMembershipValue = $priceInfo['price'] ?? '0.00';
        }

        // Fallback: query pricing_configs directly (handles NULL qualification or membership_type mismatch)
        if (bccomp($newMembershipValue, '0.01', 2) < 0) {
            $qualId = !empty($member['qualification_id']) ? (int) $member['qualification_id'] : null;
            if ($qualId) {
                $pricing = $db->selectOne(
                    "SELECT price FROM pricing_configs WHERE branch_id = ? AND qualification_id = ? AND membership_type = ? AND is_active = 1 AND effective_from <= CURDATE() AND (effective_to IS NULL OR effective_to >= CURDATE()) ORDER BY effective_from DESC LIMIT 1",
                    [$branchId, $qualId, $mType]
                );
            } else {
                $pricing = $db->selectOne(
                    "SELECT price FROM pricing_configs WHERE branch_id = ? AND membership_type = ? AND is_active = 1 AND effective_from <= CURDATE() AND (effective_to IS NULL OR effective_to >= CURDATE()) ORDER BY price ASC LIMIT 1",
                    [$branchId, $mType]
                );
            }
            if ($pricing && bccomp($pricing['price'], '0.01', 2) >= 0) {
                $newMembershipValue = $pricing['price'];
            }
        }

        // Calculate years since acquisition
        $acquisitionDate = $member['created_at'] ?? $member['form_date'] ?? date('Y-m-d');
        $yearsSince = self::calculateYearsSince($acquisitionDate);

        // Get fee percentage based on years
        $feePercentage = self::getFeePercentageByYear($yearsSince);

        // Calculate separation fee
        $separationFee = bcdiv(bcmul($newMembershipValue, (string) $feePercentage, 4), '100', 2);

        // Form fee
        $formFeeData = RuleEngine::get('FORM_TRANSFER_FEE');
        $formFee = $formFeeData['amount'] ?? '570.00';

        // Annual subscription (basic member subscription)
        $annualSub = ServicePrice::getPrice('SVC_ANNUAL_MEMBER', '492.00');
        $devFeeData = RuleEngine::get('DEVELOPMENT_FEE');
        $devFee = $devFeeData['amount'] ?? '35.00';
        $annualSubscriptionFee = bcadd($annualSub, $devFee, 2);

        $totalFee = bcadd(bcadd($separationFee, $formFee, 2), $annualSubscriptionFee, 2);

        return [
            'success'                => true,
            'source_member_id'       => $sourceMemberId,
            'child_id'               => $childId,
            'qualification_code'     => $qualificationCode,
            'new_membership_value'   => $newMembershipValue,
            'years_since_acquisition'=> $yearsSince,
            'fee_percentage'         => $feePercentage,
            'separation_fee'         => $separationFee,
            'form_fee'               => $formFee,
            'annual_subscription_fee'=> $annualSubscriptionFee,
            'total_fee'              => $totalFee,
            'acquisition_date'       => $acquisitionDate,
        ];
    }

    public static function calculateYearsSince(string $date): int
    {
        $then = new \DateTime(substr($date, 0, 10));
        $now = new \DateTime();
        $diff = $now->diff($then);
        return max(1, $diff->y + ($diff->m > 0 || $diff->d > 0 ? 1 : 0)); // partial year rounds up
    }

    public static function calculateAcquiredMemberChildFee(int $childAge, string $membershipValue): array
    {
        if ($childAge < 12) {
            $ruleCode = 'DIVORCE_CHILD_UNDER_12';
        } elseif ($childAge < 16) {
            $ruleCode = 'DIVORCE_CHILD_12_TO_16';
        } elseif ($childAge < 18) {
            $ruleCode = 'DIVORCE_CHILD_16_TO_18';
        } else {
            $ruleCode = 'DIVORCE_CHILD_OVER_18';
        }

        $data = RuleEngine::get($ruleCode);
        $percentage = $data['percentage'] ?? '30.00';
        $fee = bcdiv(bcmul($membershipValue, $percentage, 4), '100', 2);

        return [
            'age' => $childAge,
            'rule_code' => $ruleCode,
            'percentage' => $percentage,
            'fee' => $fee,
            'membership_value' => $membershipValue,
        ];
    }

    public static function getFeePercentageByYear(int $year): string
    {
        $ruleMap = [
            1 => 'SEPARATION_FEE_YEAR_1',
            2 => 'SEPARATION_FEE_YEAR_2',
            3 => 'SEPARATION_FEE_YEAR_3',
            4 => 'SEPARATION_FEE_YEAR_4',
            5 => 'SEPARATION_FEE_YEAR_5',
        ];

        $ruleCode = $ruleMap[min($year, 5)] ?? 'SEPARATION_FEE_YEAR_6_PLUS';
        if ($year > 5) {
            $ruleCode = 'SEPARATION_FEE_YEAR_6_PLUS';
        }

        $data = RuleEngine::require($ruleCode);
        return $data['percentage'];
    }

    /**
     * Calculate surcharge when new owner has more companions than the original member.
     * Uses the EXACT same tiered fee logic as adding a brand-new spouse/child:
     * - Extra spouses are charged per their ordinal position (2nd/3rd/4th wife rules)
     * - Extra children are charged per their ordinal position via PricingEngine
     */
    public static function calculateCompanionSurcharge(
        int $sourceMemberId,
        int $targetSpousesCount,
        int $targetChildrenCount,
        array $targetChildrenAges = []
    ): array {
        $db = App::getInstance()->db();
        $member = $db->selectOne("SELECT * FROM members WHERE id = ?", [$sourceMemberId]);
        if (!$member) {
            return ['surcharge' => '0.00', 'breakdown' => [], 'source_count' => 0, 'target_count' => 0];
        }

        $sourceSpouses = (int) $db->selectOne(
            "SELECT COUNT(*) as cnt FROM spouses WHERE member_id = ? AND is_archived = 0 AND status = 'active'",
            [$sourceMemberId]
        )['cnt'];

        $sourceChildren = (int) $db->selectOne(
            "SELECT COUNT(*) as cnt FROM children WHERE member_id = ? AND is_archived = 0 AND status = 'active'",
            [$sourceMemberId]
        )['cnt'];

        $sourceTotal = $sourceSpouses + $sourceChildren;
        $targetTotal = $targetSpousesCount + $targetChildrenCount;
        $breakdown = [];
        $surcharge = '0.00';

        // Use current pricing (same logic as calculate())
        $branchId = (int) ($member['branch_id'] ?? 1);
        $mType = $member['membership_type'] ?? 'working';
        $membershipValue = $member['membership_value'] ?? '0.00';
        $qualId = !empty($member['qualification_id']) ? (int) $member['qualification_id'] : null;
        if ($qualId) {
            $currentPricing = $db->selectOne(
                "SELECT price FROM pricing_configs WHERE branch_id = ? AND qualification_id = ? AND membership_type = ? AND is_active = 1 AND effective_from <= CURDATE() AND (effective_to IS NULL OR effective_to >= CURDATE()) ORDER BY effective_from DESC LIMIT 1",
                [$branchId, $qualId, $mType]
            );
        } else {
            $currentPricing = $db->selectOne(
                "SELECT price FROM pricing_configs WHERE branch_id = ? AND membership_type = ? AND is_active = 1 AND effective_from <= CURDATE() AND (effective_to IS NULL OR effective_to >= CURDATE()) ORDER BY price ASC LIMIT 1",
                [$branchId, $mType]
            );
        }
        if ($currentPricing && bccomp($currentPricing['price'], '0.01', 2) >= 0) {
            $membershipValue = $currentPricing['price'];
        }

        // Extra spouses: use tiered rules per ordinal position
        $extraSpouses = max(0, $targetSpousesCount - $sourceSpouses);
        if ($extraSpouses > 0) {
            for ($i = 0; $i < $extraSpouses; $i++) {
                $spouseOrder = $sourceSpouses + $i + 1;
                $feeForOrder = self::getSpouseFeeByOrder($spouseOrder, $membershipValue);
                $surcharge = bcadd($surcharge, $feeForOrder['fee'], 2);
                $breakdown[] = [
                    'type'       => 'extra_spouse',
                    'order'      => $spouseOrder,
                    'label'      => $feeForOrder['label'],
                    'percentage' => $feeForOrder['percentage'],
                    'fee'        => $feeForOrder['fee'],
                ];
            }
        }

        // Extra children: use tiered rules per ordinal position and age
        $extraChildren = max(0, $targetChildrenCount - $sourceChildren);
        if ($extraChildren > 0) {
            for ($i = 0; $i < $extraChildren; $i++) {
                $childOrder = $sourceChildren + $i + 1;
                $childAge = $targetChildrenAges[$i] ?? 10;
                $feeForOrder = self::getChildFeeByOrder($childOrder, $childAge, $membershipValue);
                $surcharge = bcadd($surcharge, $feeForOrder['fee'], 2);
                $breakdown[] = [
                    'type'       => 'extra_child',
                    'order'      => $childOrder,
                    'age'        => $childAge,
                    'label'      => $feeForOrder['label'],
                    'percentage' => $feeForOrder['percentage'],
                    'fee'        => $feeForOrder['fee'],
                ];
            }
        }

        return [
            'surcharge'      => $surcharge,
            'breakdown'      => $breakdown,
            'source_count'   => $sourceTotal,
            'target_count'   => $targetTotal,
            'extra_spouses'  => $extraSpouses,
            'extra_children' => $extraChildren,
        ];
    }

    /**
     * Get the addition fee for a spouse at a specific ordinal position.
     * Uses the same rule codes as SpouseFeeCalculator.
     */
    private static function getSpouseFeeByOrder(int $order, string $membershipValue): array
    {
        switch (true) {
            case ($order <= 1):
                $data = RuleEngine::require('SPOUSE_BASE_MEMBER_FEE');
                $pct = $data['percentage'];
                $label = 'الزوجة الأولى — ' . $pct . '%';
                break;
            case ($order === 2):
                $data = RuleEngine::require('SPOUSE_2ND_FEE');
                $pct = $data['percentage'];
                $label = 'الزوجة الثانية — ' . $pct . '%';
                break;
            case ($order === 3):
                $data = RuleEngine::require('SPOUSE_3RD_FEE');
                $pct = $data['percentage'];
                $label = 'الزوجة الثالثة — ' . $pct . '%';
                break;
            default:
                $data = RuleEngine::require('SPOUSE_4TH_FEE');
                $pct = $data['percentage'];
                $label = 'الزوجة الرابعة+ — ' . $pct . '%';
                break;
        }

        $fee = bcdiv(bcmul($membershipValue, $pct, 4), '100', 2);
        return ['fee' => $fee, 'percentage' => $pct, 'label' => $label];
    }

    /**
     * Get the addition fee for a child at a specific ordinal position and age.
     * Uses PricingEngine::calculateChildFee (same logic as ChildFeeCalculator).
     */
    private static function getChildFeeByOrder(int $order, int $age, string $membershipValue): array
    {
        $feeResult = PricingEngine::calculateChildFee($membershipValue, $age, $order);
        $fee = $feeResult['fee'] ?? '0.00';
        $pct = $feeResult['percentage'] ?? '0.00';
        $label = 'الابن/الابنة رقم ' . $order . ' (سن ' . $age . ') — ' . $pct . '%';

        return ['fee' => $fee, 'percentage' => $pct, 'label' => $label];
    }
}