<?php
declare(strict_types=1);

namespace App\Modules\Members\Services;

use App\Core\App;

/**
 * Handles automatic freezing of male children who reach age 25,
 * subscription blocking checks, and carnet printing eligibility.
 */
final class AutoFreezeService
{
    /**
     * Process automatic freeze for male children aged 25+.
     * Sets is_frozen = 1 with reason indicating they must convert to independent membership.
     *
     * @return array{frozen_count: int, processed: int}
     */
    public static function processAutoFreeze(): array
    {
        $db = App::getInstance()->db();

        $children = $db->select(
            "SELECT id, date_of_birth FROM children
             WHERE is_archived = 0
               AND status = 'active'
               AND date_of_birth IS NOT NULL"
        );

        $processed = count($children);
        $separatedCount = 0;
        $now = date('Y-m-d H:i:s');
        $today = new \DateTimeImmutable('today');

        foreach ($children as $child) {
            $dob = new \DateTimeImmutable($child['date_of_birth']);
            $age = (int) $dob->diff($today)->y;

            if ($age >= 25) {
                $db->update(
                    'children',
                    [
                        'status'         => 'separated',
                        'classification' => 'separated',
                        'is_frozen'      => 1,
                        'frozen_at'      => $now,
                        'frozen_reason'  => 'فصل وجوبي — بلوغ سن 25',
                    ],
                    'id = ?',
                    [$child['id']]
                );
                $separatedCount++;
            }
        }

        return [
            'separated_count' => $separatedCount,
            'processed'       => $processed,
        ];
    }

    /**
     * Check if a member has unpaid subscriptions for the current financial year.
     * Blocks certain operations if annual subscription is not paid.
     *
     * @return array{blocked: bool, reason?: string, unpaid_amount?: string}
     */
    public static function checkSubscriptionBlock(int $memberId): array
    {
        $db = App::getInstance()->db();

        $financialYear = self::getCurrentFinancialYear();

        $unpaid = $db->select(
            "SELECT total_amount, paid_amount FROM subscriptions
             WHERE member_id = ?
               AND financial_year = ?
               AND status IN ('pending', 'overdue')",
            [$memberId, $financialYear]
        );

        if (!empty($unpaid)) {
            $unpaidAmount = '0.00';
            foreach ($unpaid as $row) {
                $remaining = bcsub($row['total_amount'], $row['paid_amount'], 2);
                $unpaidAmount = bcadd($unpaidAmount, $remaining, 2);
            }

            return [
                'blocked'       => true,
                'reason'        => 'لم يتم سداد الاشتراك السنوي',
                'unpaid_amount' => $unpaidAmount,
            ];
        }

        return ['blocked' => false];
    }

    /**
     * Check if a member is eligible to print their carnet (membership card).
     * Blocked if subscription unpaid, member is suspended, or member is frozen.
     *
     * @return array{allowed: bool, reason?: string}
     */
    public static function canPrintCarnet(int $memberId): array
    {
        $db = App::getInstance()->db();

        // Check member status
        $member = $db->selectOne(
            "SELECT status FROM members WHERE id = ? AND is_archived = 0",
            [$memberId]
        );

        if (!$member) {
            return [
                'allowed' => false,
                'reason'  => 'العضو غير موجود',
            ];
        }

        if ($member['status'] === 'suspended') {
            return [
                'allowed' => false,
                'reason'  => 'العضوية موقوفة',
            ];
        }

        if ($member['status'] === 'frozen') {
            return [
                'allowed' => false,
                'reason'  => 'العضوية مجمدة',
            ];
        }

        // Check subscription block
        $subscriptionCheck = self::checkSubscriptionBlock($memberId);
        if ($subscriptionCheck['blocked']) {
            return [
                'allowed' => false,
                'reason'  => $subscriptionCheck['reason'],
            ];
        }

        return ['allowed' => true];
    }

    /**
     * Freeze temporary members who have reached their age limit.
     * Categories: sisters@25, stepchildren@25, orphans@25
     */
    public static function freezeTemporaryAtAgeLimit(): array
    {
        $db = App::getInstance()->db();
        $today = new \DateTimeImmutable('today');
        $now = date('Y-m-d H:i:s');
        $frozenCount = 0;

        $ageLimitCategories = ['sisters_under_25', 'stepchildren_under_25', 'orphan_sponsored'];

        $temps = $db->select(
            "SELECT id, date_of_birth, category FROM temporary_members
             WHERE is_archived = 0
               AND status = 'active'
               AND category IN ('" . implode("','", $ageLimitCategories) . "')
               AND date_of_birth IS NOT NULL"
        );

        foreach ($temps as $temp) {
            $dob = new \DateTimeImmutable($temp['date_of_birth']);
            $age = (int) $dob->diff($today)->y;

            if ($age >= 25) {
                $db->update(
                    'temporary_members',
                    [
                        'status'     => 'expired',
                        'updated_at' => $now,
                    ],
                    'id = ?',
                    [$temp['id']]
                );
                $frozenCount++;
            }
        }

        return ['expired_count' => $frozenCount];
    }

    /**
     * Flag honorary memberships that have passed their 1-year term without renewal.
     */
    public static function flagHonoraryExpiry(): array
    {
        $db = App::getInstance()->db();
        $now = date('Y-m-d H:i:s');
        $expiredCount = 0;

        $expired = $db->select(
            "SELECT hm.id, hm.member_id FROM honorary_members hm
             JOIN members m ON m.id = hm.member_id AND m.is_archived = 0 AND m.status = 'active'
             WHERE hm.end_date < CURDATE() AND hm.is_archived = 0"
        );

        foreach ($expired as $hm) {
            $db->update('members', ['status' => 'expired', 'updated_at' => $now], 'id = ?', [(int) $hm['member_id']]);
            $expiredCount++;
        }

        return ['expired_count' => $expiredCount];
    }

    /**
     * Report children within 6 months of reaching transfer-required age (25 for males).
     */
    public static function getChildrenNearingThreshold(): array
    {
        $db = App::getInstance()->db();
        $today = new \DateTimeImmutable('today');
        $sixMonthsLater = $today->modify('+6 months');

        $children = $db->select(
            "SELECT c.id, c.full_name_ar, c.date_of_birth, c.gender, c.member_id, m.full_name_ar as parent_name
             FROM children c
             JOIN members m ON m.id = c.member_id AND m.is_archived = 0
             WHERE c.gender = 'male'
               AND c.is_frozen = 0
               AND c.is_archived = 0
               AND c.status = 'active'
               AND c.date_of_birth IS NOT NULL"
        );

        $nearThreshold = [];
        foreach ($children as $child) {
            $dob = new \DateTimeImmutable($child['date_of_birth']);
            $ageAtCheck = (int) $dob->diff($sixMonthsLater)->y;
            $currentAge = (int) $dob->diff($today)->y;

            if ($currentAge < 25 && $ageAtCheck >= 25) {
                $turnsDate = $dob->modify('+25 years')->format('Y-m-d');
                $nearThreshold[] = [
                    'child_id'    => (int) $child['id'],
                    'name'        => $child['full_name_ar'],
                    'parent_name' => $child['parent_name'],
                    'member_id'   => (int) $child['member_id'],
                    'current_age' => $currentAge,
                    'turns_25_on' => $turnsDate,
                ];
            }
        }

        return $nearThreshold;
    }

    /**
     * Get current financial year string.
     * FY runs July to June: if month >= 7, FY is "thisYear/thisYear+1", else "lastYear/thisYear".
     */
    private static function getCurrentFinancialYear(): string
    {
        $month = (int) date('n');
        $year = (int) date('Y');

        if ($month >= 7) {
            return $year . '/' . ($year + 1);
        }

        return ($year - 1) . '/' . $year;
    }
}
