<?php

namespace Formatrica\REST;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use Formatrica\Email\Email_Service;
use Formatrica\Forms\Form_Repository;
use Formatrica\Forms\Form_Sanitizer;
use WP_REST_Request;
use WP_REST_Response;

final class Utility_Controller extends Base_Rest_Controller implements Rest_Controller
{
    // Inherit namespace from Base_Rest_Controller

    private Email_Service $email;
    private Form_Repository $forms;

    public function __construct(?Email_Service $email = null, ?Form_Repository $forms = null)
    {
        $this->email = $email ?? new Email_Service();
        $this->forms = $forms ?? new Form_Repository();
    }

    public function register_routes(): void
    {
        register_rest_route(
            self::NAMESPACE,
            '/emails/test',
            [
                'methods' => \WP_REST_Server::CREATABLE,
                'callback' => [$this, 'send_test_email'],
                'permission_callback' => [$this, 'permissions_check'],
            ]
        );

        register_rest_route(
            self::NAMESPACE,
            '/wp/post-types',
            [
                'methods' => \WP_REST_Server::READABLE,
                'callback' => [$this, 'get_wp_post_types'],
                'permission_callback' => [$this, 'permissions_check'],
            ]
        );

        register_rest_route(
            self::NAMESPACE,
            '/woocommerce/catalog',
            [
                'methods' => \WP_REST_Server::READABLE,
                'callback' => [$this, 'get_woocommerce_catalog'],
                'permission_callback' => [$this, 'permissions_check'],
            ]
        );

        /**
         * Public endpoint: return the list of countries for front-end select fields.
         *
         * Intentionally public (`__return_true`) because country/state dropdowns
         * are rendered inside forms visible to unauthenticated visitors. The data
         * is non-sensitive, read-only reference information (ISO country names).
         * No user data is accepted or stored by this endpoint.
         */
        register_rest_route(
            self::NAMESPACE,
            '/utility/countries',
            [
                'methods' => \WP_REST_Server::READABLE,
                'callback' => [$this, 'get_countries'],
                'permission_callback' => '__return_true',
            ]
        );

        /**
         * Public endpoint: return states/provinces for a given country code.
         *
         * Intentionally public (`__return_true`) for the same reason as the
         * countries endpoint above — state dropdowns are part of front-end forms
         * used by unauthenticated visitors. The country code is validated to
         * exactly two uppercase letters by the route regex `[A-Z]{2}`.
         * No user data is accepted or stored by this endpoint.
         */
        register_rest_route(
            self::NAMESPACE,
            '/utility/states/(?P<country>[A-Z]{2})',
            [
                'methods' => \WP_REST_Server::READABLE,
                'callback' => [$this, 'get_states'],
                'permission_callback' => '__return_true',
            ]
        );
    }

    public function send_test_email(WP_REST_Request $request): WP_REST_Response
    {
        $nonce_check = $this->verify_rest_nonce_or_error($request);
        if ($nonce_check instanceof \WP_Error) {
            return new WP_REST_Response([
                'sent' => false,
                'message' => $nonce_check->get_error_message(),
            ], (int) ($nonce_check->get_error_data('status') ?: 403));
        }

        $recipient = (string) $request->get_param('recipient');
        $options = $request->get_param('options');
        $options = is_array($options) ? $options : [];

        $form_id = (int) $request->get_param('formId');
        $existing_options = [];

        if ($form_id > 0) {
            $raw = $this->forms->raw_config($form_id);
            $existing_options = is_array($raw['options'] ?? null) ? $raw['options'] : [];
        }

        $sanitised = Form_Sanitizer::sanitise_payload([
            'title' => '',
            'config' => [
                'fields' => [],
                'options' => $options,
            ],
        ], [
            'config' => [
                'fields' => [],
                'options' => $existing_options,
            ],
        ]);

        $opts = $sanitised['config']['options'] ?? [];

        // Resolve global recipient when the per-form field is empty and the global flag is on
        if ($recipient === '') {
            $use_global_recipient = array_key_exists('use_global_recipient', $opts)
                ? (bool) $opts['use_global_recipient']
                : true;
            if ($use_global_recipient) {
                $recipient = $this->email->resolve_global_recipient();
            }
        }

        $result = $this->email->send_test($recipient, $opts);

        return new WP_REST_Response($result, $result['sent'] ? 200 : 500);
    }

    public function get_woocommerce_catalog(WP_REST_Request $request): WP_REST_Response
    {
        $nonce_check = $this->verify_rest_nonce_or_error($request);
        if ($nonce_check instanceof \WP_Error) {
            return new WP_REST_Response([
                'success' => false,
                'items' => [],
                'message' => $nonce_check->get_error_message(),
            ], (int) ($nonce_check->get_error_data('status') ?: 403));
        }

        if (!class_exists('\WooCommerce')) {
            return new WP_REST_Response([
                'success' => false,
                'items' => [],
                'message' => __('WooCommerce is not installed or active.', 'formatrica'),
            ], 200);
        }

        $type = $request->get_param('type');
        $type = is_string($type) ? $type : 'products';

        if ($type === 'categories') {
            $terms = get_terms([
                'taxonomy' => 'product_cat',
                'hide_empty' => false,
                'number' => 200,
            ]);

            if ($terms instanceof \WP_Error) {
                return new WP_REST_Response([
                    'success' => false,
                    'items' => [],
                    'message' => $terms->get_error_message(),
                ], 200);
            }

            $items = [];
            foreach ($terms as $term) {
                $items[] = [
                    'id' => (int) $term->term_id,
                    'name' => $term->name,
                    'slug' => $term->slug,
                    'count' => (int) $term->count,
                ];
            }

            return new WP_REST_Response([
                'success' => true,
                'items' => $items,
            ]);
        }

        if (!function_exists('wc_get_products')) {
            return new WP_REST_Response([
                'success' => false,
                'items' => [],
                'message' => __('WooCommerce product functions are unavailable.', 'formatrica'),
            ], 200);
        }

        $limit = (int) $request->get_param('limit');
        if ($limit <= 0 || $limit > 200) {
            $limit = 100;
        }

        $search = $request->get_param('search');
        $search = is_string($search) ? $search : '';

        $products = wc_get_products([
            'limit' => $limit,
            'status' => 'publish',
            'orderby' => 'title',
            'order' => 'ASC',
            'search' => $search,
        ]);

        $items = [];

        foreach ($products as $product) {
            $variations = [];
            if ($product->is_type('variable')) {
                foreach ($product->get_children() as $variation_id) {
                    $variation = wc_get_product($variation_id);
                    if (!$variation) {
                        continue;
                    }
                    $variations[] = [
                        'id' => $variation->get_id(),
                        'name' => $variation->get_formatted_name(),
                        'sku' => $variation->get_sku(),
                        'price' => $variation->get_price(),
                        'attributes' => $variation->get_attributes(),
                    ];
                }
            }

            $items[] = [
                'id' => $product->get_id(),
                'name' => $product->get_name(),
                'sku' => $product->get_sku(),
                'price' => $product->get_price(),
                'type' => $product->get_type(),
                'variations' => $variations,
            ];
        }

        return new WP_REST_Response([
            'success' => true,
            'items' => $items,
        ]);
    }

    public function get_countries(WP_REST_Request $request): WP_REST_Response
    {
        $mode = $request->get_param('mode');
        $mode = is_string($mode) ? $mode : 'all';

        $countries = $this->load_countries_list($mode);

        return new WP_REST_Response([
            'success' => true,
            'countries' => $countries,
        ]);
    }

    public function get_states(WP_REST_Request $request): WP_REST_Response
    {
        $country = strtoupper((string) $request->get_param('country'));

        if (strlen($country) !== 2) {
            return new WP_REST_Response([
                'success' => false,
                'states' => [],
                'message' => __('Invalid country code.', 'formatrica'),
            ], 400);
        }

        $states = $this->load_states_list($country);

        return new WP_REST_Response([
            'success' => true,
            'states' => $states,
        ]);
    }

    /**
     * Return available WordPress post types suitable for UI selection
     *
     * @param WP_REST_Request $request
     * @return WP_REST_Response
     */
    public function get_wp_post_types(WP_REST_Request $request): WP_REST_Response
    {
        $nonce_check = $this->verify_rest_nonce_or_error($request);
        if ($nonce_check instanceof \WP_Error) {
            return new WP_REST_Response([
                'success' => false,
                'items' => [],
                'message' => $nonce_check->get_error_message(),
            ], (int) ($nonce_check->get_error_data('status') ?: 403));
        }

        $args = [
            'show_ui' => true,
            'show_in_nav_menus' => true,
        ];

        /** @var array<string, \WP_Post_Type> $types */
        $types = get_post_types($args, 'objects');

        $items = [];
        foreach ($types as $name => $object) {
            $items[] = [
                'name' => (string) $name,
                'label' => (string) ($object->labels->singular_name ?? $object->label ?? $name),
            ];
        }

        return new WP_REST_Response([
            'success' => true,
            'items' => $items,
        ]);
    }

    /**
     * Load countries list based on mode
     *
     * @param string $mode 'all', 'shipping', 'selling', or 'both'
     * @return array<string, string> Country code => Country name
     */
    private function load_countries_list(string $mode): array
    {
        // Try WooCommerce first if available and mode is not 'all'
        if ($mode !== 'all' && class_exists('\WooCommerce') && function_exists('WC')) {
            $wc_countries = \WC()->countries;

            if ($wc_countries) {
                if ($mode === 'shipping') {
                    $allowed = $wc_countries->get_shipping_countries();
                } elseif ($mode === 'selling') {
                    $allowed = $wc_countries->get_allowed_countries();
                } elseif ($mode === 'both') {
                    $shipping = $wc_countries->get_shipping_countries();
                    $selling = $wc_countries->get_allowed_countries();
                    $allowed = array_intersect_key($shipping, $selling);
                } else {
                    $allowed = $wc_countries->get_countries();
                }

                if (!empty($allowed) && is_array($allowed)) {
                    return $allowed;
                }
            }
        }

        // Fallback to built-in JSON file. Lives under app/ (a runtime path that
        // ships in every package) — NOT src/, which is stripped from releases.
        $json_path = FORMATRICA_PATH . 'app/Data/countries.json';

        if (!file_exists($json_path)) {
            return [];
        }

        $json_content = file_get_contents($json_path);
        if ($json_content === false) {
            return [];
        }

        $countries = json_decode($json_content, true);

        return is_array($countries) ? $countries : [];
    }

    /**
     * Load states/provinces for a specific country
     *
     * @param string $country_code ISO 3166-1 alpha-2 country code
     * @return array<string, string> State code => State name
     */
    private function load_states_list(string $country_code): array
    {
        // Try WooCommerce first if available
        if (class_exists('\WooCommerce') && function_exists('WC')) {
            $wc_countries = \WC()->countries;

            if ($wc_countries) {
                $states = $wc_countries->get_states($country_code);

                if (is_array($states) && !empty($states)) {
                    return $states;
                }
            }
        }

        // Fallback to built-in JSON file. Lives under app/ (a runtime path that
        // ships in every package) — NOT src/, which is stripped from releases.
        $json_path = FORMATRICA_PATH . 'app/Data/states.json';

        if (!file_exists($json_path)) {
            return [];
        }

        $json_content = file_get_contents($json_path);
        if ($json_content === false) {
            return [];
        }

        $all_states = json_decode($json_content, true);

        if (!is_array($all_states) || !isset($all_states[$country_code])) {
            return [];
        }

        return is_array($all_states[$country_code]) ? $all_states[$country_code] : [];
    }

    public function permissions_check(WP_REST_Request $request)
    {
        return parent::permissions_check($request);
    }
}
