<?php
namespace Bot\Commands\AdminCommands;

use Bot\Config;
use Bot\Services\AdminActivityService;
use Bot\Services\BalanceService;
use Bot\Services\WithdrawalService;
use Longman\TelegramBot\Commands\AdminCommand;
use Longman\TelegramBot\Entities\ServerResponse;
use Longman\TelegramBot\Request;

class AdminwithdrawCommand extends AdminCommand
{
    protected $name = 'adminwithdraw';
    protected $description = 'Review withdrawal requests';
    protected $usage = '/adminwithdraw list';
    protected $version = '1.0.0';

    private WithdrawalService $withdrawals;
    private BalanceService $balances;
    private AdminActivityService $activity;

    public function __construct($telegram, $update)
    {
        parent::__construct($telegram, $update);
        $this->withdrawals = new WithdrawalService();
        $this->balances = new BalanceService();
        $this->activity = new AdminActivityService();
    }

    public function execute(): ServerResponse
    {
        $message = $this->getMessage();
        $text = trim($message->getText(true) ?? '');
        if ($text === '') {
            return $this->replyUsage();
        }
        [$command, $payload] = array_pad(explode(' ', $text, 2), 2, '');
        $command = strtolower($command);
        return match ($command) {
            'list'    => $this->handleList($payload),
            'approve' => $this->handleApprove($payload),
            'reject'  => $this->handleReject($payload),
            'hold'    => $this->handleHold($payload),
            'release' => $this->handleRelease($payload),
            'info'    => $this->handleInfo($payload),
            default   => $this->replyUsage(),
        };
    }

    private function replyUsage(): ServerResponse
    {
        $text = "Withdrawal review commands:\n"
            . " `/adminwithdraw list [pending|held|approved]`\n"
            . " `/adminwithdraw approve <id>`\n"
            . " `/adminwithdraw reject <id> <reason>`\n"
            . " `/adminwithdraw hold <id> <reason>`\n"
            . " `/adminwithdraw release <id>`\n"
            . " `/adminwithdraw info <id>`";
        return $this->sendReply($text);
    }

    private function handleList(string $state): ServerResponse
    {
        $state = $state !== '' ? strtolower($state) : 'pending';
        $rows = $this->withdrawals->listByReviewStatus($state);
        if (!$rows) {
            return $this->sendReply('No withdrawals found.');
        }
        $lines = [];
        foreach ($rows as $row) {
            $lines[] = sprintf(
                '#%d user:%d %s %s status:%s/%s',
                $row['id'],
                $row['user_id'],
                $row['currency'],
                $row['amount'],
                $row['review_status'],
                $row['status']
            );
        }
        return $this->sendReply(implode("\n", $lines));
    }

    private function handleApprove(string $payload): ServerResponse
    {
        $id = (int) trim($payload);
        if ($id <= 0) {
            return $this->sendReply('Usage: `/adminwithdraw approve <id>`');
        }
        $row = $this->withdrawals->approve($id, (int) $this->getMessage()->getFrom()->getId());
        if (!$row) {
            return $this->sendReply('Withdrawal not found or already processed.');
        }
        $this->notifyUser($row['user_id'], sprintf('Withdrawal #%d approved. We will process it shortly.', $row['id']));
        $this->activity->log((int) $this->getMessage()->getFrom()->getId(), 'withdraw_approve', (int) $row['user_id'], ['withdrawal_id' => $row['id']]);
        return $this->sendReply('Withdrawal approved.');
    }

    private function handleReject(string $payload): ServerResponse
    {
        [$idText, $reason] = array_map('trim', explode(' ', $payload, 2) + ['', '']);
        $id = (int) $idText;
        if ($id <= 0 || $reason === '') {
            return $this->sendReply('Usage: `/adminwithdraw reject <id> <reason>`');
        }
        $row = $this->withdrawals->reject($id, (int) $this->getMessage()->getFrom()->getId(), $reason);
        if (!$row) {
            return $this->sendReply('Withdrawal not found or already processed.');
        }
        $this->balances->unlock((int) $row['user_id'], $row['currency'], $row['amount']);
        $this->notifyUser($row['user_id'], sprintf('Withdrawal #%d rejected: %s. Funds unlocked.', $row['id'], $reason));
        $this->activity->log((int) $this->getMessage()->getFrom()->getId(), 'withdraw_reject', (int) $row['user_id'], ['withdrawal_id' => $row['id'], 'reason' => $reason]);
        return $this->sendReply('Withdrawal rejected and funds unlocked.');
    }

    private function handleHold(string $payload): ServerResponse
    {
        [$idText, $reason] = array_map('trim', explode(' ', $payload, 2) + ['', '']);
        $id = (int) $idText;
        if ($id <= 0 || $reason === '') {
            return $this->sendReply('Usage: `/adminwithdraw hold <id> <reason>`');
        }
        $row = $this->withdrawals->hold($id, (int) $this->getMessage()->getFrom()->getId(), $reason);
        if (!$row) {
            return $this->sendReply('Withdrawal not found.');
        }
        $this->notifyUser($row['user_id'], sprintf('Withdrawal #%d is on hold: %s', $row['id'], $reason));
        $this->activity->log((int) $this->getMessage()->getFrom()->getId(), 'withdraw_hold', (int) $row['user_id'], ['withdrawal_id' => $row['id'], 'reason' => $reason]);
        return $this->sendReply('Withdrawal placed on hold.');
    }

    private function handleRelease(string $payload): ServerResponse
    {
        $id = (int) trim($payload);
        if ($id <= 0) {
            return $this->sendReply('Usage: `/adminwithdraw release <id>`');
        }
        $row = $this->withdrawals->releaseHold($id, (int) $this->getMessage()->getFrom()->getId());
        if (!$row) {
            return $this->sendReply('Withdrawal not found or not on hold.');
        }
        $this->notifyUser($row['user_id'], sprintf('Hold removed for withdrawal #%d. We will continue review.', $row['id']));
        $this->activity->log((int) $this->getMessage()->getFrom()->getId(), 'withdraw_release_hold', (int) $row['user_id'], ['withdrawal_id' => $row['id']]);
        return $this->sendReply('Hold released.');
    }

    private function handleInfo(string $payload): ServerResponse
    {
        $id = (int) trim($payload);
        if ($id <= 0) {
            return $this->sendReply('Usage: `/adminwithdraw info <id>`');
        }
        $row = $this->withdrawals->getById($id);
        if (!$row) {
            return $this->sendReply('Withdrawal not found.');
        }
        $text = sprintf(
            "#%d user:%d\n%s %s\nNetwork: %s\nAddress: %s\nReview: %s (%s)\nStatus: %s\nCreated: %s",
            $row['id'],
            $row['user_id'],
            $row['currency'],
            $row['amount'],
            $row['network'],
            $row['to_address'],
            $row['review_status'],
            $row['review_reason'] ?? '-',
            $row['status'],
            $row['created_at']
        );
        return $this->sendReply($text);
    }

    private function notifyUser(int $userId, string $text): void
    {
        $stmt = Database::connection()->prepare('SELECT telegram_id FROM users WHERE id = ?');
        $stmt->execute([$userId]);
        $chatId = $stmt->fetchColumn();
        if (!$chatId) {
            return;
        }
        Request::sendMessage([
            'chat_id' => $chatId,
            'text'    => $text,
        ]);
    }

    private function sendReply(string $text): ServerResponse
    {
        return Request::sendMessage([
            'chat_id' => $this->getMessage()->getChat()->getId(),
            'text'    => $text,
        ]);
    }
}
