<?php

namespace PublishPress\FuturePro\Modules\Notifications\Models;

use PublishPress\Future\Core\DI\Container;
use PublishPress\Future\Framework\Database\Interfaces\DBTableSchemaInterface;
use PublishPress\Future\Framework\HookableInterface;
use PublishPress\FuturePro\Core\ServicesAbstract;
use PublishPress\FuturePro\Modules\Notifications\Interfaces\NotificationsModelInterface;
use PublishPress\FuturePro\Modules\Workflows\HooksAbstract;
use PublishPress\FuturePro\Modules\Workflows\Models\EventDrivenActionModel;

class NotificationsModel implements NotificationsModelInterface
{
    /**
     * @var DBTableSchemaInterface
     */
    private $dbTableSchema;

    /**
     * @var string
     */
    private $tableName;

    /**
     * @var HookableInterface
     */
    private $hooks;

    public function __construct()
    {
        $container = Container::getInstance();

        // TODO: Inject this
        $this->dbTableSchema = $container->get(ServicesAbstract::DB_TABLE_WORKFLOW_NOTIFICATIONS_SCHEMA);
        $this->tableName = $this->dbTableSchema->getTableName();
        $this->hooks = $container->get(ServicesAbstract::HOOKS);
    }

    public function getUserNotifications(
        int $userId,
        ?int $limit = null,
        ?int $offset = null,
        ?string $order = 'ASC'
    ): array {
        global $wpdb;

        $order = strtoupper($order) === 'ASC' ? 'ASC' : 'DESC';

        if (! $limit) {
            $limit = PHP_INT_MAX;
        }

        if (! $offset) {
            $offset = 0;
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
        $notifications = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM %i WHERE user_id = %d ORDER BY created_at %s LIMIT %d OFFSET %d",
                $this->tableName,
                (int) $userId,
                $order,
                (int) $limit,
                (int) $offset
            )
        );

        return $notifications;
    }

    public function getUnreadUserNotifications(int $userId): array
    {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
        $notifications = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM %i WHERE user_id = %d AND is_read = 0 ORDER BY created_at ASC",
                $this->tableName,
                (int) $userId
            )
        );

        return $notifications;
    }

    public function markNotificationsAsRead(int $userId, array $notificationIds): void
    {
        global $wpdb;

        $notificationIds = array_map('intval', $notificationIds);

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
        $updatedRows = $wpdb->update(
            $this->tableName,
            [
                'is_read' => 1,
                'read_at' => current_time('mysql'),
            ],
            [
                'user_id' => $userId,
                'is_read' => 0,
                'id' => $notificationIds,
            ]
        );

        if ($updatedRows === false || $updatedRows === 0) {
            return;
        }

        foreach ($notificationIds as $notificationId) {
            $this->hooks->doAction(
                HooksAbstract::ACTION_MARKED_NOTIFICATION_AS_READ,
                $notificationId,
                $userId
            );
        }

        $this->hooks->doAction(
            HooksAbstract::ACTION_MARKED_ALL_NOTIFICATIONS_AS_READ,
            $userId
        );
    }

    /**
     * Fill the notification options by event, integrating it with the
     * event driven action options.
     *
     * @param array $notifications
     *
     * @return array
     */
    public function fillNotificationOptionsByEvent(array $notifications): array
    {
        $eventDrivenActionModel = new EventDrivenActionModel();

        foreach ($notifications as &$notification) {
            $eventAction = (int) $notification->action_id;

            $eventDrivenActionModel->load($eventAction);
            $args = $eventDrivenActionModel->args;

            if (! isset($args['eventData']['options'])) {
                $options = [];
            } else {
                $options = (array) $args['eventData']['options'];
            }

            $options = $this->guaranteeDismissOption($options);

            $notification->options = $options;
        }

        return $notifications;
    }

    private function guaranteeDismissOption(array $options): array
    {
        if (empty($options)) {
            $options[] = [
                'name' => 'dismiss',
                'label' => __('Dismiss', 'publishpress-future-pro'),
                'hint' => __('Dismiss the notification', 'publishpress-future-pro'),
            ];
        }

        return $options;
    }
}
