<?php

declare(strict_types=1);

namespace App\Modules\Operation;

use App\Core\Database;

/**
 * OperationModel — Database management and transactional checks for
 * QR scans, guest check-ins, and wedding operation dashboards.
 *
 * Prepared PDO statements with strict workspace isolation.
 *
 * @package Inveetaire
 * @ref     PILOT-007
 */
class OperationModel
{
    /**
     * Look up guest and their RSVP status by secure token.
     *
     * @param int    $workspaceId
     * @param string $token
     * @return array|null Guest details or null.
     */
    public function getGuestByToken(int $workspaceId, string $token): ?array
    {
        $db = Database::getConnection();
        $stmt = $db->prepare('
            SELECT g.id, g.workspace_id, g.guest_code, g.full_name, g.side, g.guest_group, 
                   g.invited_pax, g.phone_number, g.notes, g.rsvp_status, g.checkin_status, g.checked_in_at,
                   r.response, r.confirmed_pax
            FROM guests g
            LEFT JOIN rsvps r ON g.id = r.guest_id
            WHERE g.workspace_id = :workspace_id 
              AND g.guest_code = :token
              AND g.is_deleted = 0
            LIMIT 1
        ');
        $stmt->execute([
            'workspace_id' => $workspaceId,
            'token'        => $token
        ]);
        $row = $stmt->fetch(\PDO::FETCH_ASSOC);
        return $row !== false ? $row : null;
    }

    /**
     * Retrieve assigned events for a guest, falling back to all active events if none explicitly assigned.
     *
     * @param int $workspaceId
     * @param int $guestId
     * @return array
     */
    public function getAssignedEvents(int $workspaceId, int $guestId): array
    {
        $db = Database::getConnection();

        // Check explicit guest events assignments
        $stmtExplicit = $db->prepare('
            SELECT we.id, we.event_name, we.event_date, we.venue_name, we.venue_address, we.is_primary
            FROM wedding_events we
            INNER JOIN guest_events ge ON we.id = ge.wedding_event_id
            WHERE ge.workspace_id = :workspace_id 
              AND ge.guest_id = :guest_id
              AND we.is_deleted = 0
            ORDER BY we.sort_order ASC, we.event_date ASC
        ');
        $stmtExplicit->execute([
            'workspace_id' => $workspaceId,
            'guest_id'     => $guestId
        ]);
        return $stmtExplicit->fetchAll(\PDO::FETCH_ASSOC);
    }

    /**
     * Ensure the three pilot events exist for a workspace.
     * Auto-seeds missing pilot events dynamically.
     *
     * @param int $workspaceId
     * @return void
     */
    public function ensurePilotEventsExist(int $workspaceId): void
    {
        $db = Database::getConnection();
        
        // Soft-delete legacy default event 'Wedding Ceremony' to keep workspace restricted to pilot events
        $stmtDelLegacy = $db->prepare('
            UPDATE wedding_events 
            SET is_deleted = 1, deleted_at = CURRENT_TIMESTAMP 
            WHERE workspace_id = :workspace_id 
              AND event_name = \'Wedding Ceremony\' 
              AND is_deleted = 0
        ');
        $stmtDelLegacy->execute(['workspace_id' => $workspaceId]);
        
        $requiredEvents = [
            ['name' => 'Holy Matrimony', 'is_primary' => 0, 'sort_order' => 1, 'time' => ' 09:00:00'],
            ['name' => 'Tea Pai', 'is_primary' => 0, 'sort_order' => 2, 'time' => ' 11:30:00'],
            ['name' => 'Reception', 'is_primary' => 1, 'sort_order' => 3, 'time' => ' 18:00:00'],
        ];
        
        foreach ($requiredEvents as $req) {
            $stmt = $db->prepare('SELECT id FROM wedding_events WHERE workspace_id = :workspace_id AND event_name = :name AND is_deleted = 0 LIMIT 1');
            $stmt->execute(['workspace_id' => $workspaceId, 'name' => $req['name']]);
            if ($stmt->fetch() === false) {
                // Fetch workspace date
                $stmtWs = $db->prepare('SELECT wedding_date FROM workspaces WHERE id = :workspace_id LIMIT 1');
                $stmtWs->execute(['workspace_id' => $workspaceId]);
                $wsDate = $stmtWs->fetchColumn() ?: date('Y-m-d');
                
                $stmtInsert = $db->prepare('
                    INSERT INTO wedding_events (workspace_id, event_name, event_date, venue_name, venue_address, is_primary, sort_order)
                    VALUES (:workspace_id, :name, :date, :venue, :address, :is_primary, :sort_order)
                ');
                $stmtInsert->execute([
                    'workspace_id' => $workspaceId,
                    'name'         => $req['name'],
                    'date'         => $wsDate . $req['time'],
                    'venue'        => 'Grand Ballroom',
                    'address'      => 'Main Wedding Hall, Grand Suite',
                    'is_primary'   => $req['is_primary'],
                    'sort_order'   => $req['sort_order']
                ]);
            }
        }

        // Auto-seed Default Session for every event in workspace if missing
        $eventSessionModel = new \App\Modules\Invitation\EventSessionModel();
        $eventSessionModel->ensureDefaultSessions($workspaceId);
    }

    /**
     * Get event sessions for a specific wedding event.
     *
     * @param int $workspaceId
     * @param int $weddingEventId
     * @return array
     */
    public function getEventSessions(int $workspaceId, int $weddingEventId): array
    {
        $eventSessionModel = new \App\Modules\Invitation\EventSessionModel();
        return $eventSessionModel->getSessionsByEventId($workspaceId, $weddingEventId);
    }

    /**
     * Get all event sessions for a workspace grouped by wedding_event_id.
     *
     * @param int $workspaceId
     * @return array
     */
    public function getSessionsGroupedByEvent(int $workspaceId): array
    {
        $eventSessionModel = new \App\Modules\Invitation\EventSessionModel();
        return $eventSessionModel->getSessionsGroupedByEvent($workspaceId);
    }

    /**
     * Migrate existing guest records to have access to all pilot events if unconfigured.
     *
     * @param int $workspaceId
     * @return void
     */
    public function migrateExistingGuestsEvents(int $workspaceId): void
    {
        $db = Database::getConnection();
        
        // 1. Get all events
        $stmtEvents = $db->prepare('SELECT id FROM wedding_events WHERE workspace_id = :workspace_id AND is_deleted = 0');
        $stmtEvents->execute(['workspace_id' => $workspaceId]);
        $eventIds = $stmtEvents->fetchAll(\PDO::FETCH_COLUMN);
        
        if (empty($eventIds)) return;
        
        // 2. Get all guests without guest_events link
        $stmtGuests = $db->prepare('
            SELECT id FROM guests 
            WHERE workspace_id = :workspace_id 
              AND is_deleted = 0 
              AND id NOT IN (SELECT DISTINCT guest_id FROM guest_events WHERE workspace_id = :workspace_id_sub)
        ');
        $stmtGuests->execute([
            'workspace_id'     => $workspaceId,
            'workspace_id_sub' => $workspaceId
        ]);
        $guestIds = $stmtGuests->fetchAll(\PDO::FETCH_COLUMN);
        
        if (empty($guestIds)) return;
        
        // 3. Link them to all events
        $stmtInsert = $db->prepare('
            INSERT INTO guest_events (guest_id, wedding_event_id, workspace_id, rsvp_status) 
            VALUES (:guest_id, :event_id, :workspace_id, "pending")
        ');
        foreach ($guestIds as $guestId) {
            foreach ($eventIds as $eventId) {
                $stmtInsert->execute([
                    'guest_id'     => $guestId,
                    'event_id'     => $eventId,
                    'workspace_id' => $workspaceId
                ]);
            }
        }
    }

    /**
     * Get single event by id.
     *
     * @param int $workspaceId
     * @param int $eventId
     * @return array|null
     */
    public function getEventById(int $workspaceId, int $eventId): ?array
    {
        $db = Database::getConnection();
        $stmt = $db->prepare('SELECT * FROM wedding_events WHERE id = :event_id AND workspace_id = :workspace_id AND is_deleted = 0 LIMIT 1');
        $stmt->execute(['event_id' => $eventId, 'workspace_id' => $workspaceId]);
        $row = $stmt->fetch(\PDO::FETCH_ASSOC);
        return $row !== false ? $row : null;
    }

    /**
     * Fetch printer configurations for the workspace.
     *
     * @param int $workspaceId
     * @return array|null
     */
    public function getPrinterConfig(int $workspaceId): ?array
    {
        $db = Database::getConnection();
        $stmt = $db->prepare('SELECT * FROM printer_configurations WHERE workspace_id = :workspace_id LIMIT 1');
        $stmt->execute(['workspace_id' => $workspaceId]);
        $config = $stmt->fetch();
        return $config ?: null;
    }

    /**
     * Update printer configuration.
     *
     * @param int $workspaceId
     * @param int $width
     * @param int $height
     * @return bool
     */
    public function updatePrinterConfig(int $workspaceId, int $width, int $height): bool
    {
        $db = Database::getConnection();
        $stmt = $db->prepare('
            INSERT INTO printer_configurations (workspace_id, label_width_mm, label_height_mm, updated_at)
            VALUES (:workspace_id, :width, :height, CURRENT_TIMESTAMP)
            ON DUPLICATE KEY UPDATE 
                label_width_mm = VALUES(label_width_mm),
                label_height_mm = VALUES(label_height_mm),
                updated_at = VALUES(updated_at)
        ');
        return $stmt->execute([
            'workspace_id' => $workspaceId,
            'width'        => $width,
            'height'       => $height
        ]);
    }

    /**
     * Get check-in record details for a guest at a specific event.
     *
     * @param int $workspaceId
     * @param int $guestId
     * @param int $eventId
     * @return array|null
     */
    public function getCheckinRecord(int $workspaceId, int $guestId, int $eventId): ?array
    {
        $db = Database::getConnection();
        $stmt = $db->prepare('
            SELECT c.*, u.display_name as operator_name 
            FROM checkins c 
            LEFT JOIN users u ON c.operator_id = u.id 
            WHERE c.guest_id = :guest_id AND c.wedding_event_id = :event_id AND c.workspace_id = :workspace_id 
            LIMIT 1
        ');
        $stmt->execute(['guest_id' => $guestId, 'event_id' => $eventId, 'workspace_id' => $workspaceId]);
        $row = $stmt->fetch(\PDO::FETCH_ASSOC);
        return $row !== false ? $row : null;
    }

    /**
     * Check-in a guest for a specific wedding event.
     *
     * @param int         $workspaceId
     * @param int         $guestId
     * @param int         $eventId
     * @param int         $operatorId
     * @param string      $method
     * @param string|null $notes
     * @return bool
     */
    public function checkInGuestForEvent(int $workspaceId, int $guestId, int $eventId, int $operatorId, string $method, ?string $notes, int $confirmedPax = 1, int $stickerQty = 0): bool
    {
        $db = Database::getConnection();
        
        $stmtCheck = $db->prepare('SELECT id FROM checkins WHERE guest_id = :guest_id AND wedding_event_id = :event_id AND workspace_id = :workspace_id LIMIT 1');
        $stmtCheck->execute(['guest_id' => $guestId, 'event_id' => $eventId, 'workspace_id' => $workspaceId]);
        if ($stmtCheck->fetch() !== false) {
            return false;
        }
        
        $hasAngpao = $stickerQty > 0 ? 1 : 0;

        $stmt = $db->prepare('
            INSERT INTO checkins (guest_id, wedding_event_id, workspace_id, operator_id, checkin_method, actual_pax, has_angpao, angpao_count, notes, checked_in_at)
            VALUES (:guest_id, :event_id, :workspace_id, :operator_id, :method, :actual_pax, :has_angpao, :angpao_count, :notes, CURRENT_TIMESTAMP)
        ');
        $stmt->execute([
            'guest_id'     => $guestId,
            'event_id'     => $eventId,
            'workspace_id' => $workspaceId,
            'operator_id'  => $operatorId,
            'method'       => $method,
            'actual_pax'   => $confirmedPax,
            'has_angpao'   => $hasAngpao,
            'angpao_count' => $stickerQty,
            'notes'        => $notes
        ]);
        
        // Keep general check-in fields for backward compatibility
        $stmtUpdateGuest = $db->prepare('
            UPDATE guests 
            SET checkin_status = \'checked_in\', 
                checked_in_at = COALESCE(checked_in_at, CURRENT_TIMESTAMP), 
                updated_at = CURRENT_TIMESTAMP 
            WHERE id = :guest_id AND workspace_id = :workspace_id
        ');
        $stmtUpdateGuest->execute(['guest_id' => $guestId, 'workspace_id' => $workspaceId]);
        
        return true;
    }

    /**
     * Cancel check-in for a guest at a specific event.
     *
     * @param int $workspaceId
     * @param int $guestId
     * @param int $eventId
     * @return bool
     */
    public function cancelCheckInGuestForEvent(int $workspaceId, int $guestId, int $eventId): bool
    {
        $db = Database::getConnection();
        
        // Delete the checkin record
        $stmt = $db->prepare('
            DELETE FROM checkins 
            WHERE guest_id = :guest_id AND wedding_event_id = :event_id AND workspace_id = :workspace_id
        ');
        $stmt->execute([
            'guest_id'     => $guestId,
            'event_id'     => $eventId,
            'workspace_id' => $workspaceId
        ]);

        // Check if there are any other checkins for this guest
        $stmtCheck = $db->prepare('SELECT COUNT(*) FROM checkins WHERE guest_id = :guest_id AND workspace_id = :workspace_id');
        $stmtCheck->execute(['guest_id' => $guestId, 'workspace_id' => $workspaceId]);
        $remainingCheckins = (int) $stmtCheck->fetchColumn();

        if ($remainingCheckins === 0) {
            // Revert guest status to not_arrived
            $stmtRevert = $db->prepare('
                UPDATE guests 
                SET checkin_status = \'not_arrived\', 
                    checked_in_at = NULL, 
                    updated_at = CURRENT_TIMESTAMP 
                WHERE id = :guest_id AND workspace_id = :workspace_id
            ');
            $stmtRevert->execute(['guest_id' => $guestId, 'workspace_id' => $workspaceId]);
        }
        
        return true;
    }

    /**
     * Fetch event check-in metrics.
     *
     * @param int $workspaceId
     * @param int $eventId
     * @return array
     */
    public function getEventAttendanceStats(int $workspaceId, int $eventId): array
    {
        $db = Database::getConnection();
        
        // 1. Expected Guests
        $stmtExpected = $db->prepare('
            SELECT COUNT(g.id) as guests_count, COALESCE(SUM(g.invited_pax), 0) as total_pax
            FROM guests g
            INNER JOIN guest_events ge ON g.id = ge.guest_id
            WHERE ge.wedding_event_id = :event_id 
              AND g.workspace_id = :workspace_id 
              AND g.is_deleted = 0
        ');
        $stmtExpected->execute(['event_id' => $eventId, 'workspace_id' => $workspaceId]);
        $expected = $stmtExpected->fetch(\PDO::FETCH_ASSOC);
        
        // 2. Checked-In
        $stmtCheckedIn = $db->prepare('
            SELECT COUNT(DISTINCT guest_id) 
            FROM checkins 
            WHERE wedding_event_id = :event_id 
              AND workspace_id = :workspace_id
        ');
        $stmtCheckedIn->execute(['event_id' => $eventId, 'workspace_id' => $workspaceId]);
        $checkedInCount = (int) $stmtCheckedIn->fetchColumn();
        
        // 3. Pending
        $stmtPending = $db->prepare('
            SELECT COUNT(g.id) 
            FROM guests g
            INNER JOIN guest_events ge ON g.id = ge.guest_id
            LEFT JOIN checkins c ON g.id = c.guest_id AND ge.wedding_event_id = c.wedding_event_id
            WHERE ge.wedding_event_id = :event_id 
              AND g.workspace_id = :workspace_id 
              AND g.is_deleted = 0
              AND c.id IS NULL
        ');
        $stmtPending->execute(['event_id' => $eventId, 'workspace_id' => $workspaceId]);
        $pendingCount = (int) $stmtPending->fetchColumn();
        
        // 4. Manual Overrides
        $stmtOverrides = $db->prepare('
            SELECT COUNT(DISTINCT c.guest_id) 
            FROM checkins c
            LEFT JOIN guest_events ge ON c.guest_id = ge.guest_id AND c.wedding_event_id = ge.wedding_event_id
            WHERE c.wedding_event_id = :event_id 
              AND c.workspace_id = :workspace_id 
              AND ge.id IS NULL
        ');
        $stmtOverrides->execute(['event_id' => $eventId, 'workspace_id' => $workspaceId]);
        $overridesCount = (int) $stmtOverrides->fetchColumn();
        
        // 5. Rejected
        $stmtRejected = $db->prepare('
            SELECT COUNT(*) 
            FROM audit_logs 
            WHERE action_type = \'checkin.rejected\' 
              AND workspace_id = :workspace_id 
              AND after_state LIKE :event_match
        ');
        $stmtRejected->execute([
            'workspace_id' => $workspaceId,
            'event_match'  => '%"wedding_event_id":' . $eventId . '%'
        ]);
        $rejectedCount = (int) $stmtRejected->fetchColumn();
        
        return [
            'expected_guests'   => (int) $expected['guests_count'],
            'expected_pax'      => (int) $expected['total_pax'],
            'checked_in_count'  => $checkedInCount,
            'pending_count'     => $pendingCount,
            'overrides_count'   => $overridesCount,
            'rejected_count'    => $rejectedCount
        ];
    }

    /**
     * Get attendance statistics summary for all active ceremonies in workspace.
     *
     * @param int $workspaceId
     * @return array
     */
    public function getPerCeremonyAttendanceStats(int $workspaceId): array
    {
        $db = Database::getConnection();

        $stmtEvents = $db->prepare('
            SELECT id, event_name, is_primary 
            FROM wedding_events 
            WHERE workspace_id = :workspace_id AND is_deleted = 0 
            ORDER BY sort_order ASC, id ASC
        ');
        $stmtEvents->execute(['workspace_id' => $workspaceId]);
        $events = $stmtEvents->fetchAll(\PDO::FETCH_ASSOC);

        $results = [];
        foreach ($events as $e) {
            $eventId = (int) $e['id'];
            $stats = $this->getEventAttendanceStats($workspaceId, $eventId);
            $results[] = [
                'event_id'   => $eventId,
                'event_name' => $e['event_name'],
                'is_primary' => (bool) $e['is_primary'],
                'invited'    => $stats['expected_guests'],
                'arrived'    => $stats['checked_in_count'],
                'remaining'  => $stats['pending_count']
            ];
        }

        return $results;
    }

    /**
     * Check if a guest has left a congratulatory wish message.
     *
     * @param int $workspaceId
     * @param int $guestId
     * @return bool
     */
    public function hasWish(int $workspaceId, int $guestId): bool
    {
        $db = Database::getConnection();
        $stmt = $db->prepare('
            SELECT id FROM wishes 
            WHERE workspace_id = :workspace_id 
              AND guest_id = :guest_id
              AND is_visible = 1
            LIMIT 1
        ');
        $stmt->execute([
            'workspace_id' => $workspaceId,
            'guest_id'     => $guestId
        ]);
        return $stmt->fetchColumn() !== false;
    }

    /**
     * Update guest checkin status to checked_in and write checked_in_at.
     *
     * Only sets checked_in_at if it was previously NULL.
     *
     * @param int $workspaceId
     * @param int $guestId
     * @return bool True if timestamp was set for the first time, false if already checked in.
     */
    public function checkInGuest(int $workspaceId, int $guestId): bool
    {
        $db = Database::getConnection();

        // Check if already checked in
        $stmtCheck = $db->prepare('
            SELECT checked_in_at 
            FROM guests 
            WHERE id = :guest_id 
              AND workspace_id = :workspace_id
            LIMIT 1
        ');
        $stmtCheck->execute([
            'guest_id'     => $guestId,
            'workspace_id' => $workspaceId
        ]);
        $checkedInAt = $stmtCheck->fetchColumn();

        $alreadyCheckedIn = ($checkedInAt !== null && $checkedInAt !== false);

        $stmtUpdate = $db->prepare('
            UPDATE guests 
            SET checkin_status = \'checked_in\', 
                checked_in_at = COALESCE(checked_in_at, CURRENT_TIMESTAMP), 
                updated_at = CURRENT_TIMESTAMP 
            WHERE id = :guest_id 
              AND workspace_id = :workspace_id
        ');
        $stmtUpdate->execute([
            'guest_id'     => $guestId,
            'workspace_id' => $workspaceId
        ]);

        return !$alreadyCheckedIn;
    }

    /**
     * Retrieve aggregated attendance metrics.
     *
     * @param int $workspaceId
     * @return array
     */
    public function getAttendanceStats(int $workspaceId): array
    {
        $db = Database::getConnection();

        // 1. Total invited guests & capacity (sum of invited_pax)
        $stmtInvited = $db->prepare('
            SELECT COUNT(*) as guests_count, COALESCE(SUM(invited_pax), 0) as total_pax 
            FROM guests 
            WHERE workspace_id = :workspace_id 
              AND is_deleted = 0
        ');
        $stmtInvited->execute(['workspace_id' => $workspaceId]);
        $invited = $stmtInvited->fetch(\PDO::FETCH_ASSOC);

        // 2. RSVP Attending (Yes)
        $stmtYes = $db->prepare('
            SELECT COUNT(*) as guests_count, COALESCE(SUM(confirmed_pax), 0) as total_pax 
            FROM rsvps 
            WHERE workspace_id = :workspace_id 
              AND response = \'attending\'
        ');
        $stmtYes->execute(['workspace_id' => $workspaceId]);
        $rsvpYes = $stmtYes->fetch(\PDO::FETCH_ASSOC);

        // 3. RSVP Declined (No)
        $stmtNo = $db->prepare('
            SELECT COUNT(*) as guests_count 
            FROM guests 
            WHERE workspace_id = :workspace_id 
              AND rsvp_status = \'declined\'
              AND is_deleted = 0
        ');
        $stmtNo->execute(['workspace_id' => $workspaceId]);
        $rsvpNoCount = (int) $stmtNo->fetchColumn();

        // 4. RSVP Pending
        $stmtPending = $db->prepare('
            SELECT COUNT(*) as guests_count 
            FROM guests 
            WHERE workspace_id = :workspace_id 
              AND rsvp_status = \'pending\'
              AND is_deleted = 0
        ');
        $stmtPending->execute(['workspace_id' => $workspaceId]);
        $rsvpPendingCount = (int) $stmtPending->fetchColumn();

        // 5. Checked-In
        $stmtCheckedIn = $db->prepare('
            SELECT COUNT(g.id) as guests_count, COALESCE(SUM(r.confirmed_pax), 0) as total_pax
            FROM guests g
            LEFT JOIN rsvps r ON g.id = r.guest_id
            WHERE g.workspace_id = :workspace_id 
              AND g.checkin_status = \'checked_in\'
              AND g.is_deleted = 0
        ');
        $stmtCheckedIn->execute(['workspace_id' => $workspaceId]);
        $checkedIn = $stmtCheckedIn->fetch(\PDO::FETCH_ASSOC);

        // 6. Wish Moderation Counts
        $stmtWishes = $db->prepare('
            SELECT 
                SUM(CASE WHEN (status = \'approved\' OR (status IS NULL AND is_visible = 1)) THEN 1 ELSE 0 END) as approved_wishes,
                SUM(CASE WHEN status = \'pending\' THEN 1 ELSE 0 END) as pending_wishes,
                SUM(CASE WHEN (status = \'rejected\' OR (status IS NULL AND is_visible = 0)) THEN 1 ELSE 0 END) as rejected_wishes
            FROM wishes 
            WHERE workspace_id = :workspace_id
        ');
        $stmtWishes->execute(['workspace_id' => $workspaceId]);
        $wishesStats = $stmtWishes->fetch(\PDO::FETCH_ASSOC);

        $totalGuests = (int) $invited['guests_count'];
        $respondedCount = (int) $rsvpYes['guests_count'] + $rsvpNoCount;
        $rsvpRate = $totalGuests > 0 ? round(($respondedCount / $totalGuests) * 100, 1) : 0.0;

        return [
            'total_guests'       => $totalGuests,
            'total_invited_pax'  => (int) $invited['total_pax'],
            'rsvp_yes_count'     => (int) $rsvpYes['guests_count'],
            'rsvp_yes_pax'       => (int) $rsvpYes['total_pax'],
            'rsvp_no_count'      => $rsvpNoCount,
            'rsvp_pending_count' => $rsvpPendingCount,
            'rsvp_responded'     => $respondedCount,
            'rsvp_rate'          => $rsvpRate,
            'checked_in_count'   => (int) $checkedIn['guests_count'],
            'checked_in_pax'     => (int) $checkedIn['total_pax'],
            'approved_wishes'    => (int) ($wishesStats['approved_wishes'] ?? 0),
            'pending_wishes'     => (int) ($wishesStats['pending_wishes'] ?? 0),
            'rejected_wishes'    => (int) ($wishesStats['rejected_wishes'] ?? 0)
        ];
    }
}
