<?php

namespace Flyerimage\App\Services;

use Flyerimage\Core\Database\QueryBuilder;
use Flyerimage\Core\Util\Helper;
use Flyerimage\Core\Database\MigrationBase;

/**
 * Abstract service
 * 
 * @author Shaiful Islam Palash <kuvic16@gmail.com>
 * @author Pritom Kumar Mondal <pritomkucse@gmail.com>
 * @version
 */
abstract class AbstractService
{
    protected $params;

    /**
     * Respected table name of the service
     * @var string
     */
    protected $table_name;

    /**
     * Constructor of abstract service
     * @return void
     */
    public function __construct($table_name)
    {
        $this->table_name = $table_name;
    }

    /**
     * Find by id
     * 
     * @param int $id
     * 
     * @return object
     */
    public function find_by_id($id)
    {
        return QueryBuilder::table($this->table_name)->find_by_id($id);
    }

    /**
     * Get all the records of respoected table
     * @return array
     */
    public function get_all()
    {
        return QueryBuilder::table($this->table_name)->get();
    }

    public function setParams($params) {
        $this->params = $params;
    }

    public function registerParams($skip_nonce_check = false) {
        $CONTENT_TYPE = isset($_SERVER["CONTENT_TYPE"]) ? strtolower( sanitize_text_field( wp_unslash( $_SERVER["CONTENT_TYPE"] ) ) ) : "";
        $REQUEST_METHOD = isset($_SERVER["REQUEST_METHOD"]) ? strtolower( sanitize_text_field( wp_unslash( $_SERVER["REQUEST_METHOD"] ) ) ) : "";
        if ($REQUEST_METHOD == "post") {
            if (str_starts_with($CONTENT_TYPE, "application/json")) {
                if (!$skip_nonce_check) {
                    $nonce = isset($_SERVER['HTTP_X_WP_NONCE']) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_WP_NONCE'] ) ) : '';
                    if ( ! wp_verify_nonce($nonce, 'wp_rest') ) {
                        throw new \Exception('Invalid nonce', 403);
                    }
                }
                $input = file_get_contents('php://input');
                // Validate JSON input is not empty
                if (empty($input)) {
                    throw new \Exception("Invalid request body, empty input");
                }
                // Decode JSON and check for errors
                $decoded = json_decode($input, true);
                if (json_last_error() !== JSON_ERROR_NONE) {
                    throw new \Exception("Invalid JSON: " . esc_html(json_last_error_msg()));
                }
                // Sanitize the decoded data
                $this->params = is_array($decoded) ? $this->recursive_sanitize_text_field(wp_unslash($decoded)) : [];
                if (count($this->params) == 0) {
                    throw new \Exception("Invalid request body, could not decode");
                }
            }
            else {
                throw new \Exception("Invalid request body, could not decode");
            }
        }
        else {
            if ($REQUEST_METHOD == "post") {
                if (!$skip_nonce_check) {
                    $nonce = isset($_SERVER['HTTP_X_WP_NONCE']) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_WP_NONCE'] ) ) : '';
                    if ( ! wp_verify_nonce($nonce, 'wp_rest') ) {
                        throw new \Exception('Invalid nonce', 403);
                    }
                }
                $this->params = $this->recursive_sanitize_text_field(wp_unslash($_POST));
            }
            else if ($REQUEST_METHOD == "get") {
                $this->params = $this->recursive_sanitize_text_field(wp_unslash($_GET));
            }
            else {
                throw new \Exception("Invalid request body, could not decode");
            }
        }
    }

    public function getParamValue($name, $default = null) {
        return isset($this->params[$name]) ? $this->recursive_sanitize_text_field(wp_unslash($this->params[$name])) : $default;
    }

    public function getParamString($name, $default = null, $max_length = 0) {
        $value = isset($this->params[$name]) ? sanitize_text_field(wp_unslash($this->params[$name])) : $default;
        return Helper::get_sub_string($value, $max_length);
    }

    public function validateIntegerValue($value, $min, $max) {
        if (Helper::is_positive_integer($value)) {
            $value = intval($value);
            return min(max($value, $min), $max);
        }
        return $min;
    }

    public function get_type($data) {
        return gettype($data);
    }

    public function doMigration() {
        $migration_path = implode(DIRECTORY_SEPARATOR, [
            FLYER_IMAGE_PATH, "src", "Core", "Migration"
        ]);

        if (defined('WP_DEBUG') && WP_DEBUG) {
            error_log( "Migration running - $migration_path" );
        }

        $files = scandir($migration_path, SCANDIR_SORT_ASCENDING);
        foreach ($files as $file) {
            // Ignore directories and abstract classes.
            if (is_dir($file) || 0 === stripos($file, 'Abstract')) {
                continue;
            }
            $file = explode('.', $file);
            $file = $file[0];

            $path = $migration_path . DIRECTORY_SEPARATOR . $file;

            $class = $this->get_migration_class($path);
            $class->fileName = $file;
            $class->up();
            $class->runMigration();
        }
    }

    public function get_table($table_name) {
        global $wpdb;
        return sprintf("%s%s%s", $wpdb->prefix, MigrationBase::$table_prefix, $table_name);
    }

    private function get_migration_class($path) {
        return include_once "$path.php";
    }

    /**
     * Recursively sanitize all values in an array.
     *
     * @param array $array
     * @return array
     */
    private function recursive_sanitize_text_field($array) {
        foreach ($array as $key => $value) {
            if (is_array($value)) {
                $array[$key] = $this->recursive_sanitize_text_field($value);
            }
            else {
                $array[$key] = sanitize_text_field($value);
            }
        }
        return $array;
    }

    public function logMessage($message) {}
}