<?php
defined('ABSPATH') or die('Direct access not allowed');

/**
 * VollstartRD — Main singleton orchestrator.
 *
 * SRP: Lazy-loads and provides access to all subsystems.
 * No business logic here — only wiring and lifecycle management.
 */
class VollstartRD {

    private ?VollstartRD_DB $db = null;
    private ?VollstartRD_Options $options = null;
    private ?VollstartRD_Admin $admin = null;
    private ?VollstartRD_Customers $customers = null;
    private ?VollstartRD_Products $products = null;
    private ?VollstartRD_Repairs $repairs = null;
    private ?VollstartRD_RepairTypes $repairTypes = null;
    private ?VollstartRD_Checklists $checklists = null;
    private ?VollstartRD_Support $support = null;
    private ?VollstartRD_FileUpload $fileUpload = null;
    private ?VollstartRD_Frontend $frontend = null;
    private ?VollstartRD_Notifications $notifications = null;
    private ?VollstartRD_Ratings $ratings = null;
    private ?VollstartRD_PDF $pdf = null;

    private string $prefix = 'vollstartRd_';

    public static function Instance(): self {
        static $inst = null;
        if ($inst === null) {
            $inst = new self();
        }
        return $inst;
    }

    private function __construct() {
        // Translations load automatically: WordPress 4.6+ fetches plugin translations
        // from WordPress.org on the 'init' hook — no load_plugin_textdomain() needed.
        add_action('init', [$this, 'handleFileServe']);
        add_action('init', [$this, 'initSubsystems']);
    }

    /**
     * Initialize subsystems on 'init' hook (deferred from constructor).
     */
    public function initSubsystems(): void {
        if (is_admin()) {
            $this->getAdmin();
        }
        // Frontend always loads (shortcodes + public AJAX)
        $this->getFrontend();
        // Schedule pickup reminder cron (registers hook + checks schedule)
        $this->getNotifications()->schedulePickupReminder();
    }

    /**
     * Serve files via download token (?vollstart_rd_file=TOKEN).
     */
    public function handleFileServe(): void {
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- public file serving via unique download token, no state change
        if (isset($_GET['vollstart_rd_file']) && !empty($_GET['vollstart_rd_file'])) {
            // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- public file serving via unique download token, no state change
            $this->getFileUpload()->serveFile(sanitize_text_field(wp_unslash($_GET['vollstart_rd_file'])));
        }
    }

    // --- Getters (lazy-loaded) ---

    public function getDB(): VollstartRD_DB {
        if ($this->db === null) {
            require_once VOLLSTART_RD_PLUGIN_DIR_PATH . 'db.php';
            $this->db = new VollstartRD_DB($this);
            // installiereTabellen(false) runs in DB constructor — checks version, no-op if current
        }
        return $this->db;
    }

    public function getOptions(): VollstartRD_Options {
        if ($this->options === null) {
            require_once VOLLSTART_RD_PLUGIN_DIR_PATH . 'includes/class-options.php';
            $this->options = new VollstartRD_Options($this);
        }
        return $this->options;
    }

    public function getAdmin(): VollstartRD_Admin {
        if ($this->admin === null) {
            require_once VOLLSTART_RD_PLUGIN_DIR_PATH . 'includes/class-admin.php';
            $this->admin = new VollstartRD_Admin($this);
        }
        return $this->admin;
    }

    public function getCustomers(): VollstartRD_Customers {
        if ($this->customers === null) {
            require_once VOLLSTART_RD_PLUGIN_DIR_PATH . 'includes/class-customers.php';
            $this->customers = new VollstartRD_Customers($this);
        }
        return $this->customers;
    }

    public function getProducts(): VollstartRD_Products {
        if ($this->products === null) {
            require_once VOLLSTART_RD_PLUGIN_DIR_PATH . 'includes/class-products.php';
            $this->products = new VollstartRD_Products($this);
        }
        return $this->products;
    }

    public function getRepairs(): VollstartRD_Repairs {
        if ($this->repairs === null) {
            require_once VOLLSTART_RD_PLUGIN_DIR_PATH . 'includes/class-repairs.php';
            $this->repairs = new VollstartRD_Repairs($this);
        }
        return $this->repairs;
    }

    public function getRepairTypes(): VollstartRD_RepairTypes {
        if ($this->repairTypes === null) {
            require_once VOLLSTART_RD_PLUGIN_DIR_PATH . 'includes/class-repair-types.php';
            $this->repairTypes = new VollstartRD_RepairTypes($this);
        }
        return $this->repairTypes;
    }

    public function getChecklists(): VollstartRD_Checklists {
        if ($this->checklists === null) {
            require_once VOLLSTART_RD_PLUGIN_DIR_PATH . 'includes/class-checklists.php';
            $this->checklists = new VollstartRD_Checklists($this);
        }
        return $this->checklists;
    }

    public function getFileUpload(): VollstartRD_FileUpload {
        if ($this->fileUpload === null) {
            require_once VOLLSTART_RD_PLUGIN_DIR_PATH . 'includes/class-file-upload.php';
            $this->fileUpload = new VollstartRD_FileUpload($this);
        }
        return $this->fileUpload;
    }

    public function getFrontend(): VollstartRD_Frontend {
        if ($this->frontend === null) {
            require_once VOLLSTART_RD_PLUGIN_DIR_PATH . 'includes/class-frontend.php';
            $this->frontend = new VollstartRD_Frontend($this);
        }
        return $this->frontend;
    }

    public function getNotifications(): VollstartRD_Notifications {
        if ($this->notifications === null) {
            require_once VOLLSTART_RD_PLUGIN_DIR_PATH . 'includes/class-notifications.php';
            $this->notifications = new VollstartRD_Notifications($this);
        }
        return $this->notifications;
    }

    public function getPdf(): VollstartRD_PDF {
        if ($this->pdf === null) {
            require_once VOLLSTART_RD_PLUGIN_DIR_PATH . 'includes/class-pdf.php';
            $this->pdf = new VollstartRD_PDF($this);
        }
        return $this->pdf;
    }

    public function getRatings(): VollstartRD_Ratings {
        if ($this->ratings === null) {
            require_once VOLLSTART_RD_PLUGIN_DIR_PATH . 'includes/class-ratings.php';
            $this->ratings = new VollstartRD_Ratings($this);
        }
        return $this->ratings;
    }

    public function getSupport(): VollstartRD_Support {
        if ($this->support === null) {
            require_once VOLLSTART_RD_PLUGIN_DIR_PATH . 'includes/class-support.php';
            $this->support = new VollstartRD_Support($this);
        }
        return $this->support;
    }

    // --- Utility ---

    public function getPrefix(): string {
        return $this->prefix;
    }


    public function getPluginVersion(): string {
        return VOLLSTART_RD_PLUGIN_VERSION;
    }

    /**
     * Get currency symbol. Priority: Options → WooCommerce → EUR fallback.
     */
    public function getCurrency(): string {
        $opt = $this->getOptions()->getOptionValue('currency');
        if (!empty($opt)) {
            return $opt;
        }
        if (function_exists('get_woocommerce_currency_symbol')) {
            return html_entity_decode(get_woocommerce_currency_symbol(), ENT_QUOTES, 'UTF-8');
        }
        return 'EUR';
    }

    /**
     * Sanitize a POST array at an AJAX entry point.
     *
     * Applies wp_unslash() once and then sanitize_text_field() recursively
     * to every scalar value. For fields that need newline preservation
     * (textareas), pass their keys in $textareaFields — they get
     * sanitize_textarea_field() instead.
     *
     * Manager methods may apply additional field-specific sanitization;
     * this helper is the first-pass entry-point sanitizer required by
     * WordPress Plugin Check.
     *
     * @param array $data           Raw $_POST (or any unsanitized array).
     * @param array $textareaFields Field keys to treat as textareas.
     * @return array Sanitized copy.
     */
    public static function sanitizePostArray(array $data, array $textareaFields = []): array {
        $unslashed = wp_unslash($data);
        $textareaSet = array_flip($textareaFields);
        $result = [];
        foreach ($unslashed as $key => $value) {
            if (isset($textareaSet[$key]) && is_string($value)) {
                $result[$key] = sanitize_textarea_field($value);
            } else {
                $result[$key] = self::sanitizeRecursive($value);
            }
        }
        return $result;
    }

    private static function sanitizeRecursive($value) {
        if (is_array($value)) {
            return array_map([__CLASS__, 'sanitizeRecursive'], $value);
        }
        if (is_scalar($value)) {
            return sanitize_text_field((string) $value);
        }
        return $value;
    }
}
