<?php

declare(strict_types=1);

use App\Bootstrap;
use App\Handler\UpdateRouter;
use App\Handler\Update\BotAddedToChatHandler;
use App\Handler\Update\BotRemovedFromChatHandler;
use App\Handler\Update\BotStartedHandler;
use App\Handler\Update\BotStopedFromChatHandler;
use App\Handler\Update\ChatTitleChangedHandler;
use App\Handler\Update\DialogClearedHandler;
use App\Handler\Update\DialogRemovedHandler;
use App\Handler\Update\MessageCallbackHandler;
use App\Handler\Update\MessageCreatedHandler;
use App\Handler\Update\MessageEditedHandler;
use App\Handler\Update\MessageRemovedHandler;
use App\Handler\Update\UserAddedToChatHandler;
use App\Handler\Update\UserRemovedFromChatHandler;
use App\Keyboard\KeyboardFactory;
use App\Logger\LoggerFactory;
use App\Scenario\AttachmentScenario;
use App\Scenario\BotInfoScenario;
use App\Scenario\ChatAdminScenario;
use App\Scenario\ChatsScenario;
use App\Scenario\DebugScenario;
use App\Scenario\HelpScenario;
use App\Scenario\KeyboardScenario;
use App\Scenario\MessagesScenario;
use App\Scenario\PhoneCheckScenario;
use App\Scenario\UploadsScenario;
use App\Util\CommandRouter;
use GuzzleHttp\Client as Guzzle;
use Monolog\Logger;
use Nyholm\Psr7\Factory\Psr17Factory;
use Pkirillw\MaxBotApi\Api;
use Pkirillw\MaxBotApi\Client\Options;
use Pkirillw\MaxBotApi\Webhook\WebhookHandler;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Console\Application;

return [
    'config' => fn () => Bootstrap::envConfig(),

    Psr17Factory::class => fn () => new Psr17Factory(),

    Guzzle::class => fn () => new Guzzle(['timeout' => 30]),

    Options::class => function (ContainerInterface $c): Options {
        $cfg = $c->get('config');
        $opts = Options::default()->withKeepRawUpdates(true);
        if (($cfg['debug.chat_id'] ?? 0) > 0) {
            $opts = $opts->withDebugChatId((int) $cfg['debug.chat_id']);
        }
        return $opts;
    },

    Api::class => function (ContainerInterface $c): Api {
        $cfg = $c->get('config');
        return Api::create(
            token: (string) $cfg['bot.token'],
            http: $c->get(Guzzle::class),
            requestFactory: $c->get(Psr17Factory::class),
            streamFactory: $c->get(Psr17Factory::class),
            options: $c->get(Options::class),
        );
    },

    LoggerInterface::class => fn (ContainerInterface $c) => LoggerFactory::create($c->get('config')),

    KeyboardFactory::class => function (ContainerInterface $c): KeyboardFactory {
        $cfg = $c->get('config');
        $url = trim((string) ($cfg['webapp.url'] ?? ''));
        return new KeyboardFactory($url !== '' ? $url : null);
    },

    CommandRouter::class => function (ContainerInterface $c): CommandRouter {
        $router = new CommandRouter();
        $router->add('start', $c->get(HelpScenario::class));
        $router->add('help', $c->get(HelpScenario::class));
        $router->add('bot', $c->get(BotInfoScenario::class));
        $router->add('bot_patch', $c->get(BotInfoScenario::class));
        $router->add('chats', $c->get(ChatsScenario::class));
        $router->add('chat', $c->get(ChatsScenario::class));
        $router->add('chat_membership', $c->get(ChatsScenario::class));
        $router->add('members', $c->get(ChatsScenario::class));
        $router->add('admins', $c->get(ChatAdminScenario::class));
        $router->add('pin', $c->get(ChatAdminScenario::class));
        $router->add('action', $c->get(ChatAdminScenario::class));
        $router->add('leave', $c->get(ChatAdminScenario::class));
        $router->add('edit_chat', $c->get(ChatAdminScenario::class));
        $router->add('add_member', $c->get(ChatAdminScenario::class));
        $router->add('remove_member', $c->get(ChatAdminScenario::class));
        $router->add('send_text', $c->get(MessagesScenario::class));
        $router->add('send_markdown', $c->get(MessagesScenario::class));
        $router->add('send_html', $c->get(MessagesScenario::class));
        $router->add('reply', $c->get(MessagesScenario::class));
        $router->add('forward', $c->get(MessagesScenario::class));
        $router->add('edit', $c->get(MessagesScenario::class));
        $router->add('delete', $c->get(MessagesScenario::class));
        $router->add('messages', $c->get(MessagesScenario::class));
        $router->add('message', $c->get(MessagesScenario::class));
        $router->add('markup', $c->get(MessagesScenario::class));
        $router->add('notify', $c->get(MessagesScenario::class));
        $router->add('disable_preview', $c->get(MessagesScenario::class));
        $router->add('keyboard', $c->get(KeyboardScenario::class));
        $router->add('upload_photo_file', $c->get(UploadsScenario::class));
        $router->add('upload_photo_url', $c->get(UploadsScenario::class));
        $router->add('upload_photo_bytes', $c->get(UploadsScenario::class));
        $router->add('upload_photo_base64', $c->get(UploadsScenario::class));
        $router->add('upload_audio', $c->get(UploadsScenario::class));
        $router->add('upload_video', $c->get(UploadsScenario::class));
        $router->add('upload_file', $c->get(UploadsScenario::class));
        $router->add('upload_url', $c->get(UploadsScenario::class));
        $router->add('attach_location', $c->get(AttachmentScenario::class));
        $router->add('attach_contact', $c->get(AttachmentScenario::class));
        $router->add('attach_sticker', $c->get(AttachmentScenario::class));
        $router->add('phone_check', $c->get(PhoneCheckScenario::class));
        $router->add('phone_list', $c->get(PhoneCheckScenario::class));
        $router->add('debug', $c->get(DebugScenario::class));
        return $router;
    },

    UpdateRouter::class => function (ContainerInterface $c): UpdateRouter {
        $router = new UpdateRouter($c->get(LoggerInterface::class));
        $router->add($c->get(MessageCreatedHandler::class));
        $router->add($c->get(MessageCallbackHandler::class));
        $router->add($c->get(MessageEditedHandler::class));
        $router->add($c->get(MessageRemovedHandler::class));
        $router->add($c->get(BotStartedHandler::class));
        $router->add($c->get(BotAddedToChatHandler::class));
        $router->add($c->get(BotRemovedFromChatHandler::class));
        $router->add($c->get(BotStopedFromChatHandler::class));
        $router->add($c->get(UserAddedToChatHandler::class));
        $router->add($c->get(UserRemovedFromChatHandler::class));
        $router->add($c->get(ChatTitleChangedHandler::class));
        $router->add($c->get(DialogClearedHandler::class));
        $router->add($c->get(DialogRemovedHandler::class));
        return $router;
    },

    WebhookHandler::class => function (ContainerInterface $c): WebhookHandler {
        $cfg = $c->get('config');
        $handler = new WebhookHandler(
            responseFactory: $c->get(Psr17Factory::class),
            secret: (string) $cfg['bot.secret'],
            keepRawUpdates: true,
        );
        $router = $c->get(UpdateRouter::class);
        $logger = $c->get(LoggerInterface::class);
        $handler->setHandler(static function (object $update) use ($router, $logger): void {
            try {
                $router->dispatch($update);
            } catch (\Throwable $e) {
                $logger->error('Update failed: ' . $e->getMessage(), ['exception' => $e]);
            }
        });
        return $handler;
    },

    HelpScenario::class => \DI\autowire(),
    BotInfoScenario::class => \DI\autowire(),
    ChatsScenario::class => \DI\autowire(),
    ChatAdminScenario::class => \DI\autowire(),
    MessagesScenario::class => \DI\autowire(),
    UploadsScenario::class => \DI\autowire(),
    KeyboardScenario::class => \DI\autowire(),
    AttachmentScenario::class => \DI\autowire(),
    PhoneCheckScenario::class => \DI\autowire(),
    DebugScenario::class => \DI\autowire(),

    MessageCreatedHandler::class => \DI\autowire(),
    MessageCallbackHandler::class => \DI\autowire(),
    MessageEditedHandler::class => \DI\autowire(),
    MessageRemovedHandler::class => \DI\autowire(),
    BotStartedHandler::class => \DI\autowire(),
    BotAddedToChatHandler::class => \DI\autowire(),
    BotRemovedFromChatHandler::class => \DI\autowire(),
    BotStopedFromChatHandler::class => \DI\autowire(),
    UserAddedToChatHandler::class => \DI\autowire(),
    UserRemovedFromChatHandler::class => \DI\autowire(),
    ChatTitleChangedHandler::class => \DI\autowire(),
    DialogClearedHandler::class => \DI\autowire(),
    DialogRemovedHandler::class => \DI\autowire(),

    Application::class => function (ContainerInterface $c): Application {
        $app = new Application('max-bot-test', '1.0.0');
        $app->addCommands([
            $c->get(\App\Command\SubscribeWebhookCommand::class),
            $c->get(\App\Command\UnsubscribeWebhookCommand::class),
            $c->get(\App\Command\ListSubscriptionsCommand::class),
            $c->get(\App\Command\GetBotInfoCommand::class),
            $c->get(\App\Command\SelfTestCommand::class),
        ]);
        return $app;
    },
];
