<?php
/**
 * Price rule model
 *
 * @package WahraRentalsBookings
 */

defined('ABSPATH') || exit;

/**
 * Price rule class
 */
class WAHRB_Price_Rule {

    /**
     * Rule ID
     *
     * @var int
     */
    private int $id = 0;

    /**
     * Rule data
     *
     * @var array
     */
    private array $data = [];

    /**
     * Database instance
     *
     * @var WAHRB_Database
     */
    private WAHRB_Database $db;

    /**
     * Constructor
     *
     * @param int|array $rule Rule ID or data
     */
    public function __construct($rule = 0) {
        $this->db = WAHRB_Database::instance();

        if (is_numeric($rule) && $rule > 0) {
            $this->id = (int) $rule;
            $this->read();
        } elseif (is_array($rule)) {
            $this->set_data($rule);
        }
    }

    /**
     * Read rule from database
     */
    private function read(): void {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $row = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$this->db->table('price_rules')} WHERE rule_id = %d",
            $this->id
        ), ARRAY_A);

        if ($row) {
            $this->set_data($row);
        }
    }

    /**
     * Set rule data
     *
     * @param array $data Rule data
     */
    private function set_data(array $data): void {
        $this->data = $data;
        if (isset($data['rule_id'])) {
            $this->id = (int) $data['rule_id'];
        }

        // Parse JSON fields
        if (isset($this->data['weekdays']) && is_string($this->data['weekdays'])) {
            $this->data['weekdays'] = json_decode($this->data['weekdays'], true);
        }
    }

    /**
     * Get rule ID
     *
     * @return int
     */
    public function get_id(): int {
        return $this->id;
    }

    /**
     * Get property
     *
     * @param string $key Property key
     * @param mixed $default Default value
     * @return mixed
     */
    public function get(string $key, $default = null) {
        return $this->data[$key] ?? $default;
    }

    /**
     * Create a new price rule
     *
     * @param array $data Rule data
     * @return WAHRB_Price_Rule|WP_Error
     */
    public static function create(array $data) {
        global $wpdb;
        $db = WAHRB_Database::instance();

        // Validate required fields
        $required = ['vendor_id', 'product_id', 'rule_name', 'rule_type', 'modifier_type', 'modifier_value'];
        foreach ($required as $field) {
            if (empty($data[$field]) && $data[$field] !== 0 && $data[$field] !== '0') {
                /* translators: %s: required field name */
                return new WP_Error('missing_field', sprintf(__('Field %s is required', 'wahra-rentals-bookings'), $field));
            }
        }

        // Validate rule type
        $valid_types = ['date_range', 'weekday', 'duration', 'guests'];
        if (!in_array($data['rule_type'], $valid_types)) {
            return new WP_Error('invalid_type', __('Invalid rule type', 'wahra-rentals-bookings'));
        }

        // Validate modifier type
        if (!in_array($data['modifier_type'], ['fixed', 'percent'])) {
            return new WP_Error('invalid_modifier', __('Invalid modifier type', 'wahra-rentals-bookings'));
        }

        $insert_data = [
            'vendor_id' => absint($data['vendor_id']),
            'product_id' => absint($data['product_id']),
            'variation_id' => !empty($data['variation_id']) ? absint($data['variation_id']) : null,
            'rule_name' => sanitize_text_field($data['rule_name']),
            'rule_type' => $data['rule_type'],
            'date_start' => !empty($data['date_start']) ? sanitize_text_field($data['date_start']) : null,
            'date_end' => !empty($data['date_end']) ? sanitize_text_field($data['date_end']) : null,
            'weekday' => !empty($data['weekday']) ? absint($data['weekday']) : null,
            'weekdays' => !empty($data['weekdays']) ? wp_json_encode($data['weekdays']) : null,
            'min_duration_days' => !empty($data['min_duration_days']) ? absint($data['min_duration_days']) : null,
            'max_duration_days' => !empty($data['max_duration_days']) ? absint($data['max_duration_days']) : null,
            'min_guests' => !empty($data['min_guests']) ? absint($data['min_guests']) : null,
            'max_guests' => !empty($data['max_guests']) ? absint($data['max_guests']) : null,
            'modifier_type' => $data['modifier_type'],
            'modifier_value' => floatval($data['modifier_value']),
            'priority' => absint($data['priority'] ?? 0),
            'active' => isset($data['active']) ? (int) $data['active'] : 1,
        ];

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $result = $wpdb->insert($db->table('price_rules'), $insert_data);

        if (!$result) {
            return new WP_Error('db_error', __('Error creating price rule', 'wahra-rentals-bookings'));
        }

        return new self($wpdb->insert_id);
    }

    /**
     * Update rule
     *
     * @param array $data Data to update
     * @return bool
     */
    public function update(array $data): bool {
        global $wpdb;

        $allowed_fields = [
            'rule_name', 'rule_type', 'date_start', 'date_end', 'weekday', 'weekdays',
            'min_duration_days', 'max_duration_days', 'min_guests', 'max_guests',
            'modifier_type', 'modifier_value', 'priority', 'active',
        ];

        $update_data = [];
        foreach ($allowed_fields as $field) {
            if (isset($data[$field])) {
                if ($field === 'weekdays' && is_array($data[$field])) {
                    $update_data[$field] = wp_json_encode($data[$field]);
                } else {
                    $update_data[$field] = $data[$field];
                }
            }
        }

        if (empty($update_data)) {
            return false;
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $result = $wpdb->update(
            $this->db->table('price_rules'),
            $update_data,
            ['rule_id' => $this->id]
        );

        if ($result !== false) {
            foreach ($update_data as $key => $value) {
                $this->data[$key] = $value;
            }
            return true;
        }

        return false;
    }

    /**
     * Delete rule
     *
     * @return bool
     */
    public function delete(): bool {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $result = $wpdb->delete(
            $this->db->table('price_rules'),
            ['rule_id' => $this->id]
        );

        return $result !== false;
    }

    /**
     * Get rules for a product
     *
     * @param int $product_id Product ID
     * @param int|null $variation_id Variation ID
     * @param bool $active_only Only return active rules
     * @return array
     */
    public static function get_for_product(int $product_id, ?int $variation_id = null, bool $active_only = true): array {
        global $wpdb;
        $db = WAHRB_Database::instance();

        $where = 'product_id = %d';
        $params = [$product_id];

        if ($variation_id) {
            $where .= ' AND (variation_id IS NULL OR variation_id = %d)';
            $params[] = $variation_id;
        }

        if ($active_only) {
            $where .= ' AND active = 1';
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        $results = $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$db->table('price_rules')}
             WHERE {$where}
             ORDER BY priority ASC",
            $params
        ), ARRAY_A);

        return array_map(function($row) {
            return new self($row);
        }, $results ?: []);
    }

    /**
     * Bulk update priorities
     *
     * @param array $priorities Array of rule_id => priority
     * @return bool
     */
    public static function bulk_update_priorities(array $priorities): bool {
        global $wpdb;
        $db = WAHRB_Database::instance();

        foreach ($priorities as $rule_id => $priority) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
            $wpdb->update(
                $db->table('price_rules'),
                ['priority' => absint($priority)],
                ['rule_id' => absint($rule_id)]
            );
        }

        return true;
    }

    /**
     * Convert to array
     *
     * @return array
     */
    public function to_array(): array {
        return $this->data;
    }
}
