<?php
declare(strict_types=1);

namespace App\Modules\Treasury\Services;

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

final class SettlementService
{
    public static function initiateSettlement(int $sessionId): array
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        $session = $db->selectOne(
            "SELECT * FROM treasury_sessions WHERE id = ? AND status = 'closed'",
            [$sessionId]
        );
        if (!$session) {
            return ['success' => false, 'error' => 'الوردية غير موجودة أو لم تُغلق بعد'];
        }

        $existingSettlement = $db->selectOne(
            "SELECT id FROM treasury_settlements WHERE session_id = ? AND status != 'rejected'",
            [$sessionId]
        );
        if ($existingSettlement) {
            return ['success' => false, 'error' => 'تم إجراء تسوية لهذه الوردية بالفعل'];
        }

        $amount = (string) $session['total_collected'];
        if (bccomp($amount, '0.01', 2) < 0) {
            return ['success' => false, 'error' => 'لا يوجد مبلغ للتسوية'];
        }

        $mainTreasury = $db->selectOne("SELECT id FROM treasuries WHERE type = 'main' AND is_active = 1 LIMIT 1");
        if (!$mainTreasury) {
            return ['success' => false, 'error' => 'لم يتم تعريف الخزنة الرئيسية'];
        }

        $receiptCount = (int) $session['total_receipts'];
        $settlementNumber = self::generateSettlementNumber($db);
        $now = date('Y-m-d H:i:s');

        $id = $db->insert('treasury_settlements', [
            'settlement_number' => $settlementNumber,
            'from_treasury_id'  => (int) $session['treasury_id'],
            'to_treasury_id'    => (int) $mainTreasury['id'],
            'session_id'        => $sessionId,
            'amount'            => $amount,
            'settled_by'        => $employee ? (int) $employee->id : 0,
            'settled_at'        => $now,
            'status'            => 'pending',
            'receipt_count'     => $receiptCount,
            'created_at'        => $now,
            'updated_at'        => $now,
        ]);

        $db->update('treasury_sessions', [
            'status'     => 'settled',
            'updated_at' => $now,
        ], '`id` = ?', [$sessionId]);

        CustodyService::recordSettlementOut(
            (int) $session['treasury_id'],
            (int) $session['cashier_id'],
            $amount,
            $id
        );

        EventBus::dispatch('treasury.settlement.initiated', [
            'settlement_id'   => $id,
            'from_treasury_id' => (int) $session['treasury_id'],
            'to_treasury_id'   => (int) $mainTreasury['id'],
            'amount'           => $amount,
            'session_id'       => $sessionId,
        ]);

        Logger::info("Treasury settlement initiated", ['id' => $id, 'amount' => $amount, 'session' => $sessionId]);

        return [
            'success'           => true,
            'settlement_id'     => $id,
            'settlement_number' => $settlementNumber,
            'amount'            => $amount,
        ];
    }

    public static function receiveSettlement(int $settlementId, int $receivedBy): array
    {
        $db = App::getInstance()->db();

        $settlement = $db->selectOne(
            "SELECT * FROM treasury_settlements WHERE id = ? AND status = 'pending'",
            [$settlementId]
        );
        if (!$settlement) {
            return ['success' => false, 'error' => 'التسوية غير موجودة أو تمت معالجتها'];
        }

        $now = date('Y-m-d H:i:s');
        $db->update('treasury_settlements', [
            'received_by' => $receivedBy,
            'received_at' => $now,
            'status'      => 'received',
            'updated_at'  => $now,
        ], '`id` = ?', [$settlementId]);

        CustodyService::recordSettlementIn(
            (int) $settlement['to_treasury_id'],
            $receivedBy,
            (string) $settlement['amount'],
            $settlementId
        );

        EventBus::dispatch('treasury.settlement.received', [
            'settlement_id'    => $settlementId,
            'from_treasury_id' => (int) $settlement['from_treasury_id'],
            'to_treasury_id'   => (int) $settlement['to_treasury_id'],
            'amount'           => (string) $settlement['amount'],
            'received_by'      => $receivedBy,
        ]);

        Logger::info("Treasury settlement received", ['id' => $settlementId, 'amount' => $settlement['amount']]);

        return ['success' => true, 'amount' => (string) $settlement['amount']];
    }

    public static function rejectSettlement(int $settlementId, int $rejectedBy, string $reason): array
    {
        $db = App::getInstance()->db();

        $settlement = $db->selectOne(
            "SELECT * FROM treasury_settlements WHERE id = ? AND status = 'pending'",
            [$settlementId]
        );
        if (!$settlement) {
            return ['success' => false, 'error' => 'التسوية غير موجودة أو تمت معالجتها'];
        }

        $now = date('Y-m-d H:i:s');
        $db->update('treasury_settlements', [
            'received_by'      => $rejectedBy,
            'received_at'      => $now,
            'status'           => 'rejected',
            'rejection_reason' => $reason,
            'updated_at'       => $now,
        ], '`id` = ?', [$settlementId]);

        // Revert session to closed so a new settlement can be initiated
        $db->update('treasury_sessions', [
            'status'     => 'closed',
            'updated_at' => $now,
        ], '`id` = ?', [(int) $settlement['session_id']]);

        // Reverse the custody out
        $session = $db->selectOne("SELECT cashier_id FROM treasury_sessions WHERE id = ?", [(int) $settlement['session_id']]);
        if ($session) {
            CustodyService::recordSettlementIn(
                (int) $settlement['from_treasury_id'],
                (int) $session['cashier_id'],
                (string) $settlement['amount'],
                $settlementId
            );
        }

        EventBus::dispatch('treasury.settlement.rejected', [
            'settlement_id' => $settlementId,
            'reason'        => $reason,
            'rejected_by'   => $rejectedBy,
        ]);

        Logger::info("Treasury settlement rejected", ['id' => $settlementId, 'reason' => $reason]);

        return ['success' => true];
    }

    public static function getPendingSettlements(): array
    {
        $db = App::getInstance()->db();
        return $db->select(
            "SELECT s.*, t_from.name_ar as from_treasury_name, t_to.name_ar as to_treasury_name,
                    e.full_name_ar as settled_by_name, ts.session_number
             FROM treasury_settlements s
             LEFT JOIN treasuries t_from ON t_from.id = s.from_treasury_id
             LEFT JOIN treasuries t_to ON t_to.id = s.to_treasury_id
             LEFT JOIN employees e ON e.id = s.settled_by
             LEFT JOIN treasury_sessions ts ON ts.id = s.session_id
             WHERE s.status = 'pending'
             ORDER BY s.settled_at ASC"
        );
    }

    public static function getSettlementHistory(int $treasuryId, int $limit = 50): array
    {
        $db = App::getInstance()->db();
        return $db->select(
            "SELECT s.*, t_from.name_ar as from_treasury_name, t_to.name_ar as to_treasury_name,
                    e_settled.full_name_ar as settled_by_name, e_received.full_name_ar as received_by_name,
                    ts.session_number
             FROM treasury_settlements s
             LEFT JOIN treasuries t_from ON t_from.id = s.from_treasury_id
             LEFT JOIN treasuries t_to ON t_to.id = s.to_treasury_id
             LEFT JOIN employees e_settled ON e_settled.id = s.settled_by
             LEFT JOIN employees e_received ON e_received.id = s.received_by
             LEFT JOIN treasury_sessions ts ON ts.id = s.session_id
             WHERE s.from_treasury_id = ? OR s.to_treasury_id = ?
             ORDER BY s.id DESC
             LIMIT ?",
            [$treasuryId, $treasuryId, $limit]
        );
    }

    public static function find(int $settlementId): ?array
    {
        $db = App::getInstance()->db();
        return $db->selectOne(
            "SELECT s.*, t_from.name_ar as from_treasury_name, t_to.name_ar as to_treasury_name,
                    e_settled.full_name_ar as settled_by_name, e_received.full_name_ar as received_by_name,
                    ts.session_number
             FROM treasury_settlements s
             LEFT JOIN treasuries t_from ON t_from.id = s.from_treasury_id
             LEFT JOIN treasuries t_to ON t_to.id = s.to_treasury_id
             LEFT JOIN employees e_settled ON e_settled.id = s.settled_by
             LEFT JOIN employees e_received ON e_received.id = s.received_by
             LEFT JOIN treasury_sessions ts ON ts.id = s.session_id
             WHERE s.id = ?",
            [$settlementId]
        );
    }

    private static function generateSettlementNumber($db): string
    {
        $year = date('Y');
        $row = $db->selectOne(
            "SELECT MAX(CAST(SUBSTRING(settlement_number, 10) AS UNSIGNED)) as max_num
             FROM treasury_settlements WHERE settlement_number LIKE ?",
            ["STL-{$year}-%"]
        );
        $next = ((int) ($row['max_num'] ?? 0)) + 1;
        return sprintf('STL-%s-%06d', $year, $next);
    }
}
