<?php
// =============================================================
// DASHBOARD/LIB/WALLETS_HANDLER — обработка POST страницы кошельков
// =============================================================
// Логика действий (add/update/delete/import/reset/tags/log) отделена от
// view. CSRF проверяется вызывающей страницей до вызова. Возвращает
// ['message'=>..., 'messageType'=>...]; конфиг персистится через
// save_wallets_config, страница перечитывает его после вызова.

require_once __DIR__ . '/../../config.php';
require_once __DIR__ . '/../../storage.php';
require_once __DIR__ . '/../../hl_executor.php';   // hl_teardown_entity: свернуть direct-след при удалении/сбросе
require_once __DIR__ . '/forms.php';

/**
 * Ищет уже добавленный кошелёк с тем же адресом (сравнение без учёта регистра).
 * Возвращает label (или id) найденного трейдера, иначе null. Используется для
 * защиты add_wallet от дублей при повторной отправке формы.
 */
function dashboard_find_wallet_by_address(array $wallets, string $address): ?string
{
    $needle = strtolower(trim($address));
    if ($needle === '') {
        return null;
    }
    foreach ($wallets as $w) {
        if (strtolower(trim((string) ($w['address'] ?? ''))) === $needle) {
            return (string) ($w['label'] ?? $w['id'] ?? $address);
        }
    }
    return null;
}

function dashboard_handle_wallets_post(array $post, array $config): array
{
    $wallets        = $config['wallets'];
    $globalSettings = $config['global_settings'];
    $availableTags  = $config['available_tags'] ?? [];
    $message = '';
    $messageType = '';

    $action = $post['action'] ?? '';

    // Управление тегами (глобальный список)
    if ($action === 'manage_tags') {
        $raw  = trim($post['tags_list'] ?? '');
        $tags = array_values(array_unique(array_filter(
            array_map('trim', preg_split('/[\r\n,]+/', $raw)),
            fn($t) => $t !== ''
        )));
        sort($tags);
        if (save_wallets_config(['global_settings' => $globalSettings, 'wallets' => $wallets, 'available_tags' => $tags])) {
            $availableTags = $tags;
            $message = 'Теги сохранены';
            $messageType = 'success';
        }
    }

    // Добавить запись в журнал
    if ($action === 'add_log') {
        $walletId = $post['wallet_id'] ?? '';
        $note     = trim($post['note'] ?? '');
        if ($walletId !== '' && $note !== '') {
            storage_add_wallet_log($walletId, $note);
            $message = 'Запись добавлена';
            $messageType = 'success';
        }
    }

    // Удалить запись журнала
    if ($action === 'delete_log') {
        $walletId = $post['wallet_id'] ?? '';
        $entryId  = (int) ($post['entry_id'] ?? 0);
        if ($walletId !== '' && $entryId > 0) {
            storage_delete_wallet_log_entry($entryId, $walletId);
        }
    }

    // Добавить новый кошелёк
    if ($action === 'add_wallet') {
        $address = trim($post['address'] ?? '');
        $label = trim($post['label'] ?? '');

        if ($address === '' || !preg_match('/^0x[a-fA-F0-9]{40}$/', $address)) {
            $message = 'Некорректный адрес кошелька (ожидается формат 0x... из 42 символов)';
            $messageType = 'error';
        } elseif (($dupLabel = dashboard_find_wallet_by_address($wallets, $address)) !== null) {
            // Дубль по адресу (без учёта регистра). Форма отправлялась повторно
            // (двойной клик / F5 / повторное «Добавить») — молча создавала второго
            // трейдера с тем же кошельком. Возвращаем ошибку вместо дубликата.
            $message = 'Трейдер с этим адресом уже добавлен: ' . $dupLabel;
            $messageType = 'error';
        } else {
            $newId = generate_wallet_id($wallets);
            $wallets[] = [
                'id'             => $newId,
                'label'          => $label !== '' ? $label : $newId,
                'address'        => $address,
                'enabled'        => true,
                'status'         => 'WATCH',
                'rating'         => 0,
                'tags'           => [],
                'notes'          => trim($post['notes'] ?? ''),
                'source'         => trim($post['source'] ?? ''),
                'archive_reason' => '',
                'settings'       => parse_wallet_overrides($post, 'new_'),
            ];

            if (save_wallets_config(['global_settings' => $globalSettings, 'wallets' => $wallets, 'available_tags' => $availableTags])) {
                // Инициализируем виртуальный счёт стартовым балансом (с учётом override, если задан)
                $newWalletSettings = resolve_wallet_settings(end($wallets), $globalSettings);
                storage_save_balance('wallet', $newId,
                    dashboard_fresh_wallet_balance((float) $newWalletSettings['virtual_balance']));

                $message = 'Кошелёк "' . ($label !== '' ? $label : $newId) . '" добавлен';
                $messageType = 'success';
            } else {
                $message = 'Ошибка сохранения';
                $messageType = 'error';
            }
        }
    }

    // Обновить существующий кошелёк
    if ($action === 'update_wallet') {
        $walletId = $post['wallet_id'] ?? '';

        // Адрес валидируем так же, как при добавлении (add_wallet): опечатка при
        // редактировании молча ломала бы сбор fills этого кошелька.
        $newAddress = array_key_exists('address', $post) ? trim((string) $post['address']) : null;
        if ($newAddress !== null && !preg_match('/^0x[a-fA-F0-9]{40}$/', $newAddress)) {
            return ['message' => 'Некорректный адрес кошелька (ожидается формат 0x... из 42 символов)', 'messageType' => 'error'];
        }

        foreach ($wallets as &$w) {
            if ($w['id'] === $walletId) {
                $newStatus = $post['status'] ?? ($w['status'] ?? 'WATCH');
                $validStatuses = ['WATCH', 'TEST', 'ACTIVE', 'ARCHIVE'];
                if (!in_array($newStatus, $validStatuses, true)) $newStatus = 'WATCH';

                // При архивации требуем причину
                if ($newStatus === 'ARCHIVE' && ($w['status'] ?? '') !== 'ARCHIVE') {
                    $archiveReason = trim($post['archive_reason'] ?? '');
                    $w['archive_reason'] = $archiveReason;
                    if ($archiveReason !== '') {
                        storage_add_wallet_log($walletId, 'Архивирован: ' . $archiveReason);
                    }
                }

                $w['label']    = trim($post['label'] ?? $w['label']);
                $w['address']  = $newAddress ?? $w['address'];
                $w['enabled']  = !empty($post['enabled']);
                $w['status']   = $newStatus;
                $w['rating']   = max(0, min(5, (int) ($post['rating'] ?? 0)));
                $w['tags']     = array_values(array_intersect(
                    $post['tags'] ?? [],
                    $availableTags
                ));
                $w['notes']    = trim($post['notes'] ?? ($w['notes'] ?? ''));
                $w['source']   = trim($post['source'] ?? ($w['source'] ?? ''));
                $w['settings'] = parse_wallet_overrides($post, 'edit_' . $walletId . '_');
                break;
            }
        }
        unset($w);

        if (save_wallets_config(['global_settings' => $globalSettings, 'wallets' => $wallets, 'available_tags' => $availableTags])) {
            $message = 'Кошелёк обновлён';
            $messageType = 'success';
        } else {
            $message = 'Ошибка сохранения';
            $messageType = 'error';
        }
    }

    // Быстрое включение/выключение кошелька (кнопка Play/Stop в списке)
    if ($action === 'toggle_wallet') {
        $walletId = $post['wallet_id'] ?? '';
        $toggled = null;
        foreach ($wallets as &$w) {
            if ($w['id'] === $walletId) {
                $w['enabled'] = empty($w['enabled']);
                $toggled = $w;
                break;
            }
        }
        unset($w);

        if ($toggled === null) {
            $message = 'Кошелёк не найден';
            $messageType = 'error';
        } elseif (save_wallets_config(['global_settings' => $globalSettings, 'wallets' => $wallets, 'available_tags' => $availableTags])) {
            $message = 'Кошелёк "' . ($toggled['label'] ?? $walletId) . '" '
                . (!empty($toggled['enabled']) ? 'включён' : 'приостановлен');
            $messageType = 'success';
        } else {
            $message = 'Ошибка сохранения';
            $messageType = 'error';
        }
    }

    // Массовые операции над выбранными кошельками (галочки в списке)
    if ($action === 'bulk_wallets') {
        $op  = $post['bulk_op'] ?? '';
        $ids = array_values(array_intersect(
            (array) ($post['wallet_ids'] ?? []),
            array_column($wallets, 'id')
        ));

        if (!in_array($op, ['enable', 'disable', 'delete', 'edit'], true)) {
            $message = 'Неизвестная массовая операция';
            $messageType = 'error';
        } elseif (empty($ids)) {
            $message = 'Не выбран ни один кошелёк';
            $messageType = 'error';
        } elseif ($op === 'edit') {
            $edits = parse_bulk_wallet_edits($post, $availableTags);
            if (empty($edits['settings']) && empty($edits['profile']) && $edits['tags_mode'] === '') {
                $message = 'Не отмечено ни одно поле для массового изменения';
                $messageType = 'error';
            } else {
                foreach ($wallets as &$w) {
                    if (!in_array($w['id'], $ids, true)) continue;

                    $settings = is_array($w['settings'] ?? null) ? $w['settings'] : [];
                    foreach ($edits['settings'] as $key => $value) {
                        $settings[$key] = $value;   // null = вернуть наследование глобального
                    }
                    $w['settings'] = $settings;

                    // Профильные поля (status/rating) — свойства кошелька
                    foreach ($edits['profile'] ?? [] as $key => $value) {
                        $w[$key] = $value;
                    }

                    if ($edits['tags_mode'] !== '') {
                        $current = array_values(array_intersect($w['tags'] ?? [], $availableTags));
                        if ($edits['tags_mode'] === 'add') {
                            $w['tags'] = array_values(array_unique(array_merge($current, $edits['tags'])));
                        } elseif ($edits['tags_mode'] === 'remove') {
                            $w['tags'] = array_values(array_diff($current, $edits['tags']));
                        } else { // replace
                            $w['tags'] = $edits['tags'];
                        }
                    }
                }
                unset($w);

                if (save_wallets_config(['global_settings' => $globalSettings, 'wallets' => $wallets, 'available_tags' => $availableTags])) {
                    $changed = [];
                    if (!empty($edits['settings']))  $changed[] = 'настройки: ' . implode(', ', array_keys($edits['settings']));
                    if (!empty($edits['profile']))   $changed[] = 'профиль: ' . implode(', ', array_keys($edits['profile']));
                    if ($edits['tags_mode'] !== '')  $changed[] = 'теги';
                    $message = 'Обновлено кошельков: ' . count($ids) . ' (' . implode('; ', $changed) . ')';
                    $messageType = 'success';
                } else {
                    $message = 'Ошибка сохранения';
                    $messageType = 'error';
                }
            }
        } elseif ($op === 'delete') {
            $labelsById = array_column($wallets, 'label', 'id');
            $wallets = array_values(array_filter($wallets, fn($w) => !in_array($w['id'], $ids, true)));
            if (save_wallets_config(['global_settings' => $globalSettings, 'wallets' => $wallets, 'available_tags' => $availableTags])) {
                foreach ($ids as $id) {
                    // direct-след (реальные ордера/позиция/лизы) сворачивается ДО
                    // удаления учёта — иначе лиза висела бы вечно, а сетка жила в книге.
                    hl_teardown_entity('wallet', $id, $labelsById[$id] ?? $id);
                    storage_delete_entity('wallet', $id);
                }
                $message = 'Удалено кошельков: ' . count($ids);
                $messageType = 'success';
            } else {
                $message = 'Ошибка сохранения';
                $messageType = 'error';
            }
        } else {
            $enable = ($op === 'enable');
            foreach ($wallets as &$w) {
                if (in_array($w['id'], $ids, true)) {
                    $w['enabled'] = $enable;
                }
            }
            unset($w);
            if (save_wallets_config(['global_settings' => $globalSettings, 'wallets' => $wallets, 'available_tags' => $availableTags])) {
                $message = ($enable ? 'Включено' : 'Приостановлено') . ' кошельков: ' . count($ids);
                $messageType = 'success';
            } else {
                $message = 'Ошибка сохранения';
                $messageType = 'error';
            }
        }
    }

    // Удалить кошелёк
    if ($action === 'delete_wallet') {
        $walletId = $post['wallet_id'] ?? '';
        $walletLabel = array_column($wallets, 'label', 'id')[$walletId] ?? $walletId;
        $wallets = array_values(array_filter($wallets, fn($w) => $w['id'] !== $walletId));

        if (save_wallets_config(['global_settings' => $globalSettings, 'wallets' => $wallets, 'available_tags' => $availableTags])) {
            // Сворачиваем direct-след (отмена ордеров, закрытие реальной позиции,
            // освобождение лиз), затем чистим всё состояние кошелька в БД (баланс,
            // позиции, watermark/cooldown, seen_fills, watching). История сделок
            // в trades_closed остаётся.
            hl_teardown_entity('wallet', $walletId, $walletLabel);
            storage_delete_entity('wallet', $walletId);
            $message = 'Кошелёк удалён';
            $messageType = 'success';
        } else {
            $message = 'Ошибка сохранения';
            $messageType = 'error';
        }
    }

    // Массовый импорт кошельков
    if ($action === 'bulk_import') {
        $raw     = trim($post['addresses'] ?? '');
        $enabled = !empty($post['import_enabled']);
        $lines   = preg_split('/\r\n|\r|\n/', $raw);

        $added    = 0;
        $skipped  = 0;
        $invalid  = 0;
        $errors   = [];

        // Существующие адреса для проверки дублей
        $existingAddresses = array_map(
            fn($w) => strtolower($w['address']),
            $wallets
        );

        foreach ($lines as $line) {
            // Поддерживаем формат "адрес,название" или просто "адрес"
            $parts   = explode(',', $line, 2);
            $address = trim($parts[0]);
            $label   = isset($parts[1]) ? trim($parts[1]) : '';

            if ($address === '') continue;

            // Валидация адреса
            if (!preg_match('/^0x[a-fA-F0-9]{40}$/', $address)) {
                $invalid++;
                $errors[] = 'Некорректный адрес: ' . htmlspecialchars(substr($address, 0, 20)) . '...';
                continue;
            }

            // Проверка дублей
            if (in_array(strtolower($address), $existingAddresses, true)) {
                $skipped++;
                continue;
            }

            $newId      = generate_wallet_id($wallets);
            $newWallet  = [
                'id'       => $newId,
                'label'    => $label !== '' ? $label : $newId,
                'address'  => $address,
                'enabled'  => $enabled,
                'settings' => [],
            ];

            $wallets[]            = $newWallet;
            $existingAddresses[]  = strtolower($address);

            // Инициализируем виртуальный счёт
            $newSettings = resolve_wallet_settings($newWallet, $globalSettings);
            storage_save_balance('wallet', $newId,
                dashboard_fresh_wallet_balance((float) $newSettings['virtual_balance']));

            $added++;
        }

        if ($added > 0) {
            save_wallets_config(['global_settings' => $globalSettings, 'wallets' => $wallets, 'available_tags' => $availableTags]);
        }

        $parts = ["Добавлено: $added"];
        if ($skipped > 0)  $parts[] = "пропущено дублей: $skipped";
        if ($invalid > 0)  $parts[] = "некорректных: $invalid";
        $message     = implode(', ', $parts);
        $messageType = $added > 0 ? 'success' : ($invalid > 0 ? 'error' : 'info');

        if (!empty($errors)) {
            $message .= '. ' . implode('; ', array_slice($errors, 0, 3));
        }
    }

    // Сбросить state одного кошелька
    if ($action === 'reset_wallet') {
        $walletId = $post['wallet_id'] ?? '';

        // Сброс — под тем же per-wallet lock, что держит бот при обработке:
        // без него бот, находящийся посреди prepare→execute→commit, закоммитил
        // бы поверх сброса старый watermark, и сброс молча «не сработал» бы.
        $lockFp = dashboard_acquire_wallet_lock($walletId);
        if ($lockFp === null) {
            return ['message' => 'Бот сейчас обрабатывает этот кошелёк — повторите сброс через несколько секунд', 'messageType' => 'error'];
        }

        try {
            $walletLabel = array_column($wallets, 'label', 'id')[$walletId] ?? $walletId;

            // Сворачиваем direct-след: сброс = «начать с чистого листа», реальная
            // позиция/сетка/лизы прежней жизни не должны пережить бумагу.
            hl_teardown_entity('wallet', $walletId, $walletLabel);

            // Сбрасываем engine state (watermark + seen fills + cooldown)
            storage_save_state('wallet', $walletId, [
                'trades'       => [],
                'cooldown'     => [],
                'last_seen_ts' => null,
            ]);

            // Сбрасываем открытые позиции
            storage_save_positions('wallet', $walletId, []);

            // Сбрасываем watching
            storage_save_watching('wallet', $walletId, []);

            // Сбрасываем виртуальный счёт
            $walletSettings = null;
            foreach ($wallets as $w) {
                if ($w['id'] === $walletId) {
                    $walletSettings = resolve_wallet_settings($w, $globalSettings);
                    break;
                }
            }
            $startBalance = $walletSettings ? (float) $walletSettings['virtual_balance'] : 1000.0;
            storage_save_balance('wallet', $walletId, dashboard_fresh_wallet_balance($startBalance));

            // Добавляем запись в журнал
            storage_add_wallet_log($walletId, 'State сброшен вручную');

            $message = 'State кошелька сброшен. Следующий запуск встанет на текущий момент.';
            $messageType = 'success';
        } catch (Throwable $e) {
            $message = 'Ошибка при сбросе state: ' . $e->getMessage();
            $messageType = 'error';
        } finally {
            dashboard_release_wallet_lock($lockFp);
        }
    }

    return ['message' => $message, 'messageType' => $messageType];
}
