<?php

declare(strict_types=1);

namespace App\Command;

use App\Bootstrap;
use Symfony\Component\Console\Attribute\AsCommand;
use Pkirillw\MaxBotApi\Builder\Keyboard;
use Pkirillw\MaxBotApi\Builder\Message as MessageBuilder;
use Pkirillw\MaxBotApi\Scheme\Enum\Intent;
use Pkirillw\MaxBotApi\Scheme\PinMessageBody;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

#[AsCommand(name: 'selftest', description: 'Smoke-test every endpoint group end-to-end.')]
final class SelfTestCommand extends AbstractCommand
{

    /** @var list<array{0:string,1:string,2:bool}> */
    private array $results = [];

    protected function doExecute(SymfonyStyle $io, InputInterface $input, OutputInterface $output): int
    {
        $config = Bootstrap::envConfig();
        $chatId = (int) $config['selftest.chat_id'];

        if ($chatId <= 0) {
            $io->warning('SELFTEST_CHAT_ID is not set — will skip chat-scoped checks (send/edit/delete/pin/leave).');
        }

        $this->probe($io, 'bots.getBot', fn () => $this->api->bots->getBot()->name);
        $this->probe($io, 'chats.getChats', fn () => count($this->api->chats->getChats(count: 1)->chats) . ' chat(s)');
        $this->probe($io, 'subscriptions.getSubscriptions', fn () => count($this->api->subscriptions->getSubscriptions()->subscriptions) . ' sub(s)');
        $this->probe($io, 'uploads.uploadPhotoFromBytes', function () {
            $png = base64_decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=', true);
            $tokens = $this->api->uploads->uploadPhotoFromBytes($png, 'pixel.png');
            return $tokens->photos === [] ? 'no tokens returned' : count($tokens->photos) . ' token(s)';
        });

        if ($chatId > 0) {
            $this->probe($io, 'messages.send (markdown + keyboard)', function () use ($chatId) {
                $kb = (new Keyboard())->addRow()->addCallback('selftest', 'selftest:ok', Intent::Positive);
                $msg = $this->api->messages->sendWithResult(
                    MessageBuilder::new()
                        ->setChat($chatId)
                        ->setText('*selftest* message')
                        ->addKeyboard($kb),
                );
                $mid = $msg->body->mid;
                if ($mid === '') {
                    throw new \RuntimeException('no mid returned');
                }
                $this->probe($io, 'messages.editMessage', function () use ($mid, $chatId) {
                    $this->api->messages->editMessage($mid, MessageBuilder::new()->setChat($chatId)->setText('*selftest* edited'));
                });
                $this->probe($io, 'chats.sendAction (typing)', fn () => $this->api->chats->sendAction($chatId, \Pkirillw\MaxBotApi\Scheme\Enum\SenderAction::TypingOn));
                $this->probe($io, 'chats.pinMessage', fn () => $this->api->chats->pinMessage($chatId, new PinMessageBody(messageId: $mid)));
                $this->probe($io, 'messages.getMessage', fn () => $this->api->messages->getMessage($mid)->body?->text ?? '?');
                $this->probe($io, 'messages.getMessages', fn () => count($this->api->messages->getMessages($chatId, count: 1)->messages) . ' msg(s)');
                $this->probe($io, 'messages.deleteMessage', fn () => $this->api->messages->deleteMessage($mid)->success ? 'ok' : 'false');
                $this->probe($io, 'chats.getChat', fn () => $this->api->chats->getChat($chatId)->title ?? '(no title)');
                $this->probe($io, 'chats.getChatMembership', fn () => $this->api->chats->getChatMembership($chatId)->userId);
                $this->probe($io, 'chats.getChatMembers', fn () => count($this->api->chats->getChatMembers($chatId, count: 1)->members) . ' member(s)');
            });
        }

        $this->probe($io, 'debugs.sendText', function () {
            if ($this->api->debugs->getChatId() === null) {
                return 'skipped (no DEBUG_CHAT_ID)';
            }
            $this->api->debugs->sendText('selftest: ' . date('c'));
            return 'sent';
        });

        $table = new Table($output);
        $table->setHeaders(['probe', 'result', 'ok']);
        $table->setRows($this->results);
        $table->render();

        $failures = array_filter($this->results, fn($r) => !$r[2]);
        return $failures === [] ? self::SUCCESS : self::FAILURE;
    }

    private function probe(SymfonyStyle $io, string $name, callable $callback): void
    {
        try {
            $result = $callback();
            $this->results[] = [$name, (string) $result, true];
        } catch (\Throwable $e) {
            $this->results[] = [$name, mb_substr($e->getMessage(), 0, 120), false];
        }
    }
}
