<?php

declare(strict_types=1);

namespace MyCustomizer\WooCommerce\Connector\Service\Admin;

use DateTime;
use MyCustomizer\WooCommerce\Connector\Config\MczrConfig;
use MyCustomizer\WooCommerce\Connector\Libs\Admin\MczrDiagnosticMessage;
use MyCustomizer\WooCommerce\Connector\Libs\Admin\MczrMessageType;
use MyCustomizer\WooCommerce\Connector\Libs\MczrSettings;

class MczrDiagnosticService
{
    /** @var array */
    private $config;

    /** @var MczrDiagnosticMessage */
    private $messageList;

    /** @var MczrSettings */
    private $settings;

    /** @var array<string> */
    private $mczrProperties = [
        'customizationNumber',
        'designId',
        'image',
        'mczrStoreId',
        'originalStartingPoint',
        'price',
        'shopProductId',
        'startingPoint',
        'summary_v2',
        'title',
    ];

    public function __construct()
    {
        $this->settings = new MczrSettings();
        $this->config = MczrConfig::getConfig();
        $this->messageList = new MczrDiagnosticMessage();
    }

    /**
     * @return array{body: mixed, responseCode: int}
     */
    private function fetchKickflipEndpoint(string $method = 'GET', string $path, array $body = [])
    {
        $endpoint = $this->config['apiBaseUrl'] . $path;

        $startTime = microtime(true);
        $response = \wp_remote_request($endpoint, [
            'headers' => [
                'X-Tenant-Id' => $this->settings->get('brand'),
                'Authorization' => "Bearer {$this->settings->get('apiToken')}"
            ],
            'method' => $method,
            'body' => $body,
            'timeout' => 30,
        ]);
        $durationMs = (microtime(true) - $startTime) * 1000;

        if ($durationMs > 10000) {
            $this->messageList->addMessage(
                sprintf(
                    'Warning: %s %s took %.0f ms to respond.',
                    $method,
                    $endpoint,
                    $durationMs
                ),
                MczrMessageType::WARNING
            );
        }

        $responseCode = \wp_remote_retrieve_response_code($response);
        $body = json_decode(\wp_remote_retrieve_body($response));

        if ($responseCode >= 300 || is_wp_error($response)) {
            $this->messageList
                ->addMessage("Failed to connect to $method $endpoint.", MczrMessageType::ERROR)
                ->addMessage('Response: ' . json_encode($response), MczrMessageType::ERROR);
        } else {
            $this->messageList->addMessage(
                sprintf('Call successful: %s %s (%.0f ms)', $method, $endpoint, $durationMs),
                MczrMessageType::SUCCESS
            );
        }

        return [
            'body' => $body,
            'responseCode' => $responseCode
        ];
    }

    private function validateSettings(): void
    {
        $this->messageList->addMessage('Validating Kickflip settings...', MczrMessageType::INFO);

        $settings = $this->settings->getAll();

        foreach ($settings as $key => $value) {
            $messages[] = isset($value) && $value !== '' ?
                $this->messageList->addMessage("The $key parameter is set", MczrMessageType::SUCCESS) :
                $this->messageList->addMessage("The $key parameter is not set", MczrMessageType::ERROR);
        }
    }

    private function validateConnectionToKickflipApi(): void
    {
        $this->messageList->addMessage('Testing connectivity from your WordPress server to Kickflip\'s API...', MczrMessageType::INFO);

        $this->fetchKickflipEndpoint('GET', '/v1/connectivity/test');
        $this->fetchKickflipEndpoint('POST', '/v1/connectivity/test');
    }

    private function validateKickflipOnlineStoreConfiguration(): void
    {
        $this->messageList->addMessage('Fetching online store configuration...', MczrMessageType::INFO);

        $result = $this->fetchKickflipEndpoint(
            'GET',
            "/brands/{$this->settings->get('brand')}/onlinestores/{$this->settings->get('shopid')}"
        );

        if ($result['responseCode'] === 200) {
            $body = $result['body'];
            $this->messageList
                ->addMessage('Online Store ID: ' . $body->id, MczrMessageType::INFO)
                ->addMessage('Online Store: ' . $body->name, MczrMessageType::INFO)
                ->addMessage('Url: ' . $body->url, MczrMessageType::INFO)
                ->addMessage('Status: ' . $body->status, MczrMessageType::INFO)
                ->addMessage('Currency: ' . $body->currency, MczrMessageType::INFO);
        }
    }

    private function validateConnectionFromKickflipApi(): void
    {
        $this->messageList->addMessage('Testing connectivity from Kickflip API to your WordPress server...', MczrMessageType::INFO);

        $result = $this->fetchKickflipEndpoint(
            'GET',
            "/trpc/wooCommerce.checkConnection?input=%22{$this->settings->get('shopid')}%22"
        );

        if ($result['body']->result->data->success === true) {
            $this->messageList
                ->addMessage('Access token is valid', MczrMessageType::SUCCESS)
                ->addMessage('Kickflip is able to communicate with your WordPress', MczrMessageType::SUCCESS);
        } else {
            if ($result['responseCode'] === 401) {
                $this->messageList->addMessage('Access token might be invalid', MczrMessageType::ERROR);
            }

            $this->messageList->addMessage('Kickflip is unable to communicate with your WordPress', MczrMessageType::ERROR);
        }
    }

    private function isValidDate(string $date): bool
    {
        return DateTime::createFromFormat('Y-m-d', $date) !== false;
    }

    private function validateKickflipOrders(string $orderStartDate, string $orderEndDate): void
    {
        $dateFromFormatted = empty($orderStartDate)
            ? date('Y-m-d', strtotime('-30 days'))
            : $orderStartDate;

        $dateToFormatted = empty($orderEndDate)
            ? date('Y-m-d')
            : $orderEndDate;

        if (!$this->isValidDate($dateFromFormatted) || !$this->isValidDate($dateToFormatted)) {
            $this->messageList->addMessage(
                'Invalid date format for Date From or Date To. Expected format: Y-m-d.',
                MczrMessageType::ERROR
            );
            return;
        }

        $orders = \wc_get_orders([
            'limit' => -1,
            'date_created' => $dateFromFormatted . '...' . $dateToFormatted,
            'orderby' => 'date',
            'order' => 'DESC',
        ]);

        $this->messageList->addMessage(
            sprintf(
                "Scanning %d orders from %s to %s for missing Kickflip properties...",
                count($orders),
                $dateFromFormatted,
                $dateToFormatted
            ),
            MczrMessageType::INFO
        );

        if (empty($orders)) {
            $this->messageList->addMessage('No orders found in this date range.', MczrMessageType::INFO);
            return;
        }

        $issuesFound = 0;

        foreach ($orders as $order) {
            foreach ($order->get_items() as $item) {
                $productId = $item->get_data()['product_id'];
                $product = \wc_get_product($productId);

                if (!$product || !$product->is_type('mczr')) {
                    continue;
                }

                $mczrMeta = $item->get_meta('mczr');
                $missingProperties = [];

                if (empty($mczrMeta)) {
                    $missingProperties[] = 'All Kickflip Metadata is missing';
                } else {
                    foreach ($this->mczrProperties as $property) {
                        if (!isset($mczrMeta[$property]) || $mczrMeta[$property] === '') {
                            $missingProperties[] = $property;
                        }
                    }
                }

                if (!empty($missingProperties)) {
                    $issuesFound++;
                    $this->messageList->addMessage(
                        sprintf(
                            'Order #%d - Product: "%s" - Missing properties: %s',
                            $order->get_id(),
                            $item->get_name(),
                            implode(', ', $missingProperties)
                        ),
                        MczrMessageType::ERROR
                    );
                }
            }
        }

        if ($issuesFound === 0) {
            $this->messageList->addMessage('No missing Kickflip properties found in orders.', MczrMessageType::SUCCESS);
        }
    }

    private function printEnvironmentInfo(): void
    {
        global $wp_version;

        $pluginData = \get_file_data(
            __DIR__ . '/../../../kickflip-product-configurators.php',
            ['Version' => 'Version']
        );

        $this->messageList->addMessage('Environment information:', MczrMessageType::INFO);
        $this->messageList->addMessage('Kickflip plugin version: ' . $pluginData['Version'], MczrMessageType::INFO);
        $this->messageList->addMessage('WordPress version: ' . $wp_version, MczrMessageType::INFO);
        $this->messageList->addMessage('WooCommerce version: ' . $this->getWooCommerceVersion(), MczrMessageType::INFO);
        $this->messageList->addMessage('PHP version: ' . PHP_VERSION, MczrMessageType::INFO);
    }

    private function getWooCommerceVersion(): string
    {
        if (\defined('WC_VERSION')) {
            return (string) \constant('WC_VERSION');
        }

        if (\function_exists('WC') && isset(\WC()->version)) {
            return (string) \WC()->version;
        }

        return 'unknown';
    }

    /**
     * @param array<string> $options
     * @return array<int, array{message: string, type: string}>
     */
    public function runDiagnostic(array $options = [])
    {
        $this->messageList->addMessage('Starting diagnostic...', MczrMessageType::INFO);

        $this->printEnvironmentInfo();
        $this->messageList->addMessage('', MczrMessageType::INFO);

        if (in_array('settings', $options)) {
            $this->validateSettings();
            $this->messageList->addMessage('', MczrMessageType::INFO);
        }

        if (in_array('connectionTo', $options)) {
            $this->validateConnectionToKickflipApi();
            $this->messageList->addMessage('', MczrMessageType::INFO);
        }

        if (in_array('onlineStore', $options)) {
            $this->validateKickflipOnlineStoreConfiguration();
            $this->messageList->addMessage('', MczrMessageType::INFO);
        }

        if (in_array('connectionFrom', $options)) {
            $this->validateConnectionFromKickflipApi();
            $this->messageList->addMessage('', MczrMessageType::INFO);
        }

        if (in_array('orders', $options)) {
            if (isset($options['orderStartDate']) && isset($options['orderEndDate'])) {
                $this->validateKickflipOrders($options['orderStartDate'], $options['orderEndDate']);
                $this->messageList->addMessage('', MczrMessageType::INFO);
            } else {
                $this->messageList->addMessage(
                    'Missing required fields: Date From and Date To.',
                    MczrMessageType::ERROR
                );
            }
        }

        $this->messageList->addMessage('Diagnostic finished.', MczrMessageType::INFO);

        return $this->messageList->getMessageList();
    }
}
