<?php
/**
 * Payment Model
 *
 * @package Easy_Invoice
 */

namespace EasyInvoice\Models;

class Payment {
    /**
     * Payment ID
     *
     * @var int
     */
    private $id;

    /**
     * Dynamic data storage for all fields
     *
     * @var array
     */
    private $data = [];

    /**
     * Modified flag
     *
     * @var bool
     */
    private $is_modified = false;

    /**
     * Constructor
     *
     * @param \WP_Post|int $post
     */
    public function __construct($post) {
        if (is_numeric($post)) {
            $post = get_post($post);
        }
        
        if (!$post || $post->post_type !== 'easy_invoice_payment') {
            throw new \Exception('Invalid payment post');
        }

        $this->id = $post->ID;
        $this->loadMeta();
    }

    /**
     * Load payment meta data
     */
    private function loadMeta() {
        $this->data = array(
            'invoice_id' => get_post_meta($this->id, '_invoice_id', true),
            'amount' => get_post_meta($this->id, '_amount', true),
            'payment_method' => get_post_meta($this->id, '_payment_method', true),
            'status' => get_post_meta($this->id, '_status', true),
            'transaction_id' => get_post_meta($this->id, '_transaction_id', true),
            'payment_date' => get_post_meta($this->id, '_payment_date', true),
            'notes' => get_post_meta($this->id, '_notes', true),
            'payment_type' => get_post_meta($this->id, '_payment_type', true),
            'recurring_id' => get_post_meta($this->id, '_recurring_id', true),
            'parent_payment_id' => get_post_meta($this->id, '_parent_payment_id', true),
            'gateway_response' => get_post_meta($this->id, '_gateway_response', true),
            'currency' => get_post_meta($this->id, '_currency', true),
            'currency_symbol' => get_post_meta($this->id, '_currency_symbol', true),
        );
    }

    /**
     * Magic getter for dynamic properties
     *
     * @param string $name
     * @return mixed
     */
    public function __get($name) {
        if (isset($this->data[$name])) {
            return $this->data[$name];
        }
        return null;
    }

    /**
     * Magic setter for dynamic properties
     *
     * @param string $name
     * @param mixed $value
     */
    public function __set($name, $value) {
        $this->data[$name] = $value;
        $this->is_modified = true;
    }

    /**
     * Magic isset for dynamic properties
     *
     * @param string $name
     * @return bool
     */
    public function __isset($name) {
        return isset($this->data[$name]);
    }

    /**
     * Magic unset for dynamic properties
     *
     * @param string $name
     */
    public function __unset($name) {
        unset($this->data[$name]);
        $this->is_modified = true;
    }

    /**
     * Dynamic getter method
     *
     * @since 1.0.0
     * @param string $name Method name
     * @param array $arguments Method arguments
     * @return mixed
     */
    public function __call($name, $arguments) {
        // Handle getter methods (getFieldName)
        if (strpos($name, 'get') === 0) {
            $field_name = $this->camelCaseToSnakeCase(substr($name, 3)); // Remove 'get' prefix
            return $this->__get($field_name);
        }
        
        // Handle setter methods (setFieldName)
        if (strpos($name, 'set') === 0) {
            $field_name = $this->camelCaseToSnakeCase(substr($name, 3)); // Remove 'set' prefix
            $value = $arguments[0] ?? null;
            $this->__set($field_name, $value);
            return null;
        }
        
        // Handle isset methods (isFieldName)
        if (strpos($name, 'is') === 0) {
            $field_name = $this->camelCaseToSnakeCase(substr($name, 2)); // Remove 'is' prefix
            return (bool) $this->__get($field_name);
        }
        
        // Handle has methods (hasFieldName)
        if (strpos($name, 'has') === 0) {
            $field_name = $this->camelCaseToSnakeCase(substr($name, 3)); // Remove 'has' prefix
            return !empty($this->__get($field_name));
        }
        
        throw new \BadMethodCallException("Method $name does not exist");
    }

    /**
     * Convert camelCase to snake_case
     *
     * @since 1.0.0
     * @param string $camelCase
     * @return string
     */
    private function camelCaseToSnakeCase($camelCase) {
        return strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', $camelCase));
    }

    // Essential methods only
    public function getId() { return $this->id; }
    public function isModified(): bool { return $this->is_modified; }
    public function toArray(): array { return array_merge(['id' => $this->id], $this->data); }
    
    /**
     * Check if payment exists
     *
     * @return bool
     */
    public function exists(): bool {
        return $this->id > 0 && get_post($this->id) !== null;
    }
    
    /**
     * Update payment data
     *
     * @param array $data Payment data to update
     * @return bool True on success, false on failure
     */
    public function update(array $data): bool {
        if (!$this->exists()) {
            return false;
        }
         
        // Update post meta for each field
        $meta_fields = [
            'invoice_id' => '_invoice_id',
            'amount' => '_amount',
            'payment_method' => '_payment_method',
            'status' => '_status',
            'transaction_id' => '_transaction_id',
            'payment_date' => '_payment_date',
            'notes' => '_notes',
            'payment_type' => '_payment_type',
            'recurring_id' => '_recurring_id',
            'parent_payment_id' => '_parent_payment_id',
            'gateway_response' => '_gateway_response',
            'currency' => '_currency',
            'currency_symbol' => '_currency_symbol',
        ];
        
        $success = true;
        
        foreach ($meta_fields as $field => $meta_key) {
            if (isset($data[$field])) {
                // update_post_meta returns false if value is unchanged (not an error)
                // It returns meta_id on success, or true if updated
                // We need to check if the meta exists to determine real failure
                $old_value = get_post_meta($this->id, $meta_key, true);
                $result = update_post_meta($this->id, $meta_key, $data[$field]);
                
                // Only consider it a failure if the result is false AND the value wasn't already the same
                if ($result === false && $old_value !== $data[$field]) {
                    //$success = false;
                }
                
                // Always update local data since we're setting it
                $this->data[$field] = $data[$field];
            }
        }
        
        // Update the post title if invoice_id is provided
        if (isset($data['invoice_id']) && $data['invoice_id']) {
            $invoice = new \EasyInvoice\Models\Invoice($data['invoice_id']);
            if ($invoice->exists()) {
                $post_title = sprintf(
                    __('Payment for Invoice %s', 'easy-invoice'),
                    $invoice->getNumber()
                );
                wp_update_post([
                    'ID' => $this->id,
                    'post_title' => $post_title
                ]);
            }
        }
        
        $this->is_modified = false;
        return $success;
    }
} 