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

    class SearchModel extends CI_Model
    {
        public function __construct()
        {
            parent::__construct();
            $this->lang->load('search', $_SESSION['site_lang']);
        }

        public function search($query, $amount, $offset, $filters)
        {
            $results = $this->getRawResults($query, $amount, $offset, $filters);
            $results = $this->prepareResults($results);
            return $results;
        }

        private function getRawResults($query, $amount, $offset, $filters)
        {
            mb_language('uni');
            mb_internal_encoding('UTF-8');

            $lang = $_SESSION['site_lang'];

            $query = strtolower($query);
            $offset *= $amount;

            list($sql, $attr) = $this->buildQuery($filters);
            $attr = str_split($attr);
            foreach ($attr as $i => $a) {
                $a = $a === 'l' ? $lang : $query;
                $attr[$i] = $a;
            }
            $attr[] = $amount;
            $attr[] = $offset;

            $this->db->cache_off();
            $results = $this->db->query($sql, $attr)->result_array();
            $this->db->cache_on();

            return $results;
        }

        private function buildQuery($filters)
        {
            $attributes = '';
            $query = 'SELECT a.*, u.username authorName, u.displayname authorDisplayname
                FROM (';

            $possibilities = [
                'blogPost' => [
                    'sql' => 'SELECT "blogPost" type, v.url url, bp.authorID author, bp.image image, v.title title, v.description content, bp.initialRelease date
                       FROM blog_post bp
                          INNER JOIN blog_post_versions v ON v.postID = bp.ID AND v.lang = ? AND active
                       WHERE (LOWER(v.title) RLIKE ?
                          OR LOWER(v.description) RLIKE ?
                          OR LOWER(v.content) RLIKE ?
                          OR bp.ID IN (SELECT bpt.postID FROM blog_post_tags bpt WHERE bpt.tagID IN (SELECT bt.tagID FROM blog_tags bt WHERE (bt.name RLIKE ? OR LOWER(bt.displayname) RLIKE ?) AND lang = ?))
                          OR bp.ID IN (SELECT bpc.postID FROM blog_post_categories bpc WHERE bpc.categoryID IN (SELECT bc.categoryID FROM blog_categories bc WHERE (bc.name RLIKE ? OR LOWER(bc.displayname) RLIKE ?) AND lang = ?))
                          OR (SELECT username FROM users WHERE ID = bp.authorID) RLIKE ?)
                          AND state = 1',
                    'attributes' => 'lqqqqqlqqlq'
                ],
                'blogCategory' => [
                    'sql' => 'SELECT "blogCategory" type, c.name url, 1 author, null image, c.displayname title, null content, null date
                      FROM blog_categories c
                      WHERE (c.name RLIKE ? OR LOWER(c.displayname) RLIKE ?) AND lang = ?',
                    'attributes' => 'qql'
                ],
                'blogTag' => [
                    'sql' => 'SELECT "blogTag" type, t.name url, 1 author, null image, t.displayname title, null content, null date
                      FROM blog_tags t
                      WHERE (t.name RLIKE ? OR LOWER(t.displayname) RLIKE ?) AND lang = ?',
                    'attributes' => 'qql'
                ],
                'user' => [
                    'sql' => 'SELECT "user" type, u.username url, u.ID author, s.headerImage image, u.displayname title, s.about content, u.dateCreated date
                       FROM users u
                          INNER JOIN user_settings s ON u.ID = s.ID
                       WHERE (username RLIKE ?
                          OR lower(about) RLIKE ?)
                          AND activated AND isDeleted = FALSE',
                    'attributes' => 'qq',
                ],
                'userPost' => [
                    'sql' => 'SELECT "userPost" type, p.hashID url, p.userID author, null image, p.content title, null content, p.date date
                       FROM user_posts p
                       WHERE LOWER(p.content) RLIKE ?
                          OR (SELECT username FROM users WHERE ID = p.userID) RLIKE ?',
                    'attributes' => 'qq',
                ],
                'project' => [
                    'sql' => 'SELECT "project" type, p.name url, 1 as author, p.source image, t.title title, t.description content, p.datetime date
                       FROM projects p
                              INNER JOIN projects_translations t ON t.projectID = p.ID AND t.lang = ?
                       WHERE LOWER(t.title) RLIKE ?
                          OR LOWER(t.description) RLIKE ?
                          OR LOWER(t.content) RLIKE ?',
                    'attributes' => 'lqqq',
                ],
                'projectCategory' => [
                    'sql' => 'SELECT "projectCategory" type, c.name url, 1 author, null image, c.displayname title, c.displayname content, null date
                       FROM projects_categories c
                       WHERE name RLIKE ?
                          OR lower(displayname) RLIKE ?',
                    'attributes' => 'qq'
                ],
            ];

            $filters = array_intersect(array_keys($possibilities), $filters);

            if (empty($filters))
                $filters = array_keys($possibilities);

            foreach ($filters as $filter) {
                $data = $possibilities[$filter];
                if (empty($data))
                    continue;

                $query .= $data['sql'];
                $query .= ' UNION ';
                $attributes .= $data['attributes'];
            }

            $query = substr($query, 0, -6);

            $query .= ') a
                       LEFT JOIN users u ON a.author = u.ID
                ORDER BY date desc LIMIT ? OFFSET ?';

            return [$query, $attributes];
        }

        private function prepareResults($results)
        {
            foreach ($results as $i => $result) {
                list(
                    'authorDisplayname' => $displayname,
                    'authorName' => $username,
                    'content' => $content,
                    'date' => $date,
                    'image' => $image,
                    'title' => $title,
                    'type' => $type,
                    'url' => $url,
                    ) = $result;

                $date = date('d.m.Y', strtotime($date));

                if (strlen($title) > 75) {
                    $title = utf8_encode($title);
                    $title = substr($title, 0, 75) . '...';
                    $title = utf8_decode($title);
                }

                if (strlen($content) > 200) {
                    $content = utf8_encode($content);
                    $content = substr($content, 0, 200) . '...';
                    $content = utf8_decode($content);
                }

                $showUser = TRUE;
                switch ($type) {
                    case 'blogPost':
                        $url = base_url('blog/post/' . $url);
                        break;
                    case 'project':
                        $url = base_url('project/' . $url);
                        break;
                    case 'projectCategory':
                        $url = base_url('projects/' . $url);
                        $showUser = FALSE;
                        break;
                    case 'user':
                        $url = base_url('user/' . $url);
                        break;
                    case 'userPost':
                        $url = base_url('user/' . $username . '/post/' . $url);
                        break;
                }

                $type = lang('search_type_' . $type);

                $newArray = [
                    'showUser' => $showUser,
                    'username' => $displayname,
                    'authorUrl' => base_url('user/' . $username),
                    'content' => $content,
                    'date' => $date,
                    'image' => $image,
                    'title' => $title,
                    'type' => $type,
                    'url' => $url,
                ];


                $results[$i] = $newArray;
            }

            return $results;
        }

    }