<?php

declare(strict_types=1);

namespace App\Models;

use App\Lib\Database;
use App\Models\{Dish, Menu, Restaurant};
use App\Helpers\DateTime;
use App\Util\{DeviceManager, Helper, JWTManager};

class Customer
{
    protected $db;
    private string $tableName = 'customer';
    protected DeviceManager $userSession;
    public static $uploadDirectory = UPLOADS['customer_upload'];
    public static $publicDirectory = UPLOADS['customer_dir'];

    public function __construct()
    {
        $this->db = Database::connectDB();
        $this->userSession = new DeviceManager;
    }

    public function getById(int $customerId, $selection = '*')
    {
        $stmt = $this->db->fetch("SELECT {$selection} FROM {$this->tableName} WHERE customer_id = ? LIMIT 1", $customerId);
        return $stmt;
    }

    public function getByEmail(string $customerEmail, $selection = '*')
    {
        $stmt = $this->db->fetch("SELECT {$selection} FROM {$this->tableName} WHERE customer_email = ? LIMIT 1", $customerEmail);
        return $stmt;
    }

    public function getSelectedAddress(string $customerId)
    {
        $stmt = $this->db->fetch("SELECT * FROM {$this->tableName}_address WHERE customer_id = ? AND address_selected = 'true' LIMIT 1", $customerId);
        return $stmt;
    }

    public function emailExist(string $email): int|bool
    {
        $stmt = $this->db->query("SELECT * FROM {$this->tableName} WHERE customer_email = ?", $email);
        return $stmt->rowCount() ?? false;
    }

    public function listCustomers($limit = null, $offset = null)
    {
        $query = "SELECT * FROM {$this->tableName} ORDER BY created_at DESC";

        if (!is_null($limit)) {
            $query .= " LIMIT " . intval($limit);

            if (!is_null($offset)) {
                $query .= " OFFSET " . intval($offset);
            }
        }

        $result = $this->db->fetchAll($query);

        return $result;
    }

    public function listApproved($limit = null, $offset = null)
    {
        $query = "SELECT * FROM {$this->tableName} WHERE customer_status = 'active' ORDER BY created_at DESC";

        if (!is_null($limit)) {
            $query .= " LIMIT " . intval($limit);

            if (!is_null($offset)) {
                $query .= " OFFSET " . intval($offset);
            }
        }

        $result = $this->db->fetchAll($query);

        return $result;
    }

    public function listPending($limit = null, $offset = null)
    {
        $query = "SELECT * FROM {$this->tableName} WHERE customer_status = 'pending' ORDER BY created_at DESC";

        if (!is_null($limit)) {
            $query .= " LIMIT " . intval($limit);

            if (!is_null($offset)) {
                $query .= " OFFSET " . intval($offset);
            }
        }

        $result = $this->db->fetchAll($query);

        return $result;
    }

    public function listDisabled($limit = null, $offset = null)
    {
        $query = "SELECT * FROM {$this->tableName} WHERE customer_status = 'disabled' ORDER BY created_at DESC";

        if (!is_null($limit)) {
            $query .= " LIMIT " . intval($limit);

            if (!is_null($offset)) {
                $query .= " OFFSET " . intval($offset);
            }
        }

        $result = $this->db->fetchAll($query);

        return $result;
    }

    public function listAddress(int $customerId, $limit = null, $offset = null)
    {
        $query = "SELECT * FROM {$this->tableName}_address WHERE customer_id = ? ORDER BY created_at DESC";

        if (!is_null($limit)) {
            $query .= " LIMIT " . intval($limit);

            if (!is_null($offset)) {
                $query .= " OFFSET " . intval($offset);
            }
        }

        $result = $this->db->fetchAll($query, $customerId);

        return $result;
    }

    public function listWishlist(int $customerId, $limit = null, $offset = null)
    {
        $query = "SELECT * FROM {$this->tableName}_wishlist WHERE customer_id = ? ORDER BY created_at DESC";

        if (!is_null($limit)) {
            $query .= " LIMIT " . intval($limit);

            if (!is_null($offset)) {
                $query .= " OFFSET " . intval($offset);
            }
        }

        $result = $this->db->fetchAll($query, $customerId);

        return $result;
    }

    public function listSearchHistory(int $customerId, $limit = null, $offset = null)
    {
        $query = "SELECT * FROM {$this->tableName}_search WHERE customer_id = ? ORDER BY created_at DESC";

        if (!is_null($limit)) {
            $query .= " LIMIT " . intval($limit);

            if (!is_null($offset)) {
                $query .= " OFFSET " . intval($offset);
            }
        }

        $result = $this->db->fetchAll($query, $customerId);

        return $result;
    }

    /**
     * Adds a customer to the database.
     *
     * @param array $data The customer data.
     * @throws Some_Exception_Class The exception description.
     * @return int|bool The customer ID if successful, false otherwise.
     */
    public function addCustomer(array $data): int|bool
    {
        $customerId = $this->db->transaction(function ($db) use ($data) {

            $db->query(
                "INSERT INTO customer",
                [
                    'customer_id' => null,
                    'first_name' => $data['first_name'],
                    'last_name' => $data['last_name'],
                    'customer_email' => $data['customer_email'],
                    'customer_phone' => '',
                    'customer_passcode' => '',
                    'customer_address' => '',
                    'customer_ip' => $data['customer_ip'],
                    'customer_device' => $data['customer_device'],
                    'customer_device_hash' => $data['customer_device_hash'],
                    'customer_session' => $data['customer_session'],
                    'customer_latitude' => $data['customer_latitude'],
                    'customer_longitude' => $data['customer_longitude'],
                    'customer_avatar' => $data['customer_avatar'],
                    'customer_status' => 'active',
                    'oauth_provider' => $data['customer_oauth'],
                    'oauth_uid' => $data['customer_oauth_id'],
                ]
            );

            $getCustomerId = (int) $db->getInsertId();

            $db->query("INSERT INTO customer_address", [
                'address_id' => null,
                'customer_id' => $getCustomerId,
                'customer_email' => $data['customer_email'],
                'customer_ip' => $data['customer_ip'],
                'customer_address' => 'Current Location',
                'address_alias' => 'CL',
                'address_type' => 'home',
                'address_latitude' => $data['customer_latitude'],
                'address_longitude' => $data['customer_longitude'],
                'address_selected' => 'true',
            ]);

            return $getCustomerId;
        });

        return $customerId ?? false;
    }
}
