<?php
declare(strict_types=1);

namespace App\Modules\Subscriptions\Services;

use App\Core\App;
use App\Core\EventBus;
use App\Core\Logger;

final class OverdueFineApplicator
{
    public static function run(): array
    {
        $db = App::getInstance()->db();

        $currentFY = self::currentFinancialYear();
        $results = ['fines_applied' => 0, 'members_dropped' => 0, 'errors' => []];

        $members = $db->select(
            "SELECT DISTINCT s.member_id
             FROM subscriptions s
             JOIN members m ON m.id = s.member_id AND m.is_archived = 0 AND m.status = 'active'
             WHERE s.status IN ('pending','overdue') AND s.financial_year < ?",
            [$currentFY]
        );

        foreach ($members as $row) {
            $memberId = (int) $row['member_id'];
            try {
                $calc = SubscriptionCalculator::calculateLateFine($memberId, $currentFY);

                foreach ($calc['details'] as $detail) {
                    if (($detail['in_grace'] ?? false)) continue;

                    $db->query(
                        "UPDATE subscriptions SET fine_amount = ?, status = 'overdue', updated_at = NOW()
                         WHERE member_id = ? AND financial_year = ? AND status IN ('pending','overdue')",
                        [$detail['fine_amount'], $memberId, $detail['financial_year']]
                    );
                }

                if (bccomp($calc['total_fine'], '0', 2) > 0) {
                    $results['fines_applied']++;
                }

                if ($calc['should_drop']) {
                    $db->query(
                        "UPDATE members SET status = 'dropped', updated_at = NOW() WHERE id = ? AND status = 'active'",
                        [$memberId]
                    );
                    $results['members_dropped']++;

                    EventBus::dispatch('member.dropped', [
                        'member_id'   => $memberId,
                        'reason'      => 'تأخر عن سداد الاشتراك السنوي ' . $calc['years_overdue'] . ' سنوات متتالية',
                        'years_unpaid' => $calc['years_unpaid'],
                    ]);

                    Logger::info("Member dropped for non-payment", [
                        'member_id' => $memberId,
                        'years'     => $calc['years_overdue'],
                    ]);
                }
            } catch (\Throwable $e) {
                $results['errors'][] = "Member #{$memberId}: " . $e->getMessage();
                Logger::error("OverdueFineApplicator error", ['member_id' => $memberId, 'error' => $e->getMessage()]);
            }
        }

        return $results;
    }

    public static function expireReinstatements(): array
    {
        $db = App::getInstance()->db();
        $results = ['expired' => 0];

        $windowData = \App\Modules\Rules\Services\RuleEngine::get('REINSTATEMENT_WINDOW');
        $windowMonths = (int) ($windowData['months'] ?? 12);

        $expired = $db->select(
            "SELECT id, full_name_ar FROM members
             WHERE status = 'dropped'
               AND updated_at < DATE_SUB(NOW(), INTERVAL ? MONTH)
               AND status != 'permanently_dropped'",
            [$windowMonths]
        );

        foreach ($expired as $m) {
            $db->query(
                "UPDATE members SET status = 'permanently_dropped', updated_at = NOW() WHERE id = ?",
                [(int) $m['id']]
            );
            $results['expired']++;

            EventBus::dispatch('member.permanently_dropped', [
                'member_id' => (int) $m['id'],
                'reason'    => 'انتهاء مهلة إعادة العضوية (' . $windowMonths . ' شهر) بعد إسقاط العضوية',
            ]);
        }

        return $results;
    }

    private static function currentFinancialYear(): string
    {
        $month = (int) date('n');
        $year = (int) date('Y');
        return $month >= 7 ? $year . '/' . ($year + 1) : ($year - 1) . '/' . $year;
    }
}
