<?php
defined('BASEPATH') or exit('No direct script access allowed');

class M_push_notification extends CI_Model
{
    public function saveSubscription($userId, array $subscription, $userAgent = '')
    {
        $endpoint = isset($subscription['endpoint']) ? trim((string) $subscription['endpoint']) : '';
        $keys = isset($subscription['keys']) && is_array($subscription['keys']) ? $subscription['keys'] : array();
        $publicKey = isset($keys['p256dh']) ? trim((string) $keys['p256dh']) : '';
        $authToken = isset($keys['auth']) ? trim((string) $keys['auth']) : '';
        $contentEncoding = isset($subscription['contentEncoding'])
            ? trim((string) $subscription['contentEncoding'])
            : 'aes128gcm';

        if (!$this->isValidEndpoint($endpoint) || $publicKey === '' || $authToken === '') {
            return false;
        }

        if (!in_array($contentEncoding, array('aes128gcm', 'aesgcm'), true)) {
            $contentEncoding = 'aes128gcm';
        }

        $endpointHash = hash('sha256', $endpoint);
        $now = time();
        $data = array(
            'user_id' => (int) $userId,
            'endpoint' => $endpoint,
            'endpoint_hash' => $endpointHash,
            'public_key' => substr($publicKey, 0, 255),
            'auth_token' => substr($authToken, 0, 255),
            'content_encoding' => $contentEncoding,
            'user_agent' => substr((string) $userAgent, 0, 255),
            'is_active' => 1,
            'failure_count' => 0,
            'updated_at' => $now
        );

        $existing = $this->db
            ->select('id')
            ->get_where('push_subscriptions', array('endpoint_hash' => $endpointHash))
            ->row_array();

        if ($existing) {
            $this->db->where('id', (int) $existing['id'])->update('push_subscriptions', $data);
            return $this->db->affected_rows() >= 0;
        }

        $data['created_at'] = $now;
        $data['last_success_at'] = 0;
        return $this->db->insert('push_subscriptions', $data);
    }

    public function removeSubscription($userId, $endpoint)
    {
        if (!$this->isValidEndpoint($endpoint)) {
            return false;
        }

        $this->db->delete('push_subscriptions', array(
            'user_id' => (int) $userId,
            'endpoint_hash' => hash('sha256', $endpoint)
        ));

        return true;
    }

    public function getActiveSubscriptions($userId)
    {
        return $this->db
            ->order_by('id', 'asc')
            ->get_where('push_subscriptions', array(
                'user_id' => (int) $userId,
                'is_active' => 1
            ))
            ->result_array();
    }

    public function hasActiveSubscription($userId)
    {
        return $this->db
            ->where(array('user_id' => (int) $userId, 'is_active' => 1))
            ->count_all_results('push_subscriptions') > 0;
    }

    public function markSuccess($subscriptionId)
    {
        $this->db->where('id', (int) $subscriptionId)->update('push_subscriptions', array(
            'failure_count' => 0,
            'is_active' => 1,
            'last_success_at' => time(),
            'updated_at' => time()
        ));
    }

    public function markFailure($subscriptionId, $disableAfterFailures)
    {
        $row = $this->db
            ->select('failure_count')
            ->get_where('push_subscriptions', array('id' => (int) $subscriptionId))
            ->row_array();

        if (!$row) {
            return;
        }

        $failureCount = (int) $row['failure_count'] + 1;
        $this->db->where('id', (int) $subscriptionId)->update('push_subscriptions', array(
            'failure_count' => $failureCount,
            'is_active' => $failureCount >= (int) $disableAfterFailures ? 0 : 1,
            'updated_at' => time()
        ));
    }

    public function deleteSubscription($subscriptionId)
    {
        $this->db->delete('push_subscriptions', array('id' => (int) $subscriptionId));
    }

    private function isValidEndpoint($endpoint)
    {
        if (!is_string($endpoint) || strlen($endpoint) > 2048 || filter_var($endpoint, FILTER_VALIDATE_URL) === false) {
            return false;
        }

        $scheme = strtolower((string) parse_url($endpoint, PHP_URL_SCHEME));
        return $scheme === 'https';
    }
}
