<?php

namespace MercadoPago\Woocommerce\Notification;

use Exception;
use MercadoPago\Woocommerce\Configs\Seller;
use MercadoPago\Woocommerce\Configs\Store;
use MercadoPago\Woocommerce\Interfaces\NotificationInterface;
use MercadoPago\Woocommerce\Libraries\Logs\Logs;
use MercadoPago\Woocommerce\Order\OrderStatus;
use MercadoPago\Woocommerce\Interfaces\MercadoPagoGatewayInterface;
use WC_Order;
use WC_Order_Refund;

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

abstract class AbstractNotification implements NotificationInterface
{
    public MercadoPagoGatewayInterface $gateway;

    public Logs $logs;

    public OrderStatus $orderStatus;

    public Seller $seller;

    public Store $store;

    /**
     * AbstractNotification constructor
     *
     * @param MercadoPagoGatewayInterface $gateway
     * @param Logs $logs
     * @param OrderStatus $orderStatus
     * @param Seller $seller
     * @param Store $store
     */
    public function __construct(
        MercadoPagoGatewayInterface $gateway,
        Logs $logs,
        OrderStatus $orderStatus,
        Seller $seller,
        Store $store
    ) {
        $this->gateway     = $gateway;
        $this->logs        = $logs;
        $this->orderStatus = $orderStatus;
        $this->seller      = $seller;
        $this->store       = $store;
    }

    /**
     * Handle Notification Request
     *
     * @param mixed $data
     *
     * @return void
     */
    public function handleReceivedNotification($data)
    {
        $this->logs->file->info('Received data content', __CLASS__, $data);
    }

    public function handleSuccessfulRequest($data): void
    {
        try {
            $this->logs->file->info('Starting to process update...', __CLASS__);

            $order_key = $data['external_reference'];

            if (empty($order_key)) {
                $message = 'external_reference not found';
                $this->logs->file->error($message, __CLASS__, $data);
                $this->setResponse(422, $message);
            }

            $invoice_prefix = get_option('_mp_store_identificator', 'WC-');
            $id = (int) str_replace($invoice_prefix, '', $order_key);
            $order = wc_get_order($id);

            if (!$order) {
                $message = 'Order is invalid';
                $this->logs->file->error($message, __CLASS__, $data);
                $this->setResponse(422, $message);
            }

            if ($order->get_id() !== $id) {
                $message = 'Order error';
                $this->logs->file->error($message, __CLASS__, $order);
                $this->setResponse(422, $message);
            }

            $this->logs->file->info('Updating metadata and status with data', __CLASS__, $data);

            $this->handleSuccessfulRequestInternal($data, $order);
        } catch (Exception $e) {
            $this->setResponse(422, $e->getMessage());
            $this->logs->file->error($e->getMessage(), static::class, $data);
        }
    }

    /**
     * @param array $data
     * @param WC_Order|WC_Order_Refund $order
     **/
    abstract public function handleSuccessfulRequestInternal($data, $order): void;

    /**
     * Process order status
     *
     * @param string $processedStatus
     * @param WC_Order $order
     * @param mixed $data
     *
     * @return bool true when the status was applied; false when a refund failed to be created
     * @throws Exception
     */
    public function processStatus(string $processedStatus, WC_Order $order, $data): bool
    {
        return $this->orderStatus->processStatus($processedStatus, $data, $order, get_class($this->gateway));
    }

    /**
     * Update order meta
     *
     * @param WC_Order $order
     * @param string $key
     * @param mixed $value
     *
     * @return void
     */
    public function updateMeta(WC_Order $order, string $key, $value): void
    {
            $order->update_meta_data($key, $value);
    }

    /**
     * Set response
     *
     * @param int $status
     * @param string $message
     *
     * @return void
     */
    public function setResponse(int $status, string $message): void
    {
        $response = [
            'status'  => $status,
            'message' => $message,
        ];

        wp_send_json($response, $status);
    }
}
