# source: https://raw.githubusercontent.com/4tie/fortiesr/d5cc40760e3cbaff381058a0ea8733d2be469578/backend/tests/test_parameter_injection.py
"""backend/tests/test_parameter_injection.py — Parameter injection tests.

Tests for parameter injection into strategy source code, including:
- _inject_params() correctness
- DecimalParameter, IntParameter, CategoricalParameter default patching
- Class renaming
"""

from __future__ import annotations

import ast

import pytest

import backend.services.auto_quant.pipeline as pl
from backend.services.auto_quant.pipeline_modules.helpers import _inject_params

from .test_helpers import _hyperopt_best


class TestParameterInjection:
    """Verify that _inject_params() produces syntactically valid, correctly patched source."""

    BASE_SOURCE = """\
from freqtrade.strategy import IStrategy
from pandas import DataFrame


class Github_4tie_fortiesr__test_parameter_injection__20260709_213639(IStrategy):
    INTERFACE_VERSION = 3
    minimal_roi = {"0": 0.10, "60": 0.02}
    stoploss = -0.10
    trailing_stop = False
    timeframe = "5m"

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        return dataframe
"""

    def test_class_is_renamed(self):
        best = {"params_dict": {}}
        result = _inject_params(self.BASE_SOURCE, "Github_4tie_fortiesr__test_parameter_injection__20260709_213639_Optimized", best)
        assert "class Github_4tie_fortiesr__test_parameter_injection__20260709_213639_Optimized(" in result
        assert "class Github_4tie_fortiesr__test_parameter_injection__20260709_213639(" not in result.split("AUTO-GENERATED")[1]

    def test_stoploss_is_injected(self):
        best = {"params_dict": {"stoploss": -0.05}}
        result = _inject_params(self.BASE_SOURCE, "Github_4tie_fortiesr__test_parameter_injection__20260709_213639_Optimized", best)
        assert "stoploss = -0.05" in result

    def test_roi_is_injected(self):
        new_roi = {"0": 0.08, "30": 0.04, "60": 0.01}
        best = {"params_dict": {"minimal_roi": new_roi}}
        result = _inject_params(self.BASE_SOURCE, "Github_4tie_fortiesr__test_parameter_injection__20260709_213639_Optimized", best)
        assert "0.08" in result or "0.04" in result

    def test_auto_generated_header_prepended(self):
        best = {"params_dict": {}}
        result = _inject_params(self.BASE_SOURCE, "Github_4tie_fortiesr__test_parameter_injection__20260709_213639_Optimized", best)
        assert result.startswith("# AUTO-GENERATED by Auto-Quant Factory")

    def test_output_is_valid_python(self):
        best = _hyperopt_best()
        result = _inject_params(self.BASE_SOURCE, "Github_4tie_fortiesr__test_parameter_injection__20260709_213639_Optimized", best)
        try:
            ast.parse(result)
        except SyntaxError as exc:
            pytest.fail(f"Injected source has a SyntaxError: {exc}")

    def test_trailing_stop_is_injected_as_true(self):
        best = {"params_dict": {"trailing_stop": True}}
        result = _inject_params(self.BASE_SOURCE, "Github_4tie_fortiesr__test_parameter_injection__20260709_213639_Optimized", best)
        assert "trailing_stop = True" in result

    def test_hyperopt_parameter_defaults_are_injected(self):
        source = """\
from freqtrade.strategy import DecimalParameter, IntParameter, CategoricalParameter, IStrategy


class Github_4tie_fortiesr__test_parameter_injection__20260709_213639(IStrategy):
    ts_tier1_trigger = DecimalParameter(0.020, 0.040, default=0.030, decimals=3, space="buy", optimize=True)
    ts_tier1_lock = DecimalParameter(0.001, 0.010, default=0.003, decimals=3, space="buy", optimize=True)
    rsi_threshold = IntParameter(20, 50, default=30, space="buy", optimize=True)
    entry_logic = CategoricalParameter(["macd_cross", "bb_breakout"], default="macd_cross", space="buy", optimize=True)
"""
        best = {
            "params_dict": {
                "ts_tier1_trigger": 0.037,
                "ts_tier1_lock": 0.006,
                "rsi_threshold": 42,
                "entry_logic": "bb_breakout",
            }
        }
        result = _inject_params(source, "Github_4tie_fortiesr__test_parameter_injection__20260709_213639_Optimized", best)
        assert "ts_tier1_trigger = DecimalParameter(0.020, 0.040, default=0.037" in result
        assert "ts_tier1_lock = DecimalParameter(0.001, 0.010, default=0.006" in result
        assert "rsi_threshold = IntParameter(20, 50, default=42" in result
        assert 'entry_logic = CategoricalParameter(["macd_cross", "bb_breakout"], default="bb_breakout"' in result

    def test_inject_params_patches_decimal_parameter_default(self):
        """_inject_params must update default= in DecimalParameter declarations."""
        source = """
class Github_4tie_fortiesr__test_parameter_injection__20260709_213639(IStrategy):
    ts_tier1_trigger = DecimalParameter(0.020, 0.040, default=0.030, decimals=3, space="buy", optimize=True)
"""
        best_params = {"params_dict": {"ts_tier1_trigger": 0.035}}
        patched = _inject_params(source, "Github_4tie_fortiesr__test_parameter_injection__20260709_213639_Optimized", best_params)
        assert 'default=0.035' in patched
        assert 'default=0.030' not in patched

    def test_inject_params_patches_int_parameter_default(self):
        """_inject_params must update default= in IntParameter declarations."""
        source = """
class Github_4tie_fortiesr__test_parameter_injection__20260709_213639(IStrategy):
    rsi_threshold = IntParameter(20, 50, default=30, space="buy", optimize=True)
"""
        best_params = {"params_dict": {"rsi_threshold": 35}}
        patched = _inject_params(source, "Github_4tie_fortiesr__test_parameter_injection__20260709_213639_Optimized", best_params)
        assert 'default=35' in patched
        assert 'default=30' not in patched

    def test_inject_params_patches_categorical_parameter_default(self):
        """_inject_params must update default= in CategoricalParameter declarations."""
        source = """
class Github_4tie_fortiesr__test_parameter_injection__20260709_213639(IStrategy):
    entry_logic = CategoricalParameter(["macd_cross", "rsi_oversold", "bb_breakout"], default="macd_cross", space="buy", optimize=True)
"""
        best_params = {"params_dict": {"entry_logic": "rsi_oversold"}}
        patched = _inject_params(source, "Github_4tie_fortiesr__test_parameter_injection__20260709_213639_Optimized", best_params)
        assert 'default="rsi_oversold"' in patched
        assert 'default="macd_cross"' not in patched

    def test_inject_params_renames_class(self):
        """_inject_params must rename the strategy class."""
        source = "class Github_4tie_fortiesr__test_parameter_injection__20260709_213639(IStrategy):"
        best_params = {"params_dict": {}}
        patched = _inject_params(source, "Github_4tie_fortiesr__test_parameter_injection__20260709_213639_Optimized", best_params)
        assert "class Github_4tie_fortiesr__test_parameter_injection__20260709_213639_Optimized(IStrategy):" in patched
        assert "class Github_4tie_fortiesr__test_parameter_injection__20260709_213639(IStrategy):" not in patched
