<?php
/**
 * GGM Commerce Address Manager Class
 * Handles customer address operations for multiple billing/shipping addresses
 */

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
// phpcs:disable PluginCheck.Security.DirectDB.UnescapedDBParameter

class GGM_Commerce_Address_Manager {

    /**
     * Get customer ID from user ID
     */
    private function get_customer_id($user_id) {
        global $wpdb;

        $user = get_userdata($user_id);
        if (!$user) {
            return null;
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $customer = $wpdb->get_row($wpdb->prepare(
            "SELECT id FROM {$wpdb->prefix}ggmc_customers WHERE user_id = %d OR email = %s LIMIT 1",
            $user_id,
            $user->user_email
        ));

        return $customer ? $customer->id : null;
    }

    /**
     * Create customer record if it doesn't exist
     */
    private function ensure_customer_exists($user_id) {
        global $wpdb;

        $customer_id = $this->get_customer_id($user_id);
        if ($customer_id) {
            return $customer_id;
        }

        // Create customer record
        $user = get_userdata($user_id);
        if (!$user) {
            return null;
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->insert(
            "{$wpdb->prefix}ggmc_customers",
            [
                'user_id' => $user_id,
                'email' => $user->user_email,
                'first_name' => get_user_meta($user_id, 'first_name', true) ?: '',
                'last_name' => get_user_meta($user_id, 'last_name', true) ?: '',
                'phone' => get_user_meta($user_id, 'phone', true) ?: ''
            ],
            ['%d', '%s', '%s', '%s', '%s']
        );

        return $wpdb->insert_id;
    }

    /**
     * Get all addresses for a user
     */
    public function get_user_addresses($user_id, $address_type = null) {
        global $wpdb;

        // Auto-create customer record if it doesn't exist
        $customer_id = $this->ensure_customer_exists($user_id);
        if (!$customer_id) {
            return [];
        }

        $query = "SELECT * FROM {$wpdb->prefix}ggmc_customer_addresses WHERE customer_id = %d";
        $params = [$customer_id];

        if ($address_type) {
            $query .= " AND address_type = %s";
            $params[] = $address_type;
        }

        $query .= " ORDER BY is_default DESC, created_at DESC";

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- $query is built safely above with conditionals
        return $wpdb->get_results($wpdb->prepare($query, $params));
    }

    /**
     * Get default address for a user
     */
    public function get_default_address($user_id, $address_type) {
        global $wpdb;

        // Auto-create customer record if it doesn't exist
        $customer_id = $this->ensure_customer_exists($user_id);
        if (!$customer_id) {
            return null;
        }

        // Try to get default address
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $address = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$wpdb->prefix}ggmc_customer_addresses
             WHERE customer_id = %d AND address_type = %s AND is_default = 1
             LIMIT 1",
            $customer_id,
            $address_type
        ));

        // If no default, get most recent
        if (!$address) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $address = $wpdb->get_row($wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}ggmc_customer_addresses
                 WHERE customer_id = %d AND address_type = %s
                 ORDER BY created_at DESC
                 LIMIT 1",
                $customer_id,
                $address_type
            ));
        }

        return $address;
    }

    /**
     * Get address by ID
     */
    public function get_address($address_id, $user_id = null) {
        global $wpdb;

        $query = "SELECT * FROM {$wpdb->prefix}ggmc_customer_addresses WHERE id = %d";
        $params = [$address_id];

        // If user_id provided, verify ownership
        if ($user_id) {
            $customer_id = $this->get_customer_id($user_id);
            if (!$customer_id) {
                return null;
            }
            $query .= " AND customer_id = %d";
            $params[] = $customer_id;
        }

        $query .= " LIMIT 1";

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- $query is built safely above with conditionals
        return $wpdb->get_row($wpdb->prepare($query, $params));
    }

    /**
     * Add new address for a user
     */
    public function add_address($user_id, $address_data) {
        global $wpdb;

        // Ensure customer exists
        $customer_id = $this->ensure_customer_exists($user_id);
        if (!$customer_id) {
            return ['error' => 'Could not create or find customer record'];
        }

        // Validate required fields
        $address_type = isset($address_data['address_type']) ? $address_data['address_type'] : 'billing';
        if (!in_array($address_type, ['billing', 'shipping'])) {
            return ['error' => 'Invalid address type'];
        }

        // Check if this is the first address of this type
        $existing_count = $this->get_address_count($user_id, $address_type);

        // Check if this should be default
        // If it's the first address OR explicitly marked as default, make it default
        $is_default = ($existing_count === 0) || (isset($address_data['is_default']) && $address_data['is_default']) ? 1 : 0;

        // If setting as default, unset other defaults
        if ($is_default) {
            $this->unset_default_addresses($customer_id, $address_type);
        }

        // Prepare address data
        $insert_data = [
            'customer_id' => $customer_id,
            'address_type' => $address_type,
            'is_default' => $is_default,
            'address_label' => sanitize_text_field($address_data['address_label'] ?? ''),
            'first_name' => sanitize_text_field($address_data['first_name'] ?? ''),
            'last_name' => sanitize_text_field($address_data['last_name'] ?? ''),
            'company' => sanitize_text_field($address_data['company'] ?? ''),
            'address_1' => sanitize_text_field($address_data['address_1'] ?? ''),
            'address_2' => sanitize_text_field($address_data['address_2'] ?? ''),
            'city' => sanitize_text_field($address_data['city'] ?? ''),
            'state' => sanitize_text_field($address_data['state'] ?? ''),
            'postcode' => sanitize_text_field($address_data['postcode'] ?? ''),
            'country' => sanitize_text_field($address_data['country'] ?? ''),
            'phone' => sanitize_text_field($address_data['phone'] ?? '')
        ];

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $result = $wpdb->insert(
            "{$wpdb->prefix}ggmc_customer_addresses",
            $insert_data,
            ['%d', '%s', '%d', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s']
        );

        if ($result === false) {
            return ['error' => 'Failed to add address'];
        }

        return ['success' => true, 'address_id' => $wpdb->insert_id];
    }

    /**
     * Update existing address
     */
    public function update_address($address_id, $user_id, $address_data) {
        global $wpdb;

        $customer_id = $this->get_customer_id($user_id);
        if (!$customer_id) {
            return ['error' => 'Customer not found'];
        }

        // Verify ownership
        $existing = $this->get_address($address_id, $user_id);
        if (!$existing) {
            return ['error' => 'Address not found or access denied'];
        }

        // Check if setting as default
        $is_default = isset($address_data['is_default']) && $address_data['is_default'] ? 1 : 0;
        if ($is_default) {
            $this->unset_default_addresses($customer_id, $existing->address_type, $address_id);
        }

        // Prepare update data
        $update_data = [];
        $format = [];

        $allowed_fields = [
            'address_label', 'first_name', 'last_name', 'company',
            'address_1', 'address_2', 'city', 'state', 'postcode', 'country', 'phone'
        ];

        foreach ($allowed_fields as $field) {
            if (isset($address_data[$field])) {
                $update_data[$field] = sanitize_text_field($address_data[$field]);
                $format[] = '%s';
            }
        }

        if ($is_default !== null) {
            $update_data['is_default'] = $is_default;
            $format[] = '%d';
        }

        if (empty($update_data)) {
            return ['error' => 'No data to update'];
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $result = $wpdb->update(
            "{$wpdb->prefix}ggmc_customer_addresses",
            $update_data,
            ['id' => $address_id, 'customer_id' => $customer_id],
            $format,
            ['%d', '%d']
        );

        if ($result === false) {
            return ['error' => 'Failed to update address'];
        }

        return ['success' => true];
    }

    /**
     * Delete address
     */
    public function delete_address($address_id, $user_id) {
        global $wpdb;

        $customer_id = $this->get_customer_id($user_id);
        if (!$customer_id) {
            return ['error' => 'Customer not found'];
        }

        // Verify ownership and get address
        $address = $this->get_address($address_id, $user_id);
        if (!$address) {
            return ['error' => 'Address not found or access denied'];
        }

        // Check if this is the only address of this type
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $count = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$wpdb->prefix}ggmc_customer_addresses
             WHERE customer_id = %d AND address_type = %s",
            $customer_id,
            $address->address_type
        ));

        if ($count <= 1) {
            return ['error' => 'Cannot delete the only ' . $address->address_type . ' address'];
        }

        // Delete the address
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $result = $wpdb->delete(
            "{$wpdb->prefix}ggmc_customer_addresses",
            ['id' => $address_id, 'customer_id' => $customer_id],
            ['%d', '%d']
        );

        if ($result === false) {
            return ['error' => 'Failed to delete address'];
        }

        // If deleted address was default, set another as default
        if ($address->is_default) {
            $this->set_first_as_default($customer_id, $address->address_type);
        }

        return ['success' => true];
    }

    /**
     * Set address as default
     */
    public function set_default_address($address_id, $user_id) {
        global $wpdb;

        $customer_id = $this->get_customer_id($user_id);
        if (!$customer_id) {
            return ['error' => 'Customer not found'];
        }

        // Verify ownership
        $address = $this->get_address($address_id, $user_id);
        if (!$address) {
            return ['error' => 'Address not found or access denied'];
        }

        // Unset other defaults
        $this->unset_default_addresses($customer_id, $address->address_type, $address_id);

        // Set this as default
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $result = $wpdb->update(
            "{$wpdb->prefix}ggmc_customer_addresses",
            ['is_default' => 1],
            ['id' => $address_id],
            ['%d'],
            ['%d']
        );

        if ($result === false) {
            return ['error' => 'Failed to set default address'];
        }

        return ['success' => true];
    }

    /**
     * Unset all default addresses of a type (except optionally one)
     */
    private function unset_default_addresses($customer_id, $address_type, $except_id = null) {
        global $wpdb;

        $query = "UPDATE {$wpdb->prefix}ggmc_customer_addresses
                  SET is_default = 0
                  WHERE customer_id = %d AND address_type = %s";
        $params = [$customer_id, $address_type];

        if ($except_id) {
            $query .= " AND id != %d";
            $params[] = $except_id;
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- $query is built safely above with conditionals
        $wpdb->query($wpdb->prepare($query, $params));
    }

    /**
     * Set first address as default (used after deleting default address)
     */
    private function set_first_as_default($customer_id, $address_type) {
        global $wpdb;

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $first_address = $wpdb->get_row($wpdb->prepare(
            "SELECT id FROM {$wpdb->prefix}ggmc_customer_addresses
             WHERE customer_id = %d AND address_type = %s
             ORDER BY created_at ASC
             LIMIT 1",
            $customer_id,
            $address_type
        ));

        if ($first_address) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->update(
                "{$wpdb->prefix}ggmc_customer_addresses",
                ['is_default' => 1],
                ['id' => $first_address->id],
                ['%d'],
                ['%d']
            );
        }
    }

    /**
     * Check if multiple addresses are enabled
     */
    public function are_multiple_billing_addresses_enabled() {
        return (bool) get_option('ggm_commerce_allow_multiple_billing', false);
    }

    /**
     * Check if multiple shipping addresses are enabled
     */
    public function are_multiple_shipping_addresses_enabled() {
        return (bool) get_option('ggm_commerce_allow_multiple_shipping', false);
    }

    /**
     * Check if multiple addresses are enabled for a type
     */
    public function are_multiple_addresses_enabled($address_type) {
        if ($address_type === 'billing') {
            return $this->are_multiple_billing_addresses_enabled();
        } elseif ($address_type === 'shipping') {
            return $this->are_multiple_shipping_addresses_enabled();
        }
        return false;
    }

    /**
     * Get address count for user by type
     */
    public function get_address_count($user_id, $address_type) {
        global $wpdb;

        $customer_id = $this->get_customer_id($user_id);
        if (!$customer_id) {
            return 0;
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        return (int) $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$wpdb->prefix}ggmc_customer_addresses
             WHERE customer_id = %d AND address_type = %s",
            $customer_id,
            $address_type
        ));
    }

    /**
     * Format address for display
     */
    public function format_address($address, $format = 'html') {
        if (!$address) {
            return '';
        }

        $parts = array_filter([
            $address->address_1,
            $address->address_2,
            $address->city,
            $address->state,
            $address->postcode,
            $address->country
        ]);

        if ($format === 'html') {
            return implode('<br>', $parts);
        } elseif ($format === 'single-line') {
            return implode(', ', $parts);
        } else {
            return implode("\n", $parts);
        }
    }

    /**
     * Get address label or generate default
     */
    public function get_address_label($address) {
        if (!empty($address->address_label)) {
            return $address->address_label;
        }

        // Generate default label
        $label_parts = array_filter([
            $address->city,
            $address->state
        ]);

        if (!empty($label_parts)) {
            return implode(', ', $label_parts);
        }

        return ucfirst($address->address_type) . ' Address';
    }
}

// Initialize global instance
global $ggm_commerce_address_manager;
$ggm_commerce_address_manager = new GGM_Commerce_Address_Manager();
