<?php

namespace Mtc\Plugins\MtcUnioIntegration\Classes;

use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;
use Mtc\Modules\Members\Models\Member;
use Mtc\Modules\MtcUnio\Classes\UnioApi;
use Mtc\Modules\MtcUnio\Interfaces\UnioApiRequestable;
use Mtc\Plugins\NHS\Classes\Prescription;
use Mtc\Shop\Order;

class QueueMessageFromUnio extends QueueMessage implements UnioApiRequestable
{

    protected $table = 'unio__queue_messages_from_unio';

    // We don't have 'updated_at' field in the table.
    public $timestamps = false;

    protected $fillable = [
        'entity_type',
        'entity_id'
    ];

    const ENTITY_CUSTOMER = 'customer';
    const ENTITY_ORDER = 'order';
    const ENTITY_MESSAGE = 'message';


    public static function get_available_entity_types()
    {
        return [
            self::ENTITY_CUSTOMER,
            self::ENTITY_ORDER,
            self::ENTITY_MESSAGE,
        ];
    }


    private $rules = [
        'entity_id' => [ 'required' , 'integer' ],
        'entity_type' => [ 'required' ],
    ];

    public function validate()
    {
        $this->rules['entity_type'][] = Rule::in(self::get_available_entity_types());

        return Validator::make($this->attributes, $this->rules);
    }



    public function saveResponse(string $response, $append = false) : void
    {
        if ($append) {
            $this->response .= $response;
        } else {
            $this->response = $response;
        }
        $this->save();
    }


    public function processResponse() : void
    {
        $response = json_decode($this->response, true);
        $response_body = Arr::get($response, 'body');

        switch ($this->entity_type) {
            case self::ENTITY_CUSTOMER:
                $this->processResponseWithCustomerData($response_body);
                break;

            case self::ENTITY_ORDER:
                $this->processResponseWithOrderData($response_body);
                break;
        }

        $this->processed_at = date('Y-m-d H:i');
        $this->save();
    }

    private function processResponseWithCustomerData(array $data, $update_if_existing = true, $update_if_new = true)
    {
        $member_id = Arr::get($data, 'id');
        $unio_internal_id = Arr::get($data, 'internalId');
        Arr::set($data, 'unio_internal_id', $unio_internal_id);

        if ($member_id) {
            $member = Member::findOrFail($member_id);
        } elseif ($unio_internal_id) {
            $member = Member::query()->where('unio_internal_id', $unio_internal_id)->first();
        }

        if (! $member) {
            $member = new Member([
                'is_external' => true,
                'is_activated' => false,
            ]);
        }

        $has_unsynced_messages = QueueMessageToUnio::pending()
            ->where('entity_type', QueueMessageToUnio::ENTITY_MEMBER)
            ->where('entity_id', $member->id)
            ->count()
        ;

        if (! $has_unsynced_messages) {
            if ($member->exists) {
                $update_if_existing and $member->update_from_input($data);
            } else {
                $update_if_new and $member->update_from_input($data);
            }
        }

        return $member;
    }

    private function processResponseWithOrderData(array $data)
    {
        $vyne_order_id = Arr::get($data, 'id');
        $unio_internal_id = Arr::get($data, 'internalId');

        // Unio doesn't know vyne_order_id for imported orders.
        if ($unio_internal_id) {
            $prescription = Prescription::query()->where('unio_internal_id', $unio_internal_id)->first();
        }
        
        // Vyne doesn't know unio_internal_id for orders originated from the website, but never updated by Unio.
        if (! $prescription && $vyne_order_id) {
            $order = Order::findOrFail($vyne_order_id);
            $prescription = $order->items->first()->prescription_item->prescription;
        }

        if (! $prescription) {
            $member = $this->processResponseWithCustomerData(Arr::get($data, 'customer'), false);
            $prescription = Prescription::create($member, $unio_internal_id);
            $prescription->save_status(Prescription::STATUS_COMPLETE);
        }

        //$has_unsynced_messages = QueueMessageToUnio::pending()
        //    ->where('entity_type', QueueMessageToUnio::ENTITY_ORDER)
        //    ->where('entity_id', $vyne_order_id)
        //    ->count()
        //;

        $items = [];
        foreach (Arr::get($data, 'items') as $item) {
            $items[] = [
                'name' => $item['item_name'],
                'quantity' => $item['quantity'],
            ];
        }
        $prescription->save_items_from_input($items);
    }


    public function getPayloadData() : array
    {
        return [];
    }


    public function getQueryParams() : array
    {
        return [
            'id' => $this->entity_id
        ];
    }


    public function getEndpointName() : string
    {
        $endpoint_name = '';

        switch ($this->entity_type) {
            case self::ENTITY_CUSTOMER:
                $endpoint_name = UnioApi::ENDPOINT_CUSTOMER_GET;
                break;

            case self::ENTITY_ORDER:
                $endpoint_name = UnioApi::ENDPOINT_ORDER_GET;
                break;
        }

        return $endpoint_name;
    }


    public function getMethodName() : string
    {
        return 'GET';
    }
}
