<?php
require_once ('Database.php');
require_once ('FacilityData.php');

class FacilityDataSet {
    protected $_dbHandle, $_dbInstance;

    public function __construct() {
        $this->_dbInstance = Database::getInstance();
        $this->_dbHandle = $this->_dbInstance->getDbConnection();
    }

    /**
     * @param $filterArray
     * @return array
     * Function to allow fetching of facility data. Data objects are created and held in an array
     * Count of rows for pagination returned alongside data objects.
     */
    public function fetchAll($filterArray): array
    {
        /**
         * COUNT(DISTINCT ecoFacilities.id) required due to multiple status comments possible.
         */
        $sqlCount = "SELECT COUNT(DISTINCT ecoFacilities.id) AS total FROM ecoFacilities";

        /**
         * DISTINCT used again for prior reasoning, although data is handled properly regardless later.
         * GROUP_CONCAT is used to handle multiple status comments under one facility. Without this, DISTINCT
         * drops the additional comment.
         */
        $sqlData = "SELECT DISTINCT ecoFacilities.id, 
                        title, 
                        GROUP_CONCAT(ecoFacilityStatus.statusComment, ', ') AS status, 
                        ecoCategories.name AS category, 
                        description, 
                        houseNumber, 
                        streetName, 
                        county, 
                        town, 
                        postcode, 
                        lng, 
                        lat, 
                        ecoUser.username AS contributor 
                    FROM ecoFacilities";

        /**
         * ? Parameters used here over named parameters so logic can be modular, more
         * columns can be added in the future
         */
        $sqlWhere = "
                    LEFT JOIN ecoCategories ON ecoCategories.id = ecoFacilities.category
                    LEFT JOIN ecoUser ON ecoUser.id = ecoFacilities.contributor
                    LEFT JOIN ecoFacilityStatus ON ecoFacilityStatus.facilityid = ecoFacilities.id
                    WHERE (ecoFacilityStatus.statusComment LIKE ? OR ? IS NULL)
                      AND ecoFacilities.title LIKE ?
                      AND ecoCategories.name LIKE ?
                      AND ecoFacilities.description LIKE ?
                      AND ecoFacilities.streetName LIKE ?
                      AND ecoFacilities.county LIKE ?
                      AND ecoFacilities.town LIKE ?
                      AND ecoFacilities.postcode LIKE ?
                      AND ecoUser.username LIKE ?
                    ";

        /**
         * GROUP BY required to ensure status comments are displayed under the same ID
         * Named parameters used here for prior reasoning, columns can be added above without
         * effecting the bindIndex.
         */
        $sqlLimits = "
                    GROUP BY ecoFacilities.id
                    LIMIT :limit OFFSET :offset;";
        $sqlLimits = "
                    GROUP BY ecoFacilities.id
                    ;";

        // Concatenate query snippets for data and row count
        $dataQuery = $sqlData . $sqlWhere . $sqlLimits;
        $countQuery = $sqlCount . $sqlWhere . ";";

        // Prepare, bind and execute data query
        $stmt = $this->populateFields($dataQuery, $filterArray);
        $stmt->execute();

        // Create data objects
        $dataSet = [];
        while ($row = $stmt->fetch()) {
            $dataSet[] = new FacilityData($row);
        }

        // Prepare, bind then execute count query
        $stmt = $this->populateFields($countQuery, $filterArray);
        $stmt->execute();
        $totalCount = $stmt->fetch()['total'];

        return [
            'dataset' => $dataSet,
            'count' => $totalCount
            ];
    }

    /**
     * @param $sqlQuery
     * @param $filterArray
     * @return false|PDOStatement
     * Function for fetchAll() to de-dupe code. Performs binding on PDO statements to facilitate
     * filtering of facilities. Returns a bound PDO statement.
     */
    private function populateFields($sqlQuery, $filterArray)
    {
        $stmt = $this->_dbHandle->prepare($sqlQuery);
        // Ensures only one value is returned per column name
        $stmt->setFetchMode(\PDO::FETCH_ASSOC);

        // Initialize index for binding
        $bindIndex = 1;

        // Bind statusComment filter, required due to comments not being so.
        $statusComment = !empty($filterArray[0]) ? "%" . $filterArray[0] . "%" : null;
        $stmt->bindValue($bindIndex++, $statusComment ?? "%", \PDO::PARAM_STR); // First ?
        $stmt->bindValue($bindIndex++, $statusComment, $statusComment === null ? \PDO::PARAM_NULL : \PDO::PARAM_STR); // Second ?

        // Bind other filters
        for ($i = 1; $i <= 8; $i++) { // Assuming 8 other filters
            $value = !empty($filterArray[$i]) ? "%" . $filterArray[$i] . "%" : "%";
            $stmt->bindValue($bindIndex++, $value, \PDO::PARAM_STR);
        }
        return $stmt;
    }

    public function setFilterUri($term, $category)
    {
        $uri = $_SERVER['REQUEST_URI'];
        $uriComp = parse_url($uri);
        $params = [];

        // Parse existing query parameters
        if (isset($uriComp['query'])) {
            parse_str($uriComp['query'], $params);
        } else {
            $params = array();
        }
        // Avoid unnecessary redirection if the filter is already correct
        if ((isset($params['category']) && $params['category'] === $category) && (isset($params['term']) && $params['term'] === $term)) {
            exit; // Do nothing if filter already applied
        }

        // Update the 'page' parameter
        $params['category'] = $category;
        $params['term'] = $term;

        // Rebuild the query string
        $newUri = http_build_query($params);
        var_dump($newUri);

        // Redirect to the updated URI
        // Use the current path or root
        return
            [
                'newUri' => $newUri,
                'path' => $uriComp['path'] ?? '/'
            ];    }

}

