<?php

namespace App\Controller;

use App\Controller\AppController;
use Cake\Event\Event;
use Cake\I18n\Time;
use Cake\Network\Exception\NotFoundException;
use Cake\ORM\TableRegistry;
use Cake\Routing\Router;

class LinksController extends AppController
{

    public function initialize()
    {
        parent::initialize();
        $this->loadComponent('Paginator');
    }

    public function beforeFilter(Event $event)
    {
        parent::beforeFilter($event);
        $this->viewBuilder()->layout('go');
        $this->Auth->allow([ 'shorten', 'st', 'api', 'view', 'go']);
    }

    public function shorten()
    {
        $this->autoRender = false;

        $this->response->type('json');

        if (!$this->request->is('ajax')) {
            $content = [
                'status' => 'error',
                'message' => __('Bad Request.'),
                'url' => ''
            ];
            $this->response->body(json_encode($content));
            return $this->response;
        }


        $user_id = 1;
        if (null !== $this->Auth->user('id')) {
            $user_id = $this->Auth->user('id');
        }

        $user = $this->Links->Users->find()->where(['id' => $user_id, 'status' => 'active'])->first();

        if (!$user) {
            $content = [
                'status' => 'error',
                'message' => __('Invalid user'),
                'url' => ''
            ];
            $this->response->body(json_encode($content));
            return $this->response;
        }

        $this->request->data['url'] = parse_url($this->request->data['url'], PHP_URL_SCHEME) === null ? 'http://' . $this->request->data['url'] : $this->request->data['url'];

        $link = $this->Links->find()->where(['url' => $this->request->data['url'], 'user_id' => $user->id])->first();

        if ($link) {
            $content = [
                'status' => 'success',
                'message' => '',
                'url' => Router::url('/' . $link->alias, true)
            ];
            $this->response->body(json_encode($content));
            return $this->response;
        }

        $link = $this->Links->newEntity();
        $data = [];

        $data['user_id'] = $user->id;
        $data['url'] = $this->request->data['url'];
        $data['alias'] = $this->Links->geturl();
        $link->status = 'active';
        $link->hits = 0;
        $link = $this->Links->patchEntity($link, $data);
        if ($this->Links->save($link)) {
            $content = [
                'status' => 'success',
                'message' => '',
                'url' => Router::url('/' . $link->alias, true)
            ];
            $this->response->body(json_encode($content));
            return $this->response;
        }

        $content = [
            'status' => 'error',
            'message' => __('Invalid URL.'),
            'url' => ''
        ];
        $this->response->body(json_encode($content));
        return $this->response;
    }

    public function st()
    {
        $this->autoRender = false;

        if (!isset($this->request->query) || !isset($this->request->query['api']) || !isset($this->request->query['url'])) {
            echo __('Invalid Call.');
            return;
        }

        $api = $this->request->query['api'];
        $url = $this->request->query['url'];

        $user = $this->Links->Users->find()->where(['api_token' => $api, 'status' => 'active'])->first();

        if (!$user) {
            echo __('Invalid API token.');
            return;
        }

        $url = parse_url($url, PHP_URL_SCHEME) === null ? 'http://' . $url : $url;

        $link = $this->Links->find()->where(['url' => $url, 'user_id' => $user->id])->first();

        if ($link) {
            $this->redirect('/' . $link->alias);
            return;
        }

        $link = $this->Links->newEntity();
        $data = [];

        $data['user_id'] = $user->id;
        $data['url'] = $url;
        $data['alias'] = $this->Links->geturl();
        $link->status = 'active';
        $link->hits = 0;
        $link = $this->Links->patchEntity($link, $data);
        if ($this->Links->save($link)) {
            $this->redirect('/' . $link->alias);
            return;
        }

        echo __('Error.');
        return;
    }

    public function api()
    {
        $this->autoRender = false;

        $this->response->type('json');


        if (!isset($this->request->query) || !isset($this->request->query['api']) || !isset($this->request->query['url'])) {
            $body = json_encode([
                'status' => 'error',
                'message' => 'Invalid API call',
                'shortenedUrl' => ''
            ]);
            $this->response->body($body);
            return $this->response;
        }

        $api = $this->request->query['api'];
        $url = $this->request->query['url'];

        $user = $this->Links->Users->find()->where(['api_token' => $api, 'active' => 1])->first();

        if (!$user) {
            $body = json_encode([
                'status' => 'error',
                'message' => 'Invalid API token',
                'shortenedUrl' => ''
            ]);
            $this->response->body($body);
            return $this->response;
        }

        $url = parse_url($url, PHP_URL_SCHEME) === null ? 'http://' . $url : $url;

        $link = $this->Links->find()->where(['url' => $url, 'user_id' => $user->id])->first();

        if ($link) {
            $body = json_encode([
                'status' => 'success',
                'shortenedUrl' => Router::url('/' . $link->alias, true)
            ]);
            $this->response->body($body);
            return $this->response;
        }

        $link = $this->Links->newEntity();
        $data = [];

        $data['user_id'] = $user->id;
        $data['url'] = $url;
        $data['alias'] = $this->Links->geturl();
        $link->status = 'active';
        $link->hits = 0;

        $link = $this->Links->patchEntity($link, $data);

        if ($this->Links->save($link)) {
            $body = json_encode([
                'status' => 'success',
                'shortenedUrl' => $link->alias
            ]);
            $this->response->body($body);
            return $this->response;
        }

        $body = json_encode([
            'status' => 'error',
            'message' => 'Invalid URL',
            'shortenedUrl' => ''
        ]);
        $this->response->body($body);
        return $this->response;
    }

    public function view($alias = null)
    {
        if (!$alias) {
            throw new NotFoundException(__('Invalid link'));
        }

        //$link = $this->Links->find()->where( ['alias' => $alias, 'status' => 1] )->contain(['Users'])->first();
        $link = $this->Links->find()->where(['alias' => $alias, 'status  <>' => 'inactive'])->first();
        if (!$link) {
            throw new NotFoundException(__('404 Not Found'));
        }
        $this->set('link', $link);

        $this->_setVisitorCookie();


        $country = $this->Links->Statistics->get_country(get_ip());

        $CampaignItems = TableRegistry::get('CampaignItems');

        $campaign_items = $CampaignItems->find()
            ->select(['CampaignItems.id', 'CampaignItems.campaign_id', 'Campaigns.id', 'Campaigns.title', 'Campaigns.url', 'Campaigns.user_id'])
            ->contain(['Campaigns'])
            ->where(['CampaignItems.country' => $country])
            ->orWhere(['CampaignItems.country' => 'all'])
            ->where(['CampaignItems.weight <' => 100])
            ->where(['Campaigns.status' => 'Active'])
            ->where(['Campaigns.ad_id' => 1])
            ->order(['CampaignItems.weight' => 'ASC'])
            ->limit(10)
            ->toArray();

        shuffle($campaign_items);
        $campaign_item = array_values($campaign_items)[0];

        $this->set('campaign_item', $campaign_item);
    }

    public function go()
    {
        $this->autoRender = false;

        if (!$this->request->is('ajax')) {
            $content = [
                'status' => 'error',
                'message' => 'Bad Request.',
                'url' => ''
            ];
            echo json_encode($content);
            return;
        }

        $link = $this->Links->find()->where([
            'alias' => $this->request->data['alias'],
            'status <>' => 'inactive'
            ])->first();
        if (!$link) {
            $content = [
                'status' => 'error',
                'message' => '404 Not Found.',
                'url' => ''
            ];
            echo json_encode($content);
            return;
        }

        /**
         * Check if cookie valid
         */
        $cookie = $this->Cookie->read('visitor');
        if (!is_array($cookie)) {
            // Update link hits
            $this->_updateLinkHits($link);
            $this->_addNormalStatisticEntry($link, $this->request->data, $cookie);
            $content = [
                'status' => 'success',
                'message' => 'Go without Earn because no cookie',
                'url' => $link->url
            ];
            echo json_encode($content);
            return;
            //return debug( 'Go without Earn because no cookie' );
            //return $this->redirect( $link->url );
        }

        /**
         * Check if proxy
         */
        if ($this->_isProxy()) {
            // Update link hits
            $this->_updateLinkHits($link);
            $this->_addNormalStatisticEntry($link, $this->request->data, $cookie);
            $content = [
                'status' => 'success',
                'message' => 'Go without Earn because proxy',
                'url' => $link->url
            ];
            echo json_encode($content);
            return;
            //return debug( 'Go without Earn because proxy' );
            //return $this->redirect( $link->url );
        }

        /**
         * Check if IP changed
         */
        if ($cookie['ip'] != get_ip()) {
            // Update link hits
            $this->_updateLinkHits($link);
            $this->_addNormalStatisticEntry($link, $this->request->data, $cookie);
            $content = [
                'status' => 'success',
                'message' => 'Go without Earn because IP changed',
                'url' => $link->url
            ];
            echo json_encode($content);
            return;
            //return debug( 'Go without Earn because IP changed' );
            //return $this->redirect( $link->url );
        }

        /**
         * Check for unique vistits within last 24 hour
         */
        $time = new Time();
        $now = strtotime($time->toDateTimeString());
        $last24 = new Time($now - 24 * 60 * 60);

        $statistics = $this->Links->Statistics->find()
            ->where(['Statistics.ip' => $cookie['ip']])
            ->where(['Statistics.campaign_id' => $this->request->data['ci']])
            ->where(["Statistics.created >=" => $last24])
            ->first();

        if ($statistics) {
            // Update link hits
            $this->_updateLinkHits($link);
            $this->_addNormalStatisticEntry($link, $this->request->data, $cookie);
            $content = [
                'status' => 'success',
                'message' => 'Go without Earn because Not unique.',
                'url' => $link->url
            ];
            echo json_encode($content);
            return;
            //return debug( 'Go without Earn because Not unique.' );
            //return $this->redirect( $link->url );
        }


        /**
         * Check Campaign Item weight
         */
        $CampaignItems = TableRegistry::get('CampaignItems');

        $campaign_item = $CampaignItems->find()
            ->contain(['Campaigns'])
            ->where(['CampaignItems.id' => $this->request->data['cii']])
            ->where(['CampaignItems.weight <' => 100])
            ->where(['Campaigns.status' => 'Active'])
            ->where(['Campaigns.ad_id' => 1])
            ->first();


        if (!$campaign_item) {
            // Update link hits
            $this->_updateLinkHits($link);
            $this->_addNormalStatisticEntry($link, $this->request->data, $cookie);
            $content = [
                'status' => 'success',
                'message' => 'Go without Earn because Campaign Item weight is full.',
                'url' => $link->url
            ];
            echo json_encode($content);
            return;
            //return debug( 'Go without Earn because Campaign Item weight is full.' );
            //return $this->redirect( $link->url );
        }

        /**
         * Check if default campaign
         */
        if ($campaign_item->campaign->default_campaign) {
            // Update link hits
            $this->_updateLinkHits($link);
            $this->_addNormalStatisticEntry($link, $this->request->data, $cookie);
            $content = [
                'status' => 'success',
                'message' => 'Go without Earn because Default Campaign.',
                'url' => $link->url
            ];
            echo json_encode($content);
            return;
            //return debug( 'Go without Earn because Default Campaign.' );
            //return $this->redirect( $link->url );
        }

        /**
         * Add statistic record
         */
        $country = $this->Links->Statistics->get_country($cookie[ 'ip' ]);

        $statistic = $this->Links->Statistics->newEntity();

        $statistic->link_id = $link->id;
        $statistic->user_id = $link->user_id;
        $statistic->ad_id = 1;
        $statistic->campaign_id = $campaign_item['campaign']['id'];
        $statistic->campaign_user_id = $campaign_item['campaign']['user_id'];
        $statistic->campaign_item_id = $campaign_item['id'];
        $statistic->ip = $cookie['ip'];
        $statistic->country = $country;
        $statistic->owner_earn = ($campaign_item['advertiser_price'] - $campaign_item['publisher_price']) / 1000;
        $statistic->publisher_earn = $campaign_item['publisher_price'] / 1000;
        $statistic->referer_domain = (parse_url($this->request->data['ref'], PHP_URL_HOST) ? parse_url($this->request->data['ref'], PHP_URL_HOST) : 'Direct');
        $statistic->referer = $this->request->data['ref'];
        $statistic->user_agent = env('HTTP_USER_AGENT');
        $this->Links->Statistics->save($statistic);

        $user_update = $this->Links->Users->get($link->user_id);
        $user_update->publisher_balance += $campaign_item['publisher_price'] / 1000;

        $this->Links->Users->save($user_update);

        /**
         * Update campaign item views and weight
         */
        $campaign_item_update = $CampaignItems->newEntity();
        $campaign_item_update->id = $campaign_item['id'];
        $campaign_item_update->views = $campaign_item['views'] + 1;
        $campaign_item_update->weight = (($campaign_item['views'] + 1) / ($campaign_item['purchase'] * 1000)) * 100;
        $CampaignItems->save($campaign_item_update);

        // Update link hits
        $this->_updateLinkHits($link);
        $content = [
            'status' => 'success',
            'message' => 'Go With earning :)',
            'url' => $link->url
        ];
        echo json_encode($content);
        return;
        //debug( "Go to URL $link->url With earning :)" );
        //return $this->redirect( $link->url );
    }

    protected function _addNormalStatisticEntry($link, $data, $cookie)
    {
        $ip = get_ip();
        if (is_array($cookie)) {
            $ip = $cookie['ip'];
        }
        $country = $this->Links->Statistics->get_country($cookie[ 'ip' ]);

        $statistic = $this->Links->Statistics->newEntity();

        $statistic->link_id = $link->id;
        $statistic->user_id = $link->user_id;
        $statistic->ad_id = 1;
        $statistic->campaign_id = $data['ci'];
        $statistic->campaign_user_id = $data['cui'];
        $statistic->campaign_item_id = $data['cii'];
        $statistic->ip = $ip;
        $statistic->country = $country;
        $statistic->owner_earn = 0;
        $statistic->publisher_earn = 0;
        $statistic->referer_domain = (parse_url($data['ref'], PHP_URL_HOST) ? parse_url($data['ref'], PHP_URL_HOST) : 'Direct');
        $statistic->referer = $data['ref'];
        $statistic->user_agent = env('HTTP_USER_AGENT');
        $this->Links->Statistics->save($statistic);
    }

    protected function _setVisitorCookie()
    {
        $cookie = $this->Cookie->read('visitor');

        if (isset($cookie)) {
            return true;
        }

        $cookie_data = [
            'ip' => get_ip(),
            'date' => (new Time())->toDateTimeString()
        ];
        $this->Cookie->configKey('visitor', [
            'expires' => '+1 day',
            'httpOnly' => true
        ]);
        $this->Cookie->write('visitor', $cookie_data);

        return true;
    }

    protected function _updateLinkHits($link = null)
    {
        if (!$link) {
            return;
        }
        $link->hits += 1;
        $link->modified = $link->modified;
        $this->Links->save($link);
        return;
    }

    protected function _isProxy()
    {
        $proxy_headers = [
            'HTTP_VIA',
            'HTTP_X_FORWARDED_FOR',
            'HTTP_FORWARDED_FOR',
            'HTTP_X_FORWARDED',
            'HTTP_FORWARDED',
            'HTTP_CLIENT_IP',
            'HTTP_FORWARDED_FOR_IP',
            'VIA',
            'X_FORWARDED_FOR',
            'FORWARDED_FOR',
            'X_FORWARDED',
            'FORWARDED',
            'CLIENT_IP',
            'FORWARDED_FOR_IP',
            'HTTP_PROXY_CONNECTION'
        ];
        foreach ($proxy_headers as $proxy_header) {
            if (isset($_SERVER[$proxy_header])) {
                return true;
            }
        }
        return false;
    }
}
