<?php
declare(strict_types=1);

namespace App\Modules\Treasury\Services;

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

final class SessionService
{
    public static function openSession(int $treasuryId, int $cashierId): array
    {
        $db = App::getInstance()->db();

        $openSession = $db->selectOne(
            "SELECT id FROM treasury_sessions WHERE treasury_id = ? AND status = 'open'",
            [$treasuryId]
        );
        if ($openSession) {
            return ['success' => false, 'error' => 'يوجد وردية مفتوحة بالفعل لهذه الخزنة'];
        }

        $sessionNumber = self::generateSessionNumber($db);
        $now = date('Y-m-d H:i:s');

        $id = $db->insert('treasury_sessions', [
            'treasury_id'     => $treasuryId,
            'cashier_id'      => $cashierId,
            'session_number'  => $sessionNumber,
            'opened_at'       => $now,
            'opening_balance' => '0.00',
            'total_collected' => '0.00',
            'total_receipts'  => 0,
            'status'          => 'open',
            'created_at'      => $now,
            'updated_at'      => $now,
        ]);

        EventBus::dispatch('treasury.session.opened', [
            'session_id'  => $id,
            'treasury_id' => $treasuryId,
            'cashier_id'  => $cashierId,
        ]);

        Logger::info("Treasury session opened", ['id' => $id, 'number' => $sessionNumber, 'treasury' => $treasuryId]);

        return [
            'success'        => true,
            'session_id'     => $id,
            'session_number' => $sessionNumber,
        ];
    }

    public static function closeSession(int $sessionId): array
    {
        $db = App::getInstance()->db();

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

        $totalCollected = $db->selectOne(
            "SELECT COALESCE(SUM(amount), 0) as total, COUNT(*) as cnt
             FROM payments WHERE session_id = ? AND is_voided = 0 AND payment_method = 'cash'",
            [$sessionId]
        );

        $closingBalance = (string) ($totalCollected['total'] ?? '0.00');
        $receiptCount = (int) ($totalCollected['cnt'] ?? 0);
        $now = date('Y-m-d H:i:s');

        $db->update('treasury_sessions', [
            'closed_at'       => $now,
            'closing_balance' => $closingBalance,
            'total_collected' => $closingBalance,
            'total_receipts'  => $receiptCount,
            'status'          => 'closed',
            'updated_at'      => $now,
        ], '`id` = ?', [$sessionId]);

        EventBus::dispatch('treasury.session.closed', [
            'session_id'      => $sessionId,
            'treasury_id'     => (int) $session['treasury_id'],
            'cashier_id'      => (int) $session['cashier_id'],
            'total_collected'  => $closingBalance,
            'total_receipts'  => $receiptCount,
        ]);

        Logger::info("Treasury session closed", ['id' => $sessionId, 'total' => $closingBalance]);

        return [
            'success'         => true,
            'closing_balance' => $closingBalance,
            'total_receipts'  => $receiptCount,
        ];
    }

    public static function getCurrentSession(int $treasuryId, ?int $cashierId = null): ?array
    {
        $db = App::getInstance()->db();
        $sql = "SELECT ts.*, e.full_name_ar as cashier_name
                FROM treasury_sessions ts
                LEFT JOIN employees e ON e.id = ts.cashier_id
                WHERE ts.treasury_id = ? AND ts.status = 'open'";
        $params = [$treasuryId];

        if ($cashierId !== null) {
            $sql .= ' AND ts.cashier_id = ?';
            $params[] = $cashierId;
        }

        $sql .= ' LIMIT 1';
        return $db->selectOne($sql, $params);
    }

    public static function getAnyCurrentSession(int $cashierId): ?array
    {
        $db = App::getInstance()->db();
        return $db->selectOne(
            "SELECT ts.*, e.full_name_ar as cashier_name, t.name_ar as treasury_name
             FROM treasury_sessions ts
             LEFT JOIN employees e ON e.id = ts.cashier_id
             LEFT JOIN treasuries t ON t.id = ts.treasury_id
             WHERE ts.cashier_id = ? AND ts.status = 'open'
             LIMIT 1",
            [$cashierId]
        );
    }

    public static function getSessionHistory(int $treasuryId, int $limit = 50): array
    {
        $db = App::getInstance()->db();
        return $db->select(
            "SELECT ts.*, e.full_name_ar as cashier_name
             FROM treasury_sessions ts
             LEFT JOIN employees e ON e.id = ts.cashier_id
             WHERE ts.treasury_id = ?
             ORDER BY ts.id DESC
             LIMIT ?",
            [$treasuryId, $limit]
        );
    }

    public static function getAllSessionHistory(int $cashierId, int $limit = 50): array
    {
        $db = App::getInstance()->db();
        return $db->select(
            "SELECT ts.*, e.full_name_ar as cashier_name, t.name_ar as treasury_name
             FROM treasury_sessions ts
             LEFT JOIN employees e ON e.id = ts.cashier_id
             LEFT JOIN treasuries t ON t.id = ts.treasury_id
             WHERE ts.cashier_id = ?
             ORDER BY ts.id DESC
             LIMIT ?",
            [$cashierId, $limit]
        );
    }

    public static function find(int $sessionId): ?array
    {
        $db = App::getInstance()->db();
        return $db->selectOne(
            "SELECT ts.*, e.full_name_ar as cashier_name, t.name_ar as treasury_name
             FROM treasury_sessions ts
             LEFT JOIN employees e ON e.id = ts.cashier_id
             LEFT JOIN treasuries t ON t.id = ts.treasury_id
             WHERE ts.id = ?",
            [$sessionId]
        );
    }

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