<?php

namespace Controllers;

use Libs\ResponseLib;
use Models\OrderbookModel;
use Models\TokenModel;
use Psr\Http\Message\ServerRequestInterface;
use Respect\Validation\Exceptions\ValidationException;
use Respect\Validation\Validator as val;

class TokenOrderbookController
{
    private TokenModel $tokenModel;
    private OrderbookModel $orderbookModel;
    private \PDO $pdo;

    public function __construct()
    {
        if (!isset($GLOBALS['pdo']) || !$GLOBALS['pdo'] instanceof \PDO) {
            throw new \RuntimeException('Global PDO connection not initialized');
        }

        $this->pdo = $GLOBALS['pdo'];
        $this->tokenModel = new TokenModel();
        $this->orderbookModel = new OrderbookModel();
    }

    public function __invoke(ServerRequestInterface $request)
    {
        $body = json_decode((string)$request->getBody(), true) ?? [];

        try {
            val::key('cpr_id', val::intType()->positive())
                ->key('value', val::numericVal())
                ->key('state', val::stringType()->notEmpty())
                ->key('commodity_type', val::stringType()->notEmpty())
                ->key('token_external_id', val::stringType()->notEmpty())
                ->assert($body);
        } catch (ValidationException $e) {
            return ResponseLib::sendFail(
                'Validation failed: ' . $e->getFullMessage(),
                [],
                'E_VALIDATE'
            )->withStatus(400);
        }

        $cprId = (int)$body['cpr_id'];
        $newValue = (int)round((float)$body['value']);
        $state = strtoupper(trim((string)$body['state']));
        $commodityType = trim((string)$body['commodity_type']);
        $tokenExternalId = trim((string)$body['token_external_id']);

        try {
            $this->pdo->beginTransaction();

            $token = $this->tokenModel->findByCprId($cprId, true);
            if (!$token) {
                $this->pdo->rollBack();
                return ResponseLib::sendFail(
                    'Token não encontrado para a CPR informada',
                    ['cpr_id' => $cprId],
                    'E_TOKEN_NOT_FOUND'
                )->withStatus(404);
            }

            $orderTokenExternalId = (string)($token['token_external_id'] ?? '');
            if ($orderTokenExternalId === '' || strcasecmp($orderTokenExternalId, $tokenExternalId) !== 0) {
                $this->pdo->rollBack();
                return ResponseLib::sendFail(
                    'Token externo informado não confere com o token da CPR',
                    [
                        'token_external_id' => $tokenExternalId,
                        'token_cpr_external_id' => $orderTokenExternalId,
                    ],
                    'E_TOKEN_MISMATCH'
                )->withStatus(409);
            }

            $this->tokenModel->updateCommoditiesValue((int)$token['token_id'], $newValue);

            $orderbook = $this->orderbookModel->create([
                'orderbook_flag' => '',
                'orderbook_ts' => time(),
                'orderbook_is_token' => true,
                'orderbook_amount' => (string)($token['token_commodities_amount'] ?? '0'),
                'orderbook_state' => $state,
                'orderbook_commodity_type' => $commodityType,
                'token_external_id' => $orderTokenExternalId,
                'status_id' => OrderbookModel::STATUS_OPEN,
                'user_id' => (int)$token['user_id'],
                'wallet_id' => (int)$token['wallet_id'],
                'token_id' => (int)$token['token_id'],
                'currency_id' => null,
                'chain_id' => (int)$token['chain_id'],
            ]);

            $this->pdo->commit();
        } catch (\Throwable $e) {
            if ($this->pdo->inTransaction()) {
                $this->pdo->rollBack();
            }

            return ResponseLib::sendFail(
                'Falha ao atualizar token e criar ordem: ' . $e->getMessage(),
                [],
                'E_ORDERBOOK'
            )->withStatus(500);
        }

        return ResponseLib::sendOk([
            'message' => 'Token atualizado e ordem registrada com sucesso',
            'token_id' => (int)$token['token_id'],
            'orderbook_id' => $orderbook['orderbook_id'],
        ], 'S_ORDERBOOK_CREATED');
    }
}
