<?php

declare(strict_types=1);

namespace MyCustomizer\WooCommerce\Connector\Api;

use MyCustomizer\WooCommerce\Connector\Auth\MczrAccess;
use MyCustomizer\WooCommerce\Connector\Controller\Admin\MczrProductTypeController;
use MyCustomizer\WooCommerce\Connector\Controller\MczrOrderController;
use MyCustomizer\WooCommerce\Connector\Libs\MczrConnect;
use MyCustomizer\WooCommerce\Connector\Libs\MczrSettings;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use WP_Query;
use WP_REST_Request;

class MczrShopApi
{
    /** @var MczrConnect */
    private $mczrConnect;
    /** @var MczrOrderController */
    private $mczrOrderController;
    /** @var MczrProductTypeController */
    private $mczrProductTypeController;
    /** @var Request */
    private $request;
    /** @var Response */
    private $response;
    /** @var MczrSettings */
    private $settings;

    public function __construct()
    {
        $this->mczrConnect = new MczrConnect();
        $this->mczrOrderController = new MczrOrderController();
        $this->mczrProductTypeController = new MczrProductTypeController();
        $this->request  = Request::createFromGlobals();
        $this->response = new Response();
        $this->settings = new MczrSettings();
    }

    public function init(): void
    {
        // /?rest_route=/mczr/v1/
        \add_action('rest_api_init', [$this, 'registerRestRoute'], 10, 0);
        \add_action('rest_api_init', [$this, 'allowAllCors'], 15, 0);
    }

    public function allowAllCors(): void
    {
        // Remove the default filter.
        \remove_filter('rest_pre_serve_request', 'rest_send_cors_headers');
        // Add a Custom filter.
        \add_filter('rest_pre_serve_request', [$this, 'corsHeaders'], 10, 1);
    }

    public function corsHeaders(bool $served): bool
    {
        header('Access-Control-Allow-Origin: *');
        header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
        header('Access-Control-Allow-Credentials: true');

        return $served;
    }

    public function registerRestRoute(): void
    {
        \register_rest_route(
            'mczr',
            '/test',
            [
                'methods' => 'GET',
                'callback' => [$this, 'test'],
                'permission_callback' => '__return_true',
            ]
        );
        \register_rest_route(
            'mczr',
            '/connect',
            [
                'methods' => 'POST',
                'callback' => [$this, 'shopConnect'],
                'permission_callback' => '__return_true',
            ]
        );
        \register_rest_route(
            'mczr',
            '/startingpoints',
            [
                'methods' => 'POST',
                'callback' => [$this, 'createStartingPoint'],
                'permission_callback' => '__return_true',
            ]
        );
        \register_rest_route(
            'mczr',
            '/startingpoints/(?P<id>\w+)',
            [
                'methods' => 'POST',
                'callback' => [$this, 'updateStartingPoint'],
                'permission_callback' => '__return_true',
            ]
        );
        \register_rest_route(
            'mczr',
            '/startingpoints',
            [
                'methods' => 'GET',
                'callback' => [$this, 'getStartingPoints'],
                'permission_callback' => '__return_true',
            ]
        );
        \register_rest_route(
            'mczr',
            '/startingpoints/(?P<id>\w+)',
            [
                'methods' => 'GET',
                'callback' => [$this, 'getStartingPoint'],
                'permission_callback' => '__return_true',
            ]
        );
        \register_rest_route(
            'mczr',
            '/startingpoints/(?P<id>\w+)',
            [
                'methods' => 'DELETE',
                'callback' => [$this, 'removeStartingPoint'],
                'permission_callback' => '__return_true',
            ]
        );
        \register_rest_route(
            'mczr',
            '/reconcile/orders',
            [
                'methods' => 'POST',
                'callback' => [$this, 'reconcileOrders'],
                'permission_callback' => '__return_true',
            ]
        );
        \register_rest_route(
            'mczr',
            '/orders/create',
            [
                'methods' => 'POST',
                'callback' => [$this, 'createOrder'],
                'permission_callback' => '__return_true',
            ]
        );
    }

    public function test(): void
    {
        MczrAccess::isAPIAuthorized();

        $this->response->headers->set('Access-Control-Allow-Origin', '*');
        $this->response->headers->set('Content-Type', 'application/json');

        $this->response
            ->setContent(json_encode(['success' => true,]))
            ->setStatusCode(Response::HTTP_OK)
            ->send();

        exit;
    }

    public function getStartingPoints(): void
    {
        MczrAccess::isAPIAuthorized();

        $this->response->headers->set('Access-Control-Allow-Origin', '*');
        $this->response->headers->set('Content-Type', 'application/json');
        $vars = [
            'success' => true,
            'data' => [],
        ];

        $args = ['type' => 'mczr'];
        $products = \wc_get_products($args);

        foreach ($products as $product) {
            array_push(
                $vars['data'],
                [
                    'startingPointId' => \get_post_meta($product->id, 'mczrStartingPoint', true),
                    'active' => 'publish' === $product->status,
                ]
            );
        }

        $this->response
            ->setContent(json_encode($vars))
            ->setStatusCode(Response::HTTP_OK)
            ->send();

        exit;
    }

    public function getStartingPoint(WP_REST_Request $request): void
    {
        MczrAccess::isAPIAuthorized();

        $this->response->headers->set('Access-Control-Allow-Origin', '*');
        $this->response->headers->set('Content-Type', 'application/json');

        $startingPointId = $request->get_param('id');

        $products = new WP_Query(
            [
                'post_type' => ['product'],
                'posts_per_page' => 1,
                'meta_query' => [
                    [
                        'key' => 'mczrStartingPoint',
                        'value' => $startingPointId,
                        'compare' => 'IS',
                    ]
                ],
            ]
        );

        if ($products->have_posts()) {
            $productId = $products->post->ID;
            $product = \wc_get_product($productId);
            $vars = [
                'success' => true,
                'data' => [
                    'startingPointId' => \get_post_meta($product->id, 'mczrStartingPoint', true),
                    'active' => 'publish' === $product->status,
                ]
            ];
            $this->response
                ->setContent(json_encode($vars))
                ->setStatusCode(Response::HTTP_OK)
                ->send();
        } else {
            $this
                ->response
                ->setContent(json_encode([
                    'success' => false,
                    'message' => 'Product not found.',
                    'data' => ['startingPointId' => $startingPointId],
                ]))
                ->setStatusCode(Response::HTTP_NOT_FOUND)
                ->send();
        }

        exit;
    }

    public function createStartingPoint(): void
    {
        MczrAccess::isAPIAuthorized();

        $this->response->headers->set('Access-Control-Allow-Origin', '*');
        $this->response->headers->set('Content-Type', 'application/json');

        $content = $this->request->getContent();
        $datas = json_decode($content, true);

        $startingPointId = $datas['startingPointId'];
        $startingPointName = $datas['startingPointName'];
        $price = $datas['price'];
        if (isset($datas['startingPointImage'])) {
            $startingPointImage = $datas['startingPointImage'];
        }

        $productId = $this->mczrProductTypeController->create($startingPointId, $startingPointName, $price);

        $this->mczrProductTypeController->attachProductThumbnail($productId, $startingPointImage);

        $vars = [
            'success' => true,
            'data' => [
                'startingPointId' => $startingPointId,
                'active' => true,
            ],
        ];

        $this->response
            ->setContent(json_encode($vars))
            ->setStatusCode(Response::HTTP_OK)
            ->send();

        exit;
    }

    public function updateStartingPoint(WP_REST_Request $request): void
    {
        MczrAccess::isAPIAuthorized();

        $this->response->headers->set('Access-Control-Allow-Origin', '*');
        $this->response->headers->set('Content-Type', 'application/json');

        $startingPointId = $request->get_param('id');

        $content = $this->request->getContent();
        $datas = json_decode($content, true);

        $startingPointName = isset($datas['startingPointName']) ? $datas['startingPointName'] : null;
        $price = isset($datas['price']) ? $datas['price'] : null;

        if ($startingPointName == null && $price == null) {
            $vars = [
                'success' => true,
                'data' => ['startingPointId' => $startingPointId],
            ];

            $this->response
                ->setContent(json_encode($vars))
                ->setStatusCode(Response::HTTP_OK)
                ->send();

            exit;
        }

        $updatedProductId = $this->mczrProductTypeController->update($startingPointId, $startingPointName, $price);

        if (!$updatedProductId) {
            $this->response
                ->setContent(json_encode([
                    'success' => false,
                    'message' => 'Product not found.',
                    'data' => ['startingPointId' => $startingPointId],
                ]))
                ->setStatusCode(Response::HTTP_NOT_FOUND)
                ->send();
        } else {
            $vars = [
                'success' => true,
                'data' => $updatedProductId
            ];

            $this->response
                ->setContent(json_encode($vars))
                ->setStatusCode(Response::HTTP_OK)
                ->send();
        }

        exit;
    }

    public function removeStartingPoint(WP_REST_Request $request): void
    {
        $this->response->headers->set('Access-Control-Allow-Origin', '*');
        $this->response->headers->set('Content-Type', 'application/json');
        $this->response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR);

        $startingPointId = $request->get_param('id');

        $wasDeleted = $this->mczrProductTypeController->delete($startingPointId);

        if (!$wasDeleted) {
            $this->response
                ->setContent(json_encode([
                    'success' => false,
                    'message' => 'Product not found.',
                    'data' => ['startingPointId' => $startingPointId],
                ]))
                ->setStatusCode(Response::HTTP_NOT_FOUND)
                ->send();

            return;
        }

        $vars = [
            'success' => true,
            'data' => ['deleted' => $wasDeleted ? $startingPointId : null],
        ];

        $this->response
            ->setContent(json_encode($vars))
            ->setStatusCode(Response::HTTP_OK)
            ->send();

        exit;
    }

    public function reconcileOrders(): void
    {
        MczrAccess::isAPIAuthorized();

        $this->response->headers->set('Access-Control-Allow-Origin', '*');
        $this->response->headers->set('Content-Type', 'application/json');
        $this->response->setStatusCode(Response::HTTP_INTERNAL_SERVER_ERROR);

        $content = $this->request->getContent();
        $datas = json_decode($content, true);

        $fromDate = $datas['fromDate'];

        $kickflipOrders = $this->mczrOrderController->getKickflipOrders($fromDate);

        $vars = [
            'success' => true,
            'data' => $kickflipOrders
        ];

        $this->response
            ->setContent(json_encode($vars))
            ->setStatusCode(Response::HTTP_OK)
            ->send();

        exit;
    }

    public function shopConnect(): void
    {
        MczrAccess::isAPIAuthorized();

        $this->response->headers->set('Access-Control-Allow-Origin', '*');
        $this->response->headers->set('Content-Type', 'application/json');
        $vars = [
            'success' => true,
            'data' => [],
        ];

        $content = $this->request->getContent();
        if (!$content || empty(json_decode($content, true))) {
            $this->response->setContent(json_encode($vars))->send();

            exit;
        }

        $datas = json_decode($content, true);
        $brand = $datas['brand'];
        $apiToken = $datas['token'];
        $onlineStoreId = $datas['onlineStoreId'];
        $customizerBaseUrl = $datas['customizerUrl'];

        $vars['success'] = true;

        $this->settings->update(['brand' => $brand]);
        $this->settings->update(['apiToken' => $apiToken]);
        $this->settings->update(['customizerBaseUrl' => $customizerBaseUrl]);

        $this->mczrConnect->connect($brand, $onlineStoreId);

        $this->response
            ->setContent(json_encode($vars))
            ->setStatusCode(Response::HTTP_OK)
            ->send();

        exit;
    }

    public function createOrder(): void
    {
        MczrAccess::isAPIAuthorized();
        $this->response->headers->set('Access-Control-Allow-Origin', '*');
        $this->response->headers->set('Content-Type', 'application/json');

        $data = json_decode($this->request->getContent(), true);
        $createdOrder = $this->mczrOrderController->createOrder($data);

        if ($createdOrder) {
            $vars = [
                'success' => true,
                'data' => $createdOrder,
            ];

            $this->response
                ->setContent(json_encode($vars))
                ->setStatusCode(Response::HTTP_OK)
                ->send();

            exit;
        }

        $vars = [
            'success' => false,
            'message' => 'Order creation failed. The order is null or undefined.',
        ];

        $this->response
            ->setContent(json_encode($vars))
            ->setStatusCode(Response::HTTP_BAD_REQUEST)
            ->send();

        exit;
    }
}
