<?php
class StellaFilter{
    public $gender;
    public $minAge;
    public $maxAge;
    public $sexuality;
    public $lookingFor;
    public $country;
    public $city;
    public $minHeight;
    public $maxHeight;
    public $minWeight;
    public $maxWeight;
    public $hair;
    public $facialHair;
    public $pubicHair;
    public $bodyHair;
    public $hairColor;
    public $tattoo;
    public $piercing;
    public $eyeColor;
    public $breastSize;
    public $minPenisSize;
    public $maxPenisSize;
    public $abs;
    public $bottomSizes;
    public $bodyTypes;
    public $ethnicities;
    public $fitnessLevels;
    public $dietaryPreferences;
    public $healthHabits;
    public $exerciseFrequency;
    public $sleepingHabits;
    public $foodAllergies;
    public $alcoholConsumptions;
    public $smoking;
    public $jobs;
    public $minNetWorth;
    public $maxNetWorth;
    public $minYearlySalary;
    public $maxYearlySalary;
    public $mainLiving;
    public $financialGoals;
    public $spendingHabits;
    public $financialIndependence;
    public $inDebt;
    public $hasKids;
    public $wantKids;
    public $fetishes;
    public $personalities;
    public $hobbiesAndActivities;
    public $movieGenres;
    public $bookGenres;
    public $highestGraduation;
    public $education;
    public $travelPreferences;
    public $religion;
    public $languages;
    public $currentSituation;
    public $pets;
    public $sexualActivity;

    public $activeFilters = array();
    public $generalFilter = array('gender', 'minAge', 'maxAge', 'sexualities', 'sexualActivity', 'lookingFor', 'country', 'city');
    public $bodyFeaturesFilter = array('minHeight','maxHeight','minWeight','maxWeight','hair','facialHair','pubicHair','bodyHair','hairColor','tattoo','piercing','eyeColor','breastSize','minPenisSize','maxPenisSize','abs','bottomSizes','bodyTypes','ethnicities');
    public $bodyLifeStyleFilter = array('fitnessLevels','dietaryPreferences','healthHabits','exerciseFrequency','sleepingHabits','foodAllergies','alcoholConsumptions','smoking');
    public $financialFilter = array('jobs','minNetWorth','maxNetWorth','minYearlySalary','maxYearlySalary','mainLiving','financialGoals','spendingHabits','financialIndependence','inDebt');
    public $personalFilter = array('hasKids','wantKids','fetishes','personalities','hobbiesAndActivities','movieGenres','bookGenres','highestGraduation','education','travelPreferences','religion','languages','currentSituation','pets');

    public $comparisionFilter = array('minAge', 'maxAge', 'minHeight', 'maxHeight', 'minWeight', 'maxWeight', 'minPenisSize', 'maxPenisSize', 'minNetWorth', 'maxNetWorth', 'minYearlySalary', 'maxYearlySalary');
    public $comparisionInfo = array(
        'minAge' => array(
            'comp' =>  '>',
            'pref' => 'dob'
        ),
        'maxAge' => array(
            'comp' =>  '<',
            'pref' => 'dob'
        ),
        'minHeight' => array(
            'comp' =>  '>',
            'pref' => 'height'
        ),
        'maxHeight' => array(
            'comp' =>  '<',
            'pref' => 'height'
        ),
        'minWeight' => array(
            'comp' =>  '>',
            'pref' => 'weight'
        ),
        'maxWeight' => array(
            'comp' =>  '<',
            'pref' => 'weight'
        ),
        'minPenisSize' => array(
            'comp' =>  '>',
            'pref' => 'penisSize'
        ),
        'maxPenisSize' => array(
            'comp' =>  '<',
            'pref' => 'penisSize'
        ),
        'minNetWorth' => array(
            'comp' =>  '>',
            'pref' => 'netWorth'
        ),
        'maxNetWorth' => array(
            'comp' =>  '<',
            'pref' => 'netWorth'
        ),
        'minYearlySalary' => array(
            'comp' =>  '>',
            'pref' => 'yearlySalary'
        ),
        'maxYearlySalary' => array(
            'comp' =>  '<',
            'pref' => 'yearlySalary'
        )
        );

        public $comparisionStatus = array(
            'dob' => false,
            'height' => false,
            'weight' => false,
            'penisSize' => false,
            'netWorth' => false,
            'yearlySalary' => false
        );

    public function returnCountries(){
        $countries = file_get_contents('includes/countries.json');
        return $countries;
    }

    public function setFilter($termName, $term){
        if(property_exists($this, $termName)){
            $this->$termName = $term;
            $this->activeFilters[] = $termName;
        }
    }

    public function search($terms){
        global $db_con;
    
        $sql = 'SELECT u.id, u.uname, u.avatar, u.bio, u.dob, ';
        $aliasCount = 1;
    
        $params = array();
    
        try {
            foreach($this->activeFilters as $filter){
                if(in_array($filter, $this->comparisionFilter)){
                    $sql_info = $this->comparisionInfo[$filter];
                    $pref_name = $sql_info['pref'];
    
                    if(!$this->comparisionStatus[$pref_name]){
                        $alias = 'ud' . $aliasCount;
                        $sql .= $alias . '.data_value AS ' . $pref_name . ",\n";
                        $aliasCount++;
                        $this->comparisionStatus[$pref_name] = true;
                    }
    
                }else{
                    $alias = 'ud' . $aliasCount;
                    $sql .= $alias . '.data_value AS ' . $filter . ",\n";
                    $aliasCount++;
                }
            }
    
            $sql = rtrim($sql, ",\n");
    
            $sql .= " \n" . 'FROM users AS u';
    
            $aliasCount = 1;
            $this->comparisionStatus = array(
                'dob' => false,
                'height' => false,
                'weight' => false,
                'penisSize' => false,
                'netWorth' => false,
                'yearlySalary' => false
            );
    
            foreach($this->activeFilters as $filter){
                $value = $this->$filter;
                if ($value !== null) {
                    if (is_array($value)) {
                        $value = implode(', ', $value);
                    }
                    $alias = 'ud' . $aliasCount;
    
                    if (in_array($filter, $this->comparisionFilter)) {
                        $sql_info = $this->comparisionInfo[$filter];
                        $pref_name = $sql_info['pref'];
                        if (!$this->comparisionStatus[$pref_name]) {
                            $sql .= "\n" . ' LEFT JOIN ' . 'user_data' . ' AS ' . $alias . ' ON u.id = ' . $alias . '.user_id AND ' . $alias . '.data_name = ? ';
                            $params[] = $pref_name;
                            $this->comparisionStatus[$pref_name] = true;
                            $aliasCount++;
                        }
                    } else {
                        $sql .= "\n" . ' LEFT JOIN ' . 'user_data' . ' AS ' . $alias . ' ON u.id = ' . $alias . '.user_id AND ' . $alias . '.data_name = ?';
                        $params[] = $filter;
                        $aliasCount++;
                    }                
                }
    
            }
    
            $aliasCount = 1;
            $this->comparisionStatus = array(
                'dob' => false,
                'height' => false,
                'weight' => false,
                'penisSize' => false,
                'netWorth' => false,
                'yearlySalary' => false
            );
            if(count($this->activeFilters) > 0){
                $sql .= "\n" . " WHERE ";
                $conditions = array();
        
                foreach ($this->activeFilters as $filter) {
                    if (isset($terms->$filter) && $terms->$filter && !empty($terms->$filter)) {
                        $filter_value = $terms->$filter;
                    } else {
                        throw new Exception('Malicious user input');
                    }
                    if(in_array($filter, $this->comparisionFilter)){
                        $sql_info = $this->comparisionInfo[$filter];
                        $pref_name = $sql_info['pref'];
        
                        if (!$this->comparisionStatus[$pref_name]) {
                            $alias = 'ud' . $aliasCount;
                            $prePref = str_replace('min', '', $filter);
                            $prePref = str_replace('max', '', $prePref);
                            $minPref = 'min' . ucfirst($prePref);
                            $maxPref = 'max' . ucfirst($prePref);
                            $minVal = $terms->$minPref;
                            $maxVal = $terms->$maxPref;
        
                            if ($prePref == 'Age') {
                                $isDate = true;
                                $isMax = intval($terms->maxAge) >= 99;
                                // Calculate age
                                $minVal = $this->calcYear($minVal);
                                $maxVal = $this->calcYear($maxVal);
                            } else {
                                $isDate = false;
                                // Check for max conditions
                                switch ($prePref) {
                                    case 'Height':
                                        $isMax = intval($terms->maxHeight) >= 240;
                                        break;
                                    case 'NetWorth':
                                        $isMax = intval($terms->maxNetWorth) == 10000000;
                                        break;
                                    case 'PenisSize':
                                        $isMax = intval($terms->maxPenisSize) == 40;
                                        break;
                                    case 'Weight':
                                        $isMax = intval($terms->maxWeight) == 200;
                                        break;
                                    case 'YearlySalary':
                                        $isMax = intval($terms->maxYearlySalary) == 1000000;
                                        break;
                                    default:
                                        $isMax = false;
                                }
                            }
        
                            if ($isDate) {
                                if ($isMax) {
                                    $conditions[] = "\n" . "STR_TO_DATE(" . $alias . ".data_value, '%Y-%m-%d') >= ?";
                                    $params[] = "'" . date('Y-m-d', strtotime($minVal)) . "'";
                                } else {
                                    $conditions[] = "\n" . "STR_TO_DATE(" . $alias . ".data_value, '%Y-%m-%d') >= ? AND STR_TO_DATE(" . $alias . ".data_value, '%Y-%m-%d') <= ?";
                                    $params[] = "'" . date('Y-m-d', strtotime($minVal)) . "'";
                                    $params[] = "'" . date('Y-m-d', strtotime($maxVal)) . "'";
                                }                     
                            } else {
                                if ($isMax) {
                                    $conditions[] = "\n" . "CAST(" . $alias . ".data_value AS SIGNED) >= ?";
                                    $params[] = intval($minVal);
                                } else {
                                    $conditions[] = "\n" . "CAST(" . $alias . ".data_value AS SIGNED) >= ? AND CAST(" . $alias . ".data_value AS SIGNED) <= ?";
                                    $params[] = intval($minVal);
                                    $params[] = intval($maxVal);
                                }
                            }
        
                            $aliasCount++;
                            $this->comparisionStatus[$pref_name] = true;
                        }
        
                    }else {
                        $alias = 'ud' . $aliasCount;
                        if (is_array($filter_value)) {
                            $conditions[] = "\n" . '(' . rtrim(str_repeat($alias . '.data_value LIKE ? OR ', count($filter_value)), 'OR ') . ')';
                            foreach ($filter_value as $value) {
                                $params[] = "%" . $value . "%";
                            }
                        } else if($filter_value == 'male' || 'female'){
                            $conditions[] = "\n" . $alias . '.data_value = ?';
                            $params[] = $filter_value;
                        } else {
                            $conditions[] = "\n" . $alias . '.data_value LIKE ?';
                            $params[] = "%" . $filter_value . "%";
                        }
                        $aliasCount++;
                    }
        
                }
                $sql .= implode(" AND ", $conditions);
                $sql .= "ORDER BY RAND() LIMIT 1000";
                $stmt = $db_con->prepare($sql);
                // echo $sql;
                $stmt->execute($params);
            }else{
                $stmt = $db_con->prepare($sql);
                $stmt->execute();
            }
            $executedQuery = $stmt->queryString;
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
            $users = array();
            foreach($rows as $row){
                $user = new stdClass();
                if(isset($row['dob']) && !empty($row['dob'])){
                    $dob = $row['dob'];
                    
                    $calcDob = new DateTime($dob);
                    $calcDob =  $calcDob->format('Y-m-d');
                    if($dob < $this->minAge && $dob > $this->maxAge){

                        // Get country
                        $stm = $db_con->prepare('SELECT data_value FROM user_data WHERE data_name = "country" AND user_id = :id');
                        $stm->bindValue(':id', $row['id']);
                        $stm->execute();
                        $_country = $stm->fetch(PDO::FETCH_ASSOC);
        
                        // Get gender
                        $stm = $db_con->prepare('SELECT data_value FROM user_data WHERE data_name = "gender" AND user_id = :id');
                        $stm->bindValue(':id', $row['id']);
                        $stm->execute();
                        $_gender = $stm->fetch(PDO::FETCH_ASSOC);
        
                         // Get orientation
                         $stm = $db_con->prepare('SELECT data_value FROM user_data WHERE data_name = "sexuality" AND user_id = :id');
                         $stm->bindValue(':id', $row['id']);
                         $stm->execute();
                         $_sexuality = $stm->fetch(PDO::FETCH_ASSOC);
        
                        // Get sexuality, gender and country
                        
        
                        $user->id = $row['id'];
                        $user->username = $row['uname'];
                        $user->avatar = $row['avatar'];
                        $user->bio = isset($row['bio']) && !empty($row['bio']) ? $row['bio'] : '';
                        $user->age = $this->calcAge($dob);
                        $user->country = isset($_country['data_value']) && !empty($_country['data_value']) ?  $_country['data_value'] : 'Unknown location';
                        $user->gender = isset($_gender['data_value']) && !empty($_gender['data_value']) ?  $_gender['data_value'] : '';
                        $user->sexuality = isset($_sexuality['data_value']) && !empty($_sexuality['data_value']) ?  $_sexuality['data_value'] : '';
                        $users[] = $user;
                    }

                    
                }
                
            }
            $filtered_users = json_encode($users);
            return $filtered_users;
        } catch (PDOException $e) {
            echo "Error: " . $e->getMessage();
        } catch (Exception $e) {
            echo "Error: " . $e->getMessage();
        }
    }
    

    public function allowed_search_value($val){
        require('includes/allowedFilter.php');
        $countries = file_get_contents('includes/countries.json');
        $countries = json_decode($countries);
        $isAllowed = false;
        if(in_array($val, $filterAllowed)){
            $isAllowed =  true;
        }

        foreach($countries as $country => $cities) {
            if($country === $val || in_array($val, $cities)) {
                $isAllowed = true;
                break;
            }
        }

        return $isAllowed;
    }

    public function calcYear($age) {
        $currentDate = new DateTime();
        $currentDate->sub(new DateInterval('P' . $age . 'Y'));
        $dateOfBirth = $currentDate->format('Y-m-d');
        return $dateOfBirth;
    }

    private function calcAge($dob) {
        $dobDate = new DateTime($dob);
        $currentDate = new DateTime();
        $age = $currentDate->diff($dobDate);
        return $age->y;
    }
}