<?php
declare(strict_types=1);

namespace App\Modules\Waiver\Services;

use App\Core\App;
use App\Core\EventBus;
use App\Core\Logger;
use App\Modules\Archive\Services\ArchiveService;

final class WaiverProcessor
{
    public static function execute(int $waiverId): array
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        $waiver = $db->selectOne("SELECT * FROM waiver_requests WHERE id = ?", [$waiverId]);
        if (!$waiver || !in_array($waiver['status'], ['approved', 'fee_paid'])) {
            return ['success' => false, 'error' => 'طلب التنازل غير صالح أو غير مُعتمد'];
        }

        if (!$waiver['target_member_id']) {
            return ['success' => false, 'error' => 'لم يتم تحديد العضو المستفيد'];
        }

        $sourceMember = $db->selectOne("SELECT * FROM members WHERE id = ?", [(int) $waiver['source_member_id']]);
        if (!$sourceMember) return ['success' => false, 'error' => 'العضو المصدر غير موجود'];

        $targetMember = $db->selectOne("SELECT * FROM members WHERE id = ?", [(int) $waiver['target_member_id']]);
        if (!$targetMember) return ['success' => false, 'error' => 'العضو المستفيد غير موجود'];

        $db->beginTransaction();
        try {
            $snapshotId = ArchiveService::takeSnapshot('members', (int) $sourceMember['id'], 'waiver', 'تنازل — طلب #' . $waiverId);

            // Archive source member FIRST (release number to avoid unique constraint violation)
            $db->update('members', [
                'membership_number' => null,
                'status'            => 'waived',
                'is_archived'       => 1,
                'archived_at'       => date('Y-m-d H:i:s'),
                'archived_by'       => $employee ? (int) $employee->id : null,
                'updated_at'        => date('Y-m-d H:i:s'),
            ], '`id` = ?', [(int) $waiver['source_member_id']]);

            // Transfer membership number to target — becomes the new primary member
            $db->update('members', [
                'membership_number' => $waiver['membership_number'],
                'status'            => 'active',
                'membership_type'   => $sourceMember['membership_type'] ?? 'working',
                'updated_at'        => date('Y-m-d H:i:s'),
            ], '`id` = ?', [(int) $waiver['target_member_id']]);

            ArchiveService::recordNumberTransfer($waiver['membership_number'], 'waiver', 'members', (int) $waiver['target_member_id']);

            $db->update('waiver_requests', [
                'archive_snapshot_id' => $snapshotId,
                'status'              => 'completed',
                'updated_at'          => date('Y-m-d H:i:s'),
            ], '`id` = ?', [$waiverId]);

            $db->commit();

            EventBus::dispatch('waiver.completed', [
                'waiver_id'        => $waiverId,
                'source_member_id' => (int) $waiver['source_member_id'],
                'target_member_id' => (int) $waiver['target_member_id'],
                'membership_number'=> $waiver['membership_number'],
                'fee_amount'       => $waiver['waiver_fee_amount'] ?? '0.00',
                'fee_percentage'   => $waiver['waiver_fee_percentage'] ?? '30',
            ]);

            return ['success' => true, 'snapshot_id' => $snapshotId];
        } catch (\Throwable $e) {
            $db->rollBack();
            Logger::error("Waiver failed: " . $e->getMessage());
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }

    /**
     * Check all financial obligations for a member.
     * Returns ['clear' => bool, 'debts' => [...details...]]
     */
    public static function checkDebts(int $memberId): array
    {
        $db = App::getInstance()->db();
        $debts = [];

        // Unpaid subscriptions
        $unpaidSubs = $db->selectOne(
            "SELECT COUNT(*) as cnt, COALESCE(SUM(total_amount - paid_amount + fine_amount), 0) as total
             FROM subscriptions WHERE member_id = ? AND status IN ('pending','overdue')",
            [$memberId]
        );
        if ((int) ($unpaidSubs['cnt'] ?? 0) > 0) {
            $debts[] = [
                'type' => 'اشتراكات سنوية',
                'count' => (int) $unpaidSubs['cnt'],
                'amount' => $unpaidSubs['total'] ?? '0.00',
            ];
        }

        // Unpaid fines
        $unpaidFines = $db->selectOne(
            "SELECT COUNT(*) as cnt, COALESCE(SUM(amount - paid_amount), 0) as total
             FROM fines WHERE member_id = ? AND status = 'pending'",
            [$memberId]
        );
        if ((int) ($unpaidFines['cnt'] ?? 0) > 0) {
            $debts[] = [
                'type' => 'غرامات',
                'count' => (int) $unpaidFines['cnt'],
                'amount' => $unpaidFines['total'] ?? '0.00',
            ];
        }

        // Unpaid payment requests (cashier queue)
        $unpaidRequests = $db->selectOne(
            "SELECT COUNT(*) as cnt, COALESCE(SUM(amount), 0) as total
             FROM payment_requests WHERE member_id = ? AND status = 'pending' AND is_voided = 0",
            [$memberId]
        );
        if ((int) ($unpaidRequests['cnt'] ?? 0) > 0) {
            $debts[] = [
                'type' => 'طلبات دفع معلقة',
                'count' => (int) $unpaidRequests['cnt'],
                'amount' => $unpaidRequests['total'] ?? '0.00',
            ];
        }

        $totalDebt = '0.00';
        foreach ($debts as $d) {
            $totalDebt = bcadd($totalDebt, (string) $d['amount'], 2);
        }

        return [
            'clear' => empty($debts),
            'debts' => $debts,
            'total' => $totalDebt,
        ];
    }

    /**
     * Count dependents for a member (spouses + children + temporary).
     */
    public static function countDependents(int $memberId): array
    {
        $db = App::getInstance()->db();
        $spouses = (int) ($db->selectOne("SELECT COUNT(*) as cnt FROM spouses WHERE member_id = ? AND is_archived = 0", [$memberId])['cnt'] ?? 0);
        $children = (int) ($db->selectOne("SELECT COUNT(*) as cnt FROM children WHERE member_id = ? AND is_archived = 0", [$memberId])['cnt'] ?? 0);
        $temps = (int) ($db->selectOne("SELECT COUNT(*) as cnt FROM temporary_members WHERE member_id = ? AND is_archived = 0", [$memberId])['cnt'] ?? 0);

        return [
            'spouses' => $spouses,
            'children' => $children,
            'temporary' => $temps,
            'total' => $spouses + $children + $temps,
        ];
    }
}
