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

class Push_notifications extends Member_Controller
{
    public function __construct()
    {
        parent::__construct();
        $this->load->model('m_push_notification');
        $this->load->library('push_service');
    }

    public function configuration()
    {
        if ($this->input->method(true) !== 'GET') {
            return $this->respond(array('success' => false, 'message' => 'Method not allowed.'), 405);
        }

        return $this->respond(array(
            'success' => true,
            'enabled' => $this->push_service->isEnabled(),
            'publicKey' => $this->push_service->getPublicKey(),
            'hasActiveSubscription' => $this->m_push_notification->hasActiveSubscription($this->currentUserId())
        ));
    }

    public function subscribe()
    {
        if ($this->input->method(true) !== 'POST') {
            return $this->respond(array('success' => false, 'message' => 'Method not allowed.'), 405);
        }
        if (!$this->isSameOriginRequest()) {
            return $this->respond(array('success' => false, 'message' => 'Invalid request origin.'), 403);
        }
        if (stripos((string) $this->input->server('CONTENT_TYPE'), 'application/json') !== 0) {
            return $this->respond(array('success' => false, 'message' => 'JSON body required.'), 415);
        }

        $payload = json_decode((string) $this->input->raw_input_stream, true);
        $subscription = is_array($payload) && isset($payload['subscription'])
            ? $payload['subscription']
            : $payload;

        if (!is_array($subscription)) {
            return $this->respond(array('success' => false, 'message' => 'Invalid subscription.'), 422);
        }

        $saved = $this->m_push_notification->saveSubscription(
            $this->currentUserId(),
            $subscription,
            (string) $this->input->user_agent()
        );

        if (!$saved) {
            return $this->respond(array('success' => false, 'message' => 'Subscription data is incomplete.'), 422);
        }

        return $this->respond(array('success' => true, 'message' => 'Browser notifications enabled.'));
    }

    public function unsubscribe()
    {
        if ($this->input->method(true) !== 'POST') {
            return $this->respond(array('success' => false, 'message' => 'Method not allowed.'), 405);
        }
        if (!$this->isSameOriginRequest()) {
            return $this->respond(array('success' => false, 'message' => 'Invalid request origin.'), 403);
        }
        if (stripos((string) $this->input->server('CONTENT_TYPE'), 'application/json') !== 0) {
            return $this->respond(array('success' => false, 'message' => 'JSON body required.'), 415);
        }

        $payload = json_decode((string) $this->input->raw_input_stream, true);
        $endpoint = is_array($payload) && isset($payload['endpoint']) ? (string) $payload['endpoint'] : '';

        if (!$this->m_push_notification->removeSubscription($this->currentUserId(), $endpoint)) {
            return $this->respond(array('success' => false, 'message' => 'Invalid endpoint.'), 422);
        }

        return $this->respond(array('success' => true, 'message' => 'Browser notifications disabled.'));
    }

    private function currentUserId()
    {
        return (int) $this->session->vUID;
    }

    private function isSameOriginRequest()
    {
        $origin = trim((string) $this->input->server('HTTP_ORIGIN'));
        if ($origin === '') {
            return true;
        }

        $originParts = parse_url($origin);
        $siteParts = parse_url(base_url());
        if (!is_array($originParts) || !is_array($siteParts)) {
            return false;
        }

        $originScheme = isset($originParts['scheme']) ? strtolower($originParts['scheme']) : '';
        $siteScheme = isset($siteParts['scheme']) ? strtolower($siteParts['scheme']) : '';
        $originHost = isset($originParts['host']) ? strtolower($originParts['host']) : '';
        $siteHost = isset($siteParts['host']) ? strtolower($siteParts['host']) : '';
        $originPort = isset($originParts['port']) ? (int) $originParts['port'] : ($originScheme === 'https' ? 443 : 80);
        $sitePort = isset($siteParts['port']) ? (int) $siteParts['port'] : ($siteScheme === 'https' ? 443 : 80);

        return $originScheme === $siteScheme && $originHost === $siteHost && $originPort === $sitePort;
    }

    private function respond(array $payload, $statusCode = 200)
    {
        return $this->output
            ->set_status_header((int) $statusCode)
            ->set_content_type('application/json', 'utf-8')
            ->set_output(json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
    }
}
